はじめに
まぐげんがーです。AtCoderのHeuristicレーティングは水色です。
この記事は、AHCにおいて、手元でテストケースをたくさん試したい人に向けての記事になっています。
時間がないという方は「どのように多くのテストケースを試すか」と「(想定される)Q&A」だけ読めば大丈夫です。
なぜテストケースをたくさん試したいか
AHC(AtCoder Heuristic Contestの略。最適解を出すのが難しい問題に対し、出来るだけ良い解を作成するコンテストです。)では、多くのテストケースでその回答がジャッジされます。さて、AHCにおいて、私たち(クソデカ主語)はなぜテストケースをたくさん試したいのか。
ここで、皆さんにAHCあるあるを2つ見ていただきたいと思います。
あるある1
ぼく「よし!手元で10ケース試した感じスコア上がりそうだから提出するぞ〜」
〜提出 WJ 26/50〜
ぼく「いや〜これは勝ったな風呂入ってくるわ」
〜入浴後〜
ぼく「え!?スコア下がっとるやん!!」
あるある2
ぼく「いやこれは流石に上がったわ。これ上がらなかったら穴に埋めてもらっても構わないよ」
〜提出 WJ 10/50〜
ぼく「よし勝ったな風呂入ってくるわ」
〜入浴後〜
RE「ぼく」
そう、テストケースが多いAHCでは、最初の5、10ケースを確かめただけでは全体のスコアやvalidな答えを常に出すことができるかが分からない場合が多いのです。
しかも、AHCは短期でも5分、長期になるとなんと30分もの提出制限時間があります。
長期コンで提出してREやWAが出たあと、3分後にバグを見つけ、悶絶するようなことも日常茶飯事です。
この点、手元で多くのテストケースを試せると、回答コードの変化によるスコアの上下、REやWAの有無などが見えてきやすくなります。
どのように多くのテストケースを試すか
必要な実行環境
- rust(cargoが実行できればいいです)
- ruby
- ShellScript
(Ubuntu 22.04で動作確認ができています)
AHCは普段、Rustで書かれたローカル版ビジュアライザ・入力ジェネレータがダウンロードできるようになっています。これを使います。
ローカル版ビジュアライザ・入力ジェネレータをダウンロードして、展開するとtools
というディレクトリが生成されるので、そのディレクトリで作業をしていきます。
tools
の中に回答コードを作成します。私はC++をメインに使っているので、main.cpp
という名前で作成します。
tools/
├ in/
├ src/
├ target/
└ main.cpp
今たぶんこんな感じのディレクトリ構造になっていると思います(tools
内の全部のファイルを書いているわけではないです。たとえばREADME_ja.md
などのファイルがあるかもしれませんが、今は関係ないので飛ばします)。
次に、tools
の中に、以下の内容でhelp.rb
とrun.sh
を作成して下さい。
n = gets.split[-1].to_i
tmp = 0
File.open("res.txt", mode = "r+") do |f|
s = f.read
tmp += s.nil? ? 0 : s.to_i
tmp += n
end
File.delete("res.txt")
File.open("res.txt", mode = "w") do |f|
f.puts tmp
end
cp /dev/null ./res.txt
g++ main.cpp -o main
for file in $(ls -1 ./in/*.txt); do
./main < $file > out.txt
cargo run --release --bin vis $file ./out.txt > ./out2.txt
cat ./out2.txt | ruby help.rb
done
echo "Done! Score:"
cat res.txt
そして、またtools
の中にres.txt
というファイルを作成して下さい。
今こんな感じになっていれば大丈夫だと思います。
tools/
├ in/
├ src/
├ target/
├ help.rb
├ run.sh
└ main.cpp
この状態で、
$ cd ~/途中のディレクトリ/tools/
$ sh ./run.sh
とするとテストケースの実行が始まると思います。
(想定される)Q&A
Pythonを使っているのですがどうすればいいですか?
main.cpp
の代わりにmain.py
を作って、
run.sh
の中身を
cp /dev/null ./res.txt
for file in $(ls -1 ./in/*.txt); do
python3 ./main.py < $file > out.txt
cargo run --release --bin vis $file ./out.txt > ./out2.txt
cat ./out2.txt | ruby help.rb
done
echo "Done! Score:"
cat res.txt
としてください。
動かなかったです。
今記事を書いているのがAHC013開催中なので、それ以降のAHCではローカル版ビジュアライザ・入力ジェネレータの中身
が異なるかもしれません。その時はrun.sh
とhelp.rb
を上手く書き換えてみて下さい。
動作が遅いのですが。
ごめんなさい…
ShellScriptとRubyを合わせて使っているのでかなり遅くなっています。
「俺のほうが速い実行スクリプト書けるぞ!」という方はぜひコメントよろしくお願いいたします🙏
最後に
AHC楽しい〜!