[C++ / VS Code] AtCoderのサンプルテストをショートカット一発で実行！

# はじめに
環境構築無しで導入できる [chrome 拡張](https://greasyfork.org/en/scripts/415946-atcoder-easy-test)も便利ですが、コンテスト中は bugfix ⇔ サンプルテストの往復地獄になりがちで、ローカルに自動テストツールの環境は欲しいところです。

この記事では [online-judge-tools](https://github.com/online-judge-tools/oj) を「自分の環境でいかに便利に使うか」について書いています。
それゆえ、全ての人にとって快適に動作することを保証するものではありません。
誰かの環境とバッチリ合致し、この記事を参考にして頂けたなら幸いです。

この記事を書くにあたって @chokoryu さんの [AtCoderで自動サンプルテストケース&手入力値テスト実行 with VS Code](https://qiita.com/chokoryu/items/4b31ffb89dbc8cb86971) をめちゃめちゃ参考にしています！有難うございます。

# この環境でできること
`ctrl + shift + b` で

 1. 今やってる問題のテストケースダウンロード (oj dl ~ コマンド)
 2. ソースコードのコンパイル (普段 C++ を実行するときにやるやつ)
 3. サンプルテストを実行 (oj test ~ コマンド)

　を一発で実行できるようにします。開催中のコンテストでも出来ます。




# 環境および想定するディレクトリ構成

### 環境

- Ubuntu 20.04 LTS (Macでも動くと思います)
- VS Code 1.52.1



### ディレクトリ構成
以下のようにコンテスト毎にディレクトリを作成し、 `abc123/a.cpp` `agc45/b.cpp` のようにファイルを作成したいです。（ファイル名をできるだけ短くしたい思惑あり）
この配置にすることで親ディレクトリ名 + ファイル名 に基づいてテストケースを取りに行きます。
(配置が違う場合もパス周りをいじったらなんとかなりそうです)


```bash
c-pro                   # workspace folder
├── .vscode
├── Codeforces
├── AtCoder
│   ├── abc
│   │   ├── abc001
│   │   ・・・
│   │   ├── abc181
│   │   ├── abc182
│   │   │   ├── a.cpp
│   │   │   ├── a.out
│   │   │   ├── b.cpp
│   │   │   ├── c.cpp
│   │   │   ├── d.cpp
│   │   │   └── e.cpp
│   │   ・・・
│   │
│   ├── agc
│   ├── arc
│   ├── othercontests
│   │
│   └── onlinejudge



```
　




今回いじる設定ファイルの場所です

```bash

c-pro                   # workspace folder
├── .vscode
│   └── tasks.json      # ビルドの設定ファイルです。これと、
├── Codeforces
├── AtCoder
│   ├── abc
│   ├── agc
│   ├── arc
│   ├── othercontests
│   │
│   └── onlinejudge
│       ├── cptest.sh    # これさえ作れば動きます。メインのシェルスクリプト
│       │   
│       └── test         # テストケースの格納ディレクトリ、自動で作られます
│           ├── abc010_3 # コンテスト毎のディレクトリ、自動で作られます
│           │   ├── sample-1.in
│           │   ・・・
│           ├── abc021_b
│           │   ├── sample-1.in
│           │   ・・・


```

# online-judge-tools のインストールとログイン
このあたりは参考にさせて頂いた記事と変わりません。詳しくは [Github](https://github.com/online-judge-tools/oj)へ。

```bash:bash
$ pip install online-judge-tools
$ oj login -u {ユーザー名} -p {パスワード} "https://atcoder.jp/"
$ oj login --check "https://atcoder.jp/"
```

# cptest.sh
メインのシェルスクリプトです。ビルドタスク（ `ctrl + shift + b` で実行されるやつ）から環境変数を渡されて実行されます。
ディレクトリ名やパスが違う場合適宜修正してください。
コンパイルオプションもお好みで！

```bash:cptest.sh
#!/bin/bash

problem_name=$1
problem_name=${problem_name##*/}
test_dir=AtCoder/onlinejudge/test/${problem_name}
base_url=${problem_name%_*}
code_path=$2

# make test directory
if [ ! -e ${test_dir} ]; then
    oj dl -d ${test_dir} https://atcoder.jp/contests/${base_url}/tasks/${problem_name//-/_}
fi

g++ -std=gnu++17 -Wall -Wextra -O2 ${code_path} && oj test -c "./a.out " -d ${test_dir}

```

# tasks.json
ビルドタスクで何をするか？を記述する設定ファイルです。 `workdpacefolder` 直下に `.vscode` ディレクトリを作成し、以下ファイルを作成・保存します。
(`settings.json` などですでに `.vscode` ディレクトリがある場合は新たに作る必要はありません。)

```json:tasks.json
{
    // See https://go.microsoft.com/fwlink/?LinkId=733558
    // for the documentation about the tasks.json format
    "version": "2.0.0",
    "tasks": [
        {
            "label": "test_atcoder_sample",
            "group": {
                "kind": "build",
                "isDefault": true
            },
            "type": "shell",
            "command": "${workspaceFolder}/AtCoder/onlinejudge/cptest.sh",
            "args": [
                "${relativeFileDirname}_${fileBasenameNoExtension}", 
                "${file}"
            ]
        }
    ]
}
```


# いざ、実行！
コードが出来上がってセーブ( `ctrl + s` )したら、 `ctrl + shift + b` するだけで下のように online-judge-tools が動いてくれます！！ 快適！
![Peek 2021-01-11 00-07.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221900/65b19030-eb73-8311-0d90-e61b5e44e8ef.gif)



# うまく行かない場合
「ビルドタスクに `cptest.sh` の実行権限がない」と言われる場合があります。
その場合は `cptest.sh`の権限を変更しておきましょう。

```bash:bash
$ cd onlinejudge/
$ chmod 755 cptest.sh
```


その他にはビルド時のメッセージをよく見ると「変なパスを参照している」「変なURLにリクエストを投げている」ということがありがちなのでチェックしてみましょう。
変な部分が見つかったら適宜 `tasks.json` `cptest.sh` を修正してください。

# ABC, ARC, AGC 以外のコンテストの場合

親ディレクトリの相対パスを取得するような設定になっているので以下のように `othercontests/{コンテスト名}/a.cpp` のようにすればちゃんと動きます。
`{コンテスト名}` は、AtCoder コンテストページの `atcoder.jp/contests/hhkb2020` のように URL に用いられる表記を使ってください。

```bash
c-pro                   # workspace folder
├── .vscode
├── Codeforces
├── AtCoder
│   ├── abc
│   ├── agc
│   ├── arc
│   ├── othercontests
│   │   ・・・
│   │   ├── hhkb2020
│   │   │   ├── a.cpp
│   │   │   ├── a.out
│   │   │   ├── b.cpp
│   │   │   ├── c.cpp
│   │   │   ├── d.cpp
│   │   │   └── e.cpp
│   │   ├── hitachi2020
│   │   │   ├── a.cpp
│   │   │   ├── b.cpp
│   │   │   └── c.cpp
│   │   ・・・
│   │
│   └── onlinejudge



```

# おまけ バーチャルコンテスト向けの jud コマンド！
ビルドタスクへの設定はうまくいったでしょうか？
これだけでもかなり便利なのですが、一点だけ残念な点があります。
それは「バーチャルコンテストなど、バラバラのコンテストから1問ずつ出されるような場合に対応が出来ない」ことです。

```bash
c-pro                   # workspace folder
├── .vscode
├── Codeforces
├── AtCoder
│   ├── abc
│   ├── agc
│   ├── arc
│   ├── asa
│   │   ├── 2020
│   │   │   ├── asa0219
│   │   │   │   ├── a.cpp   # <= 全部
│   │   │   │   ├── b.cpp   # <= 違うコンテストの
│   │   │   │   └── c.cpp   # <= 問題！
│   │   │   ├── asa0220
│   │   │   │   ├── a.cpp
│   │   │   │   ├── b.cpp
│   │   │   │   ├── c.cpp
│   │   │   │   └── d.cpp
│   │   │   ├── asa0221
│   │   │   │   ├── a.cpp
│   │   │   │   ├── b.cpp
│   │   │   │   ├── c.cpp
│   │   │   │   └── d.cpp
│   │   │   ・・・

```
 
　
 



これをショートカット一発で解決するのはなかなか難しいので以下のコマンドを作成し、妥協です。
URLコピペの手間はありますが、複数回テストケースをコピペするよりは快適です。

```bash:bash
$ cd asaXXXX/  # ソースコードのある場所に移動
$ jud https://atcoder.jp/contests/abs123/tasks/abs123_a  # jud + 今開いてる問題ページのURLをコピペ

```
　


出力、動作の様子
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221900/68cf93d4-f832-9949-65c2-a6341da9de19.png)


やり方は簡単です。以下のシェルスクリプトをパスの通ったところに置きましょう。
`test/` が相対パスで書かれているので必要であれば修正してください。

```bash:jud
#!/bin/bash
problem_url=$1
problem_name=${problem_url##*/}
test_dir=../../onlinejudge/test/${problem_name}

# make test directory
if [ ! -e ${test_dir} ]; then
    oj dl -d ${test_dir} ${problem_url}
fi

oj test -c "./a.out" -d ${test_dir}


```


# さいごに
一回環境を作ってしまうと一発でサンプルテストできるのはなかなか便利です、
ディレクトリ構成などは人によって全然違うと思いますが、参考になったならとても嬉しいです。
また、記事内に間違った点があればご指摘頂けますとありがたいです。

それでは、良い精進ライフを！