AHCにおけるローカルテストについて

第一回 AHCをみんなで解く会コンテストのための記事です。

discord.gg

ローカルテストの必要性

ジャッジに投げるだけだと

  • 提出制限があり、短時間に何度も提出できない
  • テストケースの偏りにより、最終ジャッジでは点数が下がる可能性がある
  • ビジュアライザによる分析ができない

難易度別ローカルテスト

難易度は私の主観で決めています。

レベル1 Webビジュアライザを使う

環境構築の必要性ゼロ!! AHC001ビジュアライザ

入力の準備

generate
ビジュアライザのSeed:の欄に好きな数字を入れてGenerateをクリック
input
すると、input:欄に標準入力が形成されるのでコピー (ctrl+A / cmd+Aで全て選択してコピーすると楽ちん)

出力の準備

コードテストなり、IDEなりでプログラムを実行し、出力をコピー

結果のビジュアライズ

output: 欄に貼り付けて、Visualizeを実行

output

考察

結果を眺めて、アイデアを出す

〜環境構築の壁〜

みなさん、競技プログラミングをするときには何を使ってコードを書いていますか? 私はしばらくコードテストを使っていました。 なぜか?そう、環境構築の壁が立ちはだかるからですね。 環境構築とは、プログラムの実行環境を整えることです。書いたプログラムを、自分のPCで動かせるようにする、ただそれだけなんですけどね… 使っているOSによってやり方が違ったり、昔の記事がアテにならなかったり、エラーの内容が多岐にわたっていたりで、非常につまづきやすいポイントだと思います。 中には黃や橙レートの、私からみて現人神のような方々でさえ、環境構築は難しいとおっしゃっているので、私なんかが説明するのは無理です… ググってくれ!!

レベル5 ビジュアライザを使う

ありがたいことにAHCでは毎回Rust製のビジュアライザが提供されています。 環境構築(自分の言語 + Rust)さえ乗り越えれば、Webビジュアライザよりも多数のテストを高速に行ったり、自分で必要な情報のみを受取ることができたりといいことづくしです。

テストケースの生成

seed値という数字から、テストケースを生成するプログラムがgen.rsです。 ダウンロードした時点で既に50個用意されていますが、いずれ足りなくなってくるので、たとえば1000個のテストケースを用意したいというときに使うプログラムです。

以下、ビジュアライザのREADME.ja.txtを補足する形で説明していきます。 まず8行目

以下の解説では、このREADMEファイルの置かれているディレクトリ上に現在居ることを想定します。

ここから躓いたひとはいませんか。当時の私です。 これはVSCodezshコマンドプロンプトなど、ターミナルでtoolsディレクトリを開いているということです。cdコマンドなどで移動します。もしくは、MacであればFinderから任意のフォルダでターミナルを起動できます

terminalの起動

in ディレクトリに予め生成された入力ファイルが50個用意されています(暫定テストやシステムテストで用いられる入力とは異なります)。より多くの入力ファイルが欲しい方は seeds.txt に欲しい入力ファイルの数だけ乱数seed値(符号なし64bit整数値)を記入し、以下のコマンドで生成して下さい。 cargo run --release --bin gen < seeds.txt

seeds.txtはダウンロードしたままでも予め用意されているので、まずはこのコマンドを説明します。 (テストケースを増やしたい場合はseeds.txtにずらーっとseed値を書き込むことになります。1000個も数字を手打ちできないのでpythonとかで作っちゃいましょう。

print(*(i for i in range(1000)), sep = "\n")

cargo run --release --binはRust製のプログラムを実行するコマンド(リリースビルド、バイナリ実行のオプションについては私も詳しくないので割愛…) gen < seeds.txtgenというファイルを実行するときに標準入力としてseeds.txtを用いますよ、という意味です。

ビジュアライザ

cargo run --release --bin vis <input_file> <output_file>

入力ファイルとその入力に対する出力ファイルを読み込み、出力結果のビジュアライズ結果を out.svg というファイルに書き出します。 標準出力にはスコアを出力します。 svgファイルは画像ビューアソフト、webブラウザなどで表示できます。 vis.html ファイルを開くことでも表示できます。

cargo run --release --bin visvis.rsを起動するよ!の意味で <input_file> <output_file>でテストケースが書いてあるテキストファイルとそのテストケースから得られた出力が書かれたテキストファイルを指定します。

(補足) ターミナルでのコマンドでは、<が標準入力の指定(リダイレクト)の記号として使われるので、gen.rsでは< seeds.txtという引数を与えていましたが、vis.rsではcargo run --release --bin visの後のコマンドを<なしでも読み込めるようにプログラムが書かれているので、<なしでも動きます。うーん書いててわからなくなってきた

とにもかくにも、これでテストケースと出力からローカルでビジュアライザを動かすことができました! …でもこれだけだとWebビジュアライザを動かした方が早いし見やすいですよね?

レベル6 スクリプトでビジュアライザを動かす

ところで、pythonにはsubprocessというモジュールがあります

subprocess --- サブプロセス管理 — Python 3.11.1 ドキュメント

先程までターミナルに手打ちしていたコマンド、退屈ですよね?退屈といえば、退屈なことはpythonにやらせようですよね?(未読)

import subprocess
subprocess.run("cargo run --release --bin vis input.txt output.txt", shell=True)

subprocess.run("<command>", shell=True)を用いるとターミナルにを打ち込んだのと同じ結果が得られます。 これで例えば何個ものテストケースをまとめて実行することが可能になります

import subprocess
for i in range(100):
    input_file = f"in/{i:04d}.txt"
    output_file = f"out/{i:04d}.txt"
    subprocess.run(f"python3 main.py <{input_file} >{output_file}")
    subprocess.run(f"cargo run --release --bin vis {input_file} {output_file}", shell=True)

100個のテストケースを事前に用意していれば、100個まとめで一つのスクリプトで実行できてしまうのです!