/tmp

雑記帳.

競技プログラミングのための自分用アシスタントツールを作った。

最近, 弱小ながら競技プログラミングをやっている. 競技プログラミングは, 与えられた問題を解くプログラムを書いて提出する競技だ. 正しいプログラムを早く提出できるほど高得点を得られる.

競技プログラミングをするときには, 書いたプログラムが正しいかどうかをまずは問題文に書かれているサンプルケースで検証する. つまり, フォーカスをエディタに切り替えて, プログラムを書き, 端末にフォーカスを移してコンパイルし, 実行し, ブラウザにフォーカスを移し, サンプルの入力部分を正しく選択し, コピーし, 端末にフォーカスを移して貼り付けし, 出力を目視し, ブラウザにフォーカスを移し, サンプルの出力と一致するかを確かめる. 面倒くさい. それも, 確認が一回で済むような強者ならまだしも, たいていはサンプルとすら一致しない. するとバグを見つけて修正し, コンパイルし直しから全く同じプロセスを経て確かめなければならない.

入力をファイルに保存してしまって, 以降はリダイレクトで済ませる手がある. これをするとコピペの手間が省ける. しかしそれでもファイルを作ったりいろいろ面倒だし, 出力は目視だし, 実行は逐一コマンドを入力しなければならない.

というわけで, 自分のためにアシスタントツールを作成した. その名も procon-assistant . いくつかの機能がある.

% procon-assistant
Procon Assistant
Usage: procon-assistant [command] [options]

List of commands:
    initdirs [name] [num] initializes directories tree (name/{a,...,a+num})
    init           initializes files in directory
    fetch [ID]     downloads test cases from webpages
      [ID] is:
      - aoj:xxxx   id xxxx of Aizu Online Judge
    addcase        adds new sample case. creates inX.txt, outX.txt in current directory.
    run            runs and tests current solution (main.cpp) with input inX.txt.

initdirs / id

コンテストのためのディレクトリ構造を作成する.

コンテストは, 大抵はいくつかの問題から成る. たとえば 6 問など. 各問題に対してディレクトリを作るわけだが, けっこう面倒だ. というわけで, ディレクトリ構造を作成してくれる機能を付けた.

コンテスト名のディレクトリの下に, [num] で指定した数の空ディレクトリ a, b, c, ... を作成する. なお文字の種類を変更 (数字にするなど) はできない. 面倒だし自分にはあまり必要ないので.

init / i

コンテストのためのファイルを作成する.

カレントディレクトリに #include <...>using namespace std; など必ず使う要素を入れたファイル main.cpp を作成し, これをエディタで開く. エディタで開くには open という名前のコマンドが必要で, こういう名前のコマンドにファイル名を渡すようになっている. open はたとえばエディタへの symlink であるとか, 何らかのシェルスクリプトとかで準備してパスの通ったディレクトリに置く.

ほとんど何も入ってない. テンプレートを指定する機能はない. 面倒だし自分には十分なので.

fetch / f

コンテストからテストケースをダウンロードする.

カレントディレクトリに, コンテストのテストケースをダウンロードする. 一つずつ in1.txt, out1.txt, in2.txt, out2.txt, ... というように作っていく. 現状 AOJ と AtCoder に対応. ただ, やっつけ仕事なのと今日実装したので使い勝手は不明. そもそも AtCoder のコンテストってリアルタイムにログイン無しで問題見えたっけか. 普段参加登録してから開くのでそれすら知らない.

addcase / a / ac

手動でテストケースを追加する.

カレントディレクトリに inX.txt, outX.txt を作成して, エディタで開く. X にはカレントディレクトリに同名のファイルが存在しないような最小の整数が入る. 手動で追加するときに便利か? fetch を実装するまではここでコピペしてた. fetch できないコンテストでも使えそう.

run / r

プログラムをコンパイルし, 各テストケースを実行する. いい感じにテスト結果を表示する. ここでは示せないが, 実はちょっと色もついている. 色付き出力には自作の colored_print クレートを使用した (言い忘れていたが, Rust で書いた) . "Your solution was Sample Case Passed." って変な英語だが, まあそれは英語力がないからなので仕方ない (他の色々な部分も残念ながら「英語っぽい何か」にしかならなかった) .

% procon-assistant run
  Compiling main.cpp
    Running 4 testcases (current timeout is 1000 millisecs)
   Finished running

    PS  in1.txt
    PS  in2.txt
    PS  in3.txt
    PS  in4.txt

    Your solution was Sample Case Passed.

コンパイルオプションはハードコーディングされている. 必要なら変えて再コンパイルすればよいと思って. Time Limit Exceeded も 1000ms 固定になっている. まあ TLE はそれを判定するというより, うっかり無限ループとかになっているやつも最大 1000ms で終了させるためにある.

判定はガバガバなので, たとえば改行コードが CRLF になってたりすると Linux 環境では Presentation Error になったりする. 当然一致判定をしているだけなので, 複数の解答が有り得る場合などでサンプルとは違う (正しい) 出力をしても Wrong Answer になる.

stdout は完全にキャプチャしてしまうのでデバッグ出力には向かない (Wrong Answer になったときに出力はされるけど) . 変わりに stderr を使う. ただ, 各テストケースを並列に実行するので (テストケースが 1 つでない限り) デバッグ出力は滅茶苦茶になる. コンパイルされたバイナリは普通にカレントディレクトリにあるので, 個別に実行するには普通にテストケースをリダイレクトして直接実行すればよい.

ただのアシスタントなので, 細かいところはやっぱり手動で実行して試すことになるが, 大分手間は減ると思われる. これを使って学習効率が上がるとよいのだが...