AtCoderってinput()で入力を受け取って、print()で結果を出力しているので
- 標準入力をファイルにして
- 標準出力をio.StringIOにすれば
検証用プログラム自作できるよね、ってことで、ちょっと雑なプログラムですが作ってみました。
使い方
前提
- data/inXXX.txtに入力データ、data/outXXX.txtに正解データが出力されており、それらを検証に使用しています。(XXXは0埋め整数)
- Python 3.9.15 で動作確認しています(macOS Monterey)
コマンド
python try2.py answer.py
- 検証用プログラム(try2.py)に解答プログラム(answer.py)のpathを指定して実行します
- 全部正解だと最後に'AC'と出力します。不正解の場合は'WA'です。
try2.py
- 日本語の正規化にneologdn使ってます(AtCoderなら要らないはず)
というわけでソースはコチラ(try2.py)
import glob
import sys, os
import io
import neologdn
import subprocess
def try_all(exec_python_path):
in_path_all = sorted(glob.glob("data/in*.txt"))
error_count = 0
for in_path1 in in_path_all:
out_path1 = in_path1.replace("in","out")
with open(in_path1,"r") as f_in:
# 標準入力を file に、標準出力を io.StringIO に結びつけてsubprocessで実行する
proc = subprocess.Popen(['python', exec_python_path], encoding='utf-8', stdin=f_in, stdout=subprocess.PIPE)
stdout, stderr = proc.communicate()
stdout_io = io.StringIO(stdout)
with open(out_path1,"r") as f_out:
all_output = f_out.readlines()
all_temp = stdout_io.getvalue().split('\n')
for out_str1 in all_output:
stdout_str1 = neologdn.normalize(all_temp.pop(0)) # neologdnで正規化してから比較する
out_str1 = neologdn.normalize(out_str1) # neologdnで正規化してから比較する
if out_str1 != stdout_str1:
print(f"Error! temp={stdout_str1}, answer={out_str1}, in_path={in_path1}")
error_count += 1
else:
print(f"OK temp={stdout_str1}, answer={out_str1}")
pass
print("AC" if error_count == 0 else "WA")
if __name__ == "__main__":
try_all(sys.argv[1])
徒然なる補足
- 日本語の正規化が不要な場合はそっくりそのまま取り外してください。
- 入力データと出力データは、先に正解のプログラムを作っておいて、ファイル出力しています。
- 途中で”Error”とか"OK"とかprint文で出していますが、邪魔なときはコメントアウトして使ってください。
-
AtCoderの検証用プログラムをPythonで自作した(雑) のsubprocess版です。
説明が重複している部分はごめんなさい
バッドなノウハウ
- 最初はNotebookでやろうと思ったんですが標準入力と標準出力を切り替えられなかったので断念しました。なので.pyファイルで作っています。
- subprocess.run()でstdoutにio.String()を渡すとエラーが出てちょっとハマりました。上記のようにPopen()とcommunicate()使うと解決できました。
感想
- ちょっと便利になりました。
- AtCoder用のテスト自動化ツール(コンテスト中も使えるやつ)はもっと高機能なものがあるので、本格的な利用にはそちらを使ってみることをおすすめします。こことか。