AtCoder等のプログラミング問題を解く際、提出前に手元の環境で動作確認すると思う。私の場合は便利な環境を用意できていなく1、代わりに paiza.io を利用している2。
問題には入出力の例が複数与えられているのでなるべく全て試したいが、入力例をいちいち変えるのが辛い。自分で例を追加する場合は尚更である。
環境を整えてさえいれば、テストの自動生成なども可能なようだが…
何とかならないか考えた結果、Rubyにおいて1行で解決する方法を思いついた。
方法
Rubyスクリプトの最後に以下の1行を追加する。解答のメソッド化などは必要ない。
load __FILE__ unless $stdin.eof?
あとは入力例を結合して読み込ませれば、全ての出力がまとめて表示される。
【追記】
スクリプト内で exit
を使う可能性を考慮したより汎用的な方法。Rubyスクリプトの先頭のほう(必ず実行される場所)に以下の1行を追加する。
END { load __FILE__ unless $stdin.eof? }
制限
解答のスクリプト内では「入力終端まで読み込む」ことをしてはいけない。問題に与えられた数字をもとに #gets
などで正確な行数だけ取得しなければいけない。
動作原理
単に同じスクリプトを何度も実行している。
Kernel.#load
は Kernel.#require
と異なり、常に指定ファイルを読み込む。指定ファイルとして自分自身を与えれば、スクリプトを再び先頭から実行する効果が得られる。あとは無限ループ防止のために「入力終端でなければ」という条件を追加すればいい。
【追記】
END
を使った方法はRubyの終了処理の仕組みを利用している。「同じスクリプトの実行」を終了処理の一環として登録することで、スクリプトの途中で終える場合でも動作する。
例
AtCoder Beginner Contest 154 の A問題 に適用してみる。この問題は入力が3行で与えられる。
s, t = gets.split
a, b = gets.split.map(&:to_i)
u = gets.chomp
if u == s
a -= 1
else
b -= 1
end
puts "#{a} #{b}"
load __FILE__ unless $stdin.eof?
入力例が2つあるので、それらを結合して与える。
red blue
3 4
red
red blue
5 5
blue
すると、それぞれの結果がまとめて表示される。
2 4
5 4
制限に違反した場合
解答のスクリプト内で「入力終端まで読み込む」ことをしてしまうと、一度に試すことはできなくなる。提出する分には問題ない。
s, t, *ab, u = $stdin.read.split
ab.map!(&:to_i)
ab[u == s ? 0 : 1] -= 1
puts ab * " "
load __FILE__ unless $stdin.eof?
3 3 0 0 0 5 5