はむ吉(のんびり)の練習ノート

プログラミングとことばに関する話題を中心に,思いついたこと,試してみたこと,学んだことを,覚え書きを兼ねてまとめます.その際に役立った,技術書,参考書,辞書,機器などの紹介も行います.

Online Judge Template Generator を Windows 10 + Python で使う:AtCoder コンテストにおける提出コードの作成,テストから提出まで

Online Judge Template Generator (OJTG) *1は,提出コードのひな型作成や,ランダムテストケースの作成といった機能を備え,競技プログラミングの問題やコンテストへの取り組みを強力に支援するツール群です.本記事では,Windows 10 環境に OJTG を導入し,AtCoder のコンテスト(過去問を含む)に Python で取り組む*2際に,これを活用する方法について述べます.

はじめに

競技プログラミングでは,ただ問題に答えるコードを書くだけではなく,それをテストにより検証したり,オンラインジャッジに提出したりする必要があります.この操作は,時として煩雑となり,その過程で思わぬ誤りが生じ,苦しむこともあります.そこで,近年さまざまな支援ツールが開発されました.その例として,以前紹介した online-judge-tools や atcoder-cli が挙げられます.このようなツールのおかげで,作業を省力化し,解法やその実装法を考える時間を増やすことができるようになりました.

今回紹介する OJTG は,上記の online-judge-tools とも連携し,競技プログラミングにつきものの作業に対し,さらなる強力な支援を行うツールです*3.このツール群には,たとえば以下のような機能が含まれています.

  • 問題を解析し,適切な入出力処理を含む,解答コードのひな型を作成する
  • 問題の制約に合うランダムケースを出力するコード(ジェネレータ)を作成する
  • 上記のコードおよび問題に記された入出力例を,取り組むコンテストの構成に合わせて適切にプロジェクトに配置する

本記事では,Windows 10 環境において,AtCoder のコンテストに Python で取り組むことを想定して,上記の支援機能を用いる方法を説明します.OJTG はほかのオンラインジャッジや言語にも既定で対応しているか,適切な設定により対応させることができますが,ここでは一つの例として,このケースについて述べます.

主な前提条件

  • OS: Windows 10(バージョン 1909 で動作を確認)
  • Python: 3.8.3
  • 問題を解くのに利用する Python の処理系(すなわち CPython *4)とエディタが導入されている
  • 以前の記事に従い,online-judge-tools の導入および AtCoder へのログインが完了している
  • 簡単のため,各種ツールは,ユーザごとではなくグローバルに導入するものとする
  • Windows Subsystem for LinuxCygwin などは使わず,Windows 環境に直接諸ツールを導入する

ツールの導入と初期設定

Python 3 環境が適切に導入されていれば,以下の操作で OJTG と関連ツールを導入できます.

pip3 install online-judge-template-generator

AtCoder のコンテストに取り組む

以下では,AtCoder Beginner Contest 177 - AtCoderA - Don't be latePython で解くことを想定し,一連の操作を行います.なお,以下ではこの問題に対するネタバレがあるので,注意してください.

コンテストのプロジェクトを作成する

解答コードのひな型,入出力例,ジェネレータを,一括して得るには,以下を実行します.コンテストの問題数や通信環境によっては,処理に時間がかかることがあります.

oj-prepare https://atcoder.jp/contests/abc177

しばらく待つと,問題ごとに,abc177_a から abc177_f までのディレクトリが現れます.ここでは,abc177_a に入ります.

cd abc177_a

このディレクトリには,以下のファイルやディレクトリが存在します.

  • main.cpp: 解答コード (C++) *5
  • main.py: 解答コード (Python)
  • generator.py: ジェネレータ
  • test: 入出力例を含むディレクト
    • sample-*.in: 問題に記載の入力例
    • sample-*.out: 問題に記載の出力例

解答コードを作成する

解答のコードは main.py に記述します.初期状態では,たとえば以下のようになっています.

#!/usr/bin/env python3
# from typing import *

YES = 'Yes'
NO = 'No'

# def solve(D: int, T: int, S: int) -> str:
def solve(D, T, S):
    pass  # TODO: edit here

# generated by online-judge-template-generator v4.4.0 (https://github.com/kmyk/online-judge-template-generator)
def main():
    D, T, S = map(int, input().split())
    a = solve(D, T, S)
    print(a)

if __name__ == '__main__':
    main()

以下のように修正すれば,問題に答えるコードになるはずです.

#!/usr/bin/env python3
# from typing import *

YES = 'Yes'
NO = 'No'

# def solve(D: int, T: int, S: int) -> str:
def solve(D, T, S):
    return YES if S * T >= D else NO

# generated by online-judge-template-generator v4.4.0 (https://github.com/kmyk/online-judge-template-generator)
def main():
    D, T, S = map(int, input().split())
    a = solve(D, T, S)
    print(a)

if __name__ == '__main__':
    main()

ランダムテストケースを作成する

解答コードを検査するには,与えられた入出力例だけではなく,愚直解を利用してランダムテストケースも作成して準備しておくと,なおよいでしょう.そのための方法を記述します.ごく簡単な問題では,この手順は必ずしも必要でないかもしれませんが,込み入った問題になると,この準備が威力を発揮します.

ランダムな入力例

ランダムな入力例を作るためのコードは,generator.py に記載されています.まずはこれを修正します.初期状態では,たとえば次のようなコードになっています.

#!/usr/bin/env python3
# usage: $ oj generate-input 'python3 generate.py'
import random

# generated by online-judge-template-generator v4.4.0 (https://github.com/kmyk/online-judge-template-generator)
def main():
    D = random.randint(1, 10 ** 9)  # TODO: edit here
    T = random.randint(1, 10 ** 9)  # TODO: edit here
    S = random.randint(1, 10 ** 9)  # TODO: edit here
    print(D, T, S)

if __name__ == "__main__":
    main()

たいていのデバッグでは,小さな入力例を用意し,これに対し計算時間がかかるものの確実な解答コード(愚直解)を用いて,対応する出力例を作ることになります.そこで,以下のように設定します.

#!/usr/bin/env python3
# usage: $ oj generate-input 'python3 generate.py'
import random

# generated by online-judge-template-generator v4.4.0 (https://github.com/kmyk/online-judge-template-generator)
def main():
    D = random.randint(1, 100)
    T = random.randint(1, 100)
    S = random.randint(1, 100)
    print(D, T, S)

if __name__ == "__main__":
    main()

これにより,小さな入力例のみが得られます*6.その後,以下を実行します.なお,generate-inputg/i とすることもできます.

oj generate-input "python generate.py"

すると,test/random-*.in という形で,入力例が作成されます.

ランダムな出力例

続いて,愚直解を用いて,入力例に対する出力例を作ります.愚直解は,main.py を複製し,適宜編集して作るとよいでしょう.ここでは,straightforward.py という愚直解を作ったと仮定します.すると,出力例は次のように作れます.なお,generate-outputg/o とすることもできます.

oj generate-output -c "python straightforward.py"

すると,test/random-*.out という形で,出力例が作成されます.

解答コードのテスト

問題文に書かれた入出力例と,上記のランダムな入出力例を用いて,解答コードをテストするには,以下を実行します.なお,testt とすることもできます.

oj test -c "python main.py"

すべてのケースに対して,AC が得られていることを確認しましょう.さもなければ,コードを修正しましょう.

解答コードの提出

コードの提出は,以下で行えます.なお,submits とすることもできます.

oj submit main.py

自動的にブラウザが開き,提出結果が表示されます.

おわりに

OJTG および関連ツールの基本的な使い方をまとめました.今までは複数のツールを行ったり来たりしていましたが,このように,共通の操作感をもつツール群を用いることで,より効率的になりました.今後,実戦等でも活用していきたいと思います.

参考

OJTG および online-judge-tools については,本記事では扱わなかった機能,設定および仕様を含め,以下のドキュメントにわかりやすく記載されています.

*1:OJTG およびそれに関連するツールは,サードパーティ(有志の方々)が手がけられているものです.今後,もし AtCoder の仕様または規約,ポリシー等に変更があった場合,本記事の記述のようには利用できなくなるおそれがあります.

*2:後述のように,OJTG はさまざまなオンラインジャッジと言語に対応しますが,本記事は一つの例として,この場合について述べます.

*3:上述の記事を記した後,開発者の方から OJTG の存在を教えていただきました.

*4:Cython ではありません.

*5:今回は使いません.

*6:ただ,ここでは仮に値の上限を 100 としているものの,それが適切かは状況によります.