8
9

Xcode de AtCoder

Last updated at Posted at 2021-04-03

0. はじめに

2年ほど前からAtCoderに参加しています。はじめた頃はVSCode上でKotlinを使用していました。しかし、もともとXcode+Swiftでアプリを開発していたことと、AtCoderのジャッジシステムが新しくなったこともあって、昨年(2020年)4月からSwiftでAtCoderに参加しています。
AtCoderのコンテスト中、テストケースの実行やコードの提出は、AtCoderのコンテストページから/へのコピペで行っていましたが、『これら、自動化できるよね』ということで、今回の記事に至りました。

AtCoderに関する自動化については、下記2つの記事が大変参考になります。
  1. AtCoderの提出自動化をする(Python)

  2. atcoder初心者こそ環境構築しよう!(atcoder-cli,online-judge-toolsのインストール、使い方)

Swift言語においても、VSCodeやコマンドラインでコンパル&実行するなら、上記の記事で十分ですが、今回はXcodeのコンソールアプリのプロジェクトを使い回すことを前提にしています。つまり、コンテストや問題ごとにソースファイルを分けずに、常に一つのXcodeプロジェクトで実施しようというものです。これがベストプラクティスとは言いませんが、自分はこの環境でAtCoderに参加したいということです。

1. 今回のゴール

Xcode+SwiftのコンソールアプリにてAtCoderの解答コードを作成し、サンプルテストケースの自動実行とAtCoderへのソースコードの提出を自動化すること。

2. 準備

前出の自動化記事を参考に、online-judge-toolsatcoder-cliをインストールしておきます。

3. 環境

a) Xcodeのコンソールアプリのプロジェクト

Xcodeで 新規プロジェクト(New Project) macOS Command Line Tool と進み、「プロジェクト名」やプロジェクトの「格納先ディレクトリ」を指定して作成したプロジェクトは、標準入力/標準出力から入出力するコンソールアプリとなります。変更しない限りプロジェクト名=プログラム名です。

b) ソースファイルの場所の確認

上記で指定したプロジェクトフォルダ配下にmain.swiftとして作成されます。このファイルにAtCoderの問題を解くコードを書きます(いわゆるコーディング)。
AtCoderへ提出するコードがこれになるのでフルパスをメモしておきます。

c) ビルドして生成されるバイナリファイルの場所の確認

Xcodeでビルドすると、実行ファイルが生成されます。このファイルの場所は、XcodeのプロジェクトナビゲーターのProductsの下にあるプロジェクト名と同名の実行ファイルをクリックすると、フルパスを知ることができます。
スクショ
またShow in Finderを選べば、その場所のファインダーが開きます。
ローカル環境でテストするバイナリファイル(実行ファイル)がこれになるのでフルパスをメモしておきます。
XcodeでRun(実行)すると、このプログラムが起動され、Xcode上のコンソールで入力や出力されます。もちろん、ターミナルを開き、この実行ファイルを直接起動することもできます。

4. 自動化

AtCoderの2つの自動化に対応します。

  1. テストの自動化
  2. ソースコードの提出

4.1 テストの自動化

AtCoderのコンテストでは各問題ごとに例題として数件のテストケースが提供されます。『この入力を与えると、こう出力されたら正解』といった例です。この例題の入力と出力をもとに、作成したプログラムの動作確認を自動で行うことが目的です。
これには前出online-judge-tools(oj)を使用します。ojはターミナルから投入するコマンドです。

a) AtCoderへログイン

下記のコマンドを投入します。AtCoderへのログインは、コンテストごとに最初に一回実行しておきます。

$ acc login
  ? username: ユーザID
  ? password: パスワード
$ oj login -u ユーザID -p パスワード https://atcoder.jp/

b) テストケースのダウンロード

サブフォルダ作成とテストケースのダウンロードをまとめて行ってくれるacc newを使用します。コマンドの引数にコンテストIDを指定します。
この例では、コンテストID:ABC190

$ acc new abc190

すると、カレントディレクトリに、以下のようにコンテストIDフォルダが作成され、その配下に問題タスクごとのテストケースをダウンロードして入力と出力ファイルが作成されます。

.
└── ABC190
    ├── a
    │   └── tests
    │       ├── sample-1.in
    │       ├── sample-1.out
    │       ├── sample-2.in
    │       ├── sample-2.out
    │       ├── sample-3.in
    │       └── sample-3.out
    ├── b
    │   └── tests
    │       ├── sample-1.in
    │       ├── sample-1.out
    │       ├── sample-2.in
    │       ├── sample-2.out
    │       ├── sample-3.in
    │       └── sample-3.out
    ├── c
    │   └── tests
    │       ├── sample-1.in
    │       ├── sample-1.out
    │       ├── sample-2.in
    │       ├── sample-2.out
    │       ├── sample-3.in
    │       └── sample-3.out
    ├── contest.acc.json
    ├── d
    │   └── tests
    │       ├── sample-1.in
    │       ├── sample-1.out
    │       ├── sample-2.in
    │       ├── sample-2.out
    │       ├── sample-3.in
    │       └── sample-3.out
    ├── e
    │   └── tests
    │       ├── sample-1.in
    │       ├── sample-1.out
    │       ├── sample-2.in
    │       ├── sample-2.out
    │       ├── sample-3.in
    │       └── sample-3.out
    └── f
        └── tests
            ├── sample-1.in
            ├── sample-1.out
            ├── sample-2.in
            └── sample-2.out
acc contest|tasksコマンドでAtCoderのURLが取得可能です。
$ acc contest abc190
AtCoder Beginner Contest 190  https://atcoder.jp/contests/abc190

$ acc tasks abc190
A  Very Very Primitive Game  https://atcoder.jp/contests/abc190/tasks/abc190_a
B  Magic 3                   https://atcoder.jp/contests/abc190/tasks/abc190_b
C  Bowls and Dishes          https://atcoder.jp/contests/abc190/tasks/abc190_c
D  Staircase Sequences       https://atcoder.jp/contests/abc190/tasks/abc190_d
E  Magical Ornament          https://atcoder.jp/contests/abc190/tasks/abc190_e
F  Shift and Inversions      https://atcoder.jp/contests/abc190/tasks/abc190_f

c) テスト

これまでは準備で、やっとテストです。
下記コマンドで実行します。各問題のサブディレクトリに移動して実行します。例えば、A問題はディレクトリaを指定します。

$ cd コンテストID
$ cd a
$ oj test -d tests -c "実行ファイルパス"

結果は、下記の通り。それぞれのテストケースが自動でテストされて出力と照合してACとなっています。
実行ファイルパスは固定のため、環境変数SWIFTEXEに設定しています。

$ cd ABC190
$ cd a
$ oj test -d tests -c "$SWIFTEXE"
[INFO] online-judge-tools 11.1.1 (+ online-judge-api-client 10.8.0)
[INFO] 3 cases found
time: illegal option -- f
usage: time [-lp] <command>
[WARNING] GNU time is not available: time

[INFO] sample-1
[INFO] time: 0.035278 sec
[SUCCESS] AC

[INFO] sample-2
[INFO] time: 0.009566 sec
[SUCCESS] AC

[INFO] sample-3
[INFO] time: 0.009297 sec
[SUCCESS] AC

[INFO] slowest: 0.035278 sec  (for sample-1)
[SUCCESS] test success: 3 cases 

4.2 提出の自動化

下記コマンドでソースコードを提出します。コマンドの引数で前述の問題ごとのURLを指定します。
この例では、
 コンテストID:ABC190
 問題ID:ABC190-A (A問題)
コマンドの引数の意味は、--no-guess:推測しない、-y:応答確認しない、--no-open:提出後にAtCoderのサイトを開かない、 -l:言語を指定、です。

$ oj submit --no-guess -y --no-open -l Swift https://atcoder.jp/contests/abc190/tasks/abc190_a "ソースファイルパス"

結果は以下の通り。
ソースファイル名は固定のため、環境変数SWIFTSRCに設定しています。

$ oj submit --no-guess -y --no-open -l Swift https://atcoder.jp/contests/abc190/tasks/abc190_a "$SWIFTSRC"
[INFO] online-judge-tools 11.1.1 (+ online-judge-api-client 10.8.0)
[WARNING] cannot guess URL since the given file is not in the current directory
: : :
: : :
[INFO] chosen language: 4055 (Swift (5.2.1))
[WARNING] the problem "https://atcoder.jp/contests/abc190/tasks/abc190_a" is specified to submit, but no samples were downloaded in this directory. this may be mis-operation
[INFO] sleep(3.00)
: : :
: : :
[SUCCESS] result: https://atcoder.jp/contests/abc190/submissions/19897304
[INFO] save cookie to: /Users/USERNAME/Library/Application Support/online-judge-tools/cookie.jar

ソースコードの提出はできましたが、想定外のワーニングが出ています。カレントディレクトリにソースファイルが置かれていないことが原因のようです。
とは言え、今回の目的は問題ごとにソースファイルを分けないので、元のソースファイルをカレントディレクトリにコピーしてこのファイルを指定するようにしました。するとワーニングがなくなります。

$ cp $SWIFTSRC ./
$ oj submit --no-guess -y --no-open -l Swift https://atcoder.jp/contests/abc190/tasks/abc190_a main.swift
[INFO] online-judge-tools 11.1.1 (+ online-judge-api-client 10.8.0)
[INFO] read history from: /Users/USERNAME/Library/Caches/online-judge-tools/download-history.jsonl
[INFO] found urls in history: https://atcoder.jp/contests/abc190/tasks/abc190_a
[INFO] problem recognized: AtCoderProblem.from_url('https://atcoder.jp/contests/abc190/tasks/abc190_a'): https://atcoder.jp/contests/abc190/tasks/abc190_a
[INFO] code (13321 byte):
: : :
: : :
[SUCCESS] result: https://atcoder.jp/contests/abc190/submissions/19897431
[INFO] save cookie to: /Users/USERNAME/Library/Application Support/online-judge-tools/cookie.jar

例えば、問題Aから問題Bへの切り替えは、サブディレクトの移動だけですみます。

$ cd ../b

5. コマンドレス化(CUI化)

上手く実現できる方式がなかなか見つからないのでGUI化を見送って、上記までの種々のコマンドをシェルスクリプトに閉じ込めて1文字のキャラクタをタイプするだけで実行可能にしました。

$ . ~/atc コンテストID

スクリプトの中身は、login実行、環境変数等を設定、acc new コンテストIDの実行、下記コマンドのfunction定義、です。

コマンド 意味 内容
a A問題を選択 サブディレクトをA問題に切り替え
b B問題を選択 サブディレクトをB問題に切り替え
c C問題を選択 サブディレクトをC問題に切り替え
d D問題を選択 サブディレクトをD問題に切り替え
e E問題を選択 サブディレクトをE問題に切り替え
f F問題を選択 サブディレクトをF問題に切り替え
t テスト 選択中の問題のテスト
s 提出 選択中の問題のソースコードを提出

コンテスト終了後に、logoutは手動で実行します。

6. おわりに

前出記事の真似に過ぎませんが、実際のコンテストに数回参加し実践しましたが、超絶便利になりました。自画自賛ですが、AtCoderされている方にはぜひ自動化お勧めします

ジャッジ結果がモーダルで表示される、stanicさんが開発したプラグインも大変便利です。こちらを参照してください。⇒ AtCoderResultNotifier - AtCoderの提出結果を通知するUserScriptを作成しました

これを使うために、SafariからGoogle Chromeに変えました。 こちらのuserscriptsをSafariにインストールすれば、上記のプラグインがSafariでちゃんと動きました。AtCoderResultNotifierの「スクリプトをインストール」ではインストールできないのでちょっと手こずりました。

New Remoteを選び、Enter remote url:にhttps://greasyfork.org/scripts/371225-atcoderresultnotifier/code/AtCoderResultNotifier.user.jsを入れてOK。ファイルが読み込まれたら、右下のSaveをクリック。

みなさんの参考になれば幸いです。以上

7. 追加情報(2021.12.26追記)

7.1 online-judge-toolsのアップデート

アップデートの案内に従ってコマンドを投入するだけです。

$ pip install --upgrade pip           # pip自身のアップデート
$ pip3 install -U online-judge-tools
$ pip3 install -U online-judge-api-client

7.2 gnu-timeのインストール

$ oj test -d tests -c "$SWIFTEXE"
 [INFO] online-judge-tools 11.5.1 (+ online-judge-api-client 10.10.0)
 [INFO] 2 cases found
+[WARNING] GNU time is not available: gtime
+[HINT] You can install GNU time with: $ brew install gnu-time

$

アップデート後、上記のようにgtimeのインストールの案内が出てきたのでgnu-timeをインストールしました。

$ brew install gnu-time

すると、テスト時のWARNINGが出なくなりスッキリしました。

$ oj test -d tests -c "$SWIFTEXE"
/Users/USERNAME/Library/Developer/Xcode/DerivedData/AtCoder-fbvzrmhzrmdoyxeaszbdjifcteet/Build/Products/Debug/AtCoder -d tests
[INFO] online-judge-tools 11.5.1 (+ online-judge-api-client 10.10.0)
[INFO] 2 cases found

[INFO] sample-1
[INFO] time: 0.013775 sec
[SUCCESS] AC

[INFO] sample-2
[INFO] time: 0.010516 sec
[SUCCESS] AC

[INFO] slowest: 0.013775 sec  (for sample-1)
[INFO] max memory: 2.188000 MB  (for sample-1)
[SUCCESS] test success: 2 cases
$

参考情報

online-judge-tools/oj

atcoder-cli チュートリアル

8
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
9