AtCoder に Rust で参加するときは cargo-compete がお勧め

# はじめに

[cargo\-atcoderの代替品を作った \- Qiita](https://qiita.com/qryxip/items/bff57848ac9310d27f1a) で紹介されている、cargo-compete を 1か月ほど使っています。

とても便利ですので、 AtCoder に Rust で参加している方にお勧めしたいと思いました。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">AtCoder ABC262 お疲れさまでした。D 問題のループ指定ミスで1時間悩まされましたが、2分前にぎりぎり虫取りできました。テストケースのコピペなど定型作業を担当してくれた cargo-compete に感謝。これなしだと 3問でした。 <a href="https://t.co/JUjYigmj0t">pic.twitter.com/JUjYigmj0t</a></p>&mdash; ほっしー (@hossie) <a href="https://twitter.com/hossie/status/1553740830371827713?ref_src=twsrc%5Etfw">July 31, 2022</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

# 想定読者
* Rust で AtCoder に参加している
* 定型作業でのタイムロスを感じている
* (Windows + Visual Studio Code を使っている)
    * 違う OS や違うエディターの方は読み替えてください

# 定型作業でのタイムロス

[はじめに \- AtCoderコンテストにRustで参加するためのガイドブック](https://doc.rust-jp.rs/atcoder-rust-resources/) で紹介されている通り行っていました。

* 事前準備
    * 解くだろう A-E 問題それぞれについて:
        * `cargo generate --git https://githu：b.com/rust-lang-ja/atcoder-rust-base --branch ja` でプロジェクト作成
        * `cargo test` しておく (初回ビルド・テストに時間がかかるので)
* 本番
    * A-E 問題それぞれについて:
        * テストケースを問題ページからコピーペースト ★1
            * 複数行の場合はインデントを除くなど書き換える
        * 解く
        * `cargo test` でテストし、通過を確認する
            * テキストの完全一致なので、実際の採点より厳しい。実数の精度などはねられることがある
            * 並列実行されるので、どのテスト結果がどう間違っているか追いづらい 
        * WEB フォームから提出し、WEB で結果を確認する ★2
            * 画面が狭いと、この結果を待っている間ほかのことをしづらい
            * 注意しないとたまに違う問題の解答として提出してしまう
* 事後作業
    * 不要なバイナリファイルを消す

★1, ★2 は合計しても数分程度の地味なものですが、地味に手作業のミスが入るところでした。制限時間がある中で、こんなところを意識したくないです。

# cargo-compete を使う
[GitHub \- qryxip/cargo\-compete: A Cargo subcommand for competitive programming](https://github.com/qryxip/cargo-compete/) 詳細はこちら。

## 本番例 (2022-08-22 ABC 265)
21時に以下のコマンドを入力します。

```terminal
> cargo compete new abc265
> cd abc265
> cargo compete open
```

a-ex のコードを書くひな形がすべて「単体テスト付きで」得られます。もうコピーペーストは必要ありません。

```
abc265/
  src/
    bin/
      a.rs
      b.rs
      :
  testcases/
    a.yml
    b.yml
    :
```

コードを書くのはいつも通り。コードを書き終わったら単体テストします。

```terminal
> cargo compete test a
: 中略
1/4 ("sample1") Accepted (21 ms)
2/4 ("sample2") Accepted (16 ms)
3/4 ("sample3") Accepted (25 ms)
4/4 ("sample4") Accepted (26 ms)
: 中略
```

問題なければそのまま提出。ブラウザーに切り替えなくて良いです。

```terminal
> cargo compete submit a
: 中略
Successfully submitted the code
│ 2022-08-21 21:03:22 +09:00 │ A - Apple │ Rust (1.42.0) │ AC  │     7 ms │    2116 KB │
: 中略
```

お疲れさまでした。次の問題に進みます。

`cargo compete submit` は提出前に単体テストして、通過するときだけ提出します。A 問題などで自信があるなら `cargo compete test` は省略しても良いでしょう。


## 初期設定例

このように cargo-compete を使うには、インストール・初期設定が必要です。1回だけ

`cargo compete init` 私はバイナリ提出不要な `2` を設定しました。

a.rs などの初期コードは compete.toml 内にテンプレートで書けます。私はガイドブックと同じ設定にしています。

```toml
[template]
src = '''
use proconio::input;

fn main() {
    input! {
        n: usize,
        mut plan: [(i32, i32, i32); n],  // Vec<(i32, i32, i32)>
    }
    plan.insert(0, (0, 0, 0));
    let yes = plan.windows(2).all(|w| {
        let (t0, x0, y0) = w[0];
        let (t1, x1, y1) = w[1];
        let time = t1 - t0;
        let dist = (x1 - x0).abs() + (y1 - y0).abs();
        dist <= time && time % 2 == dist % 2
    });
    println!("{}", if yes { "Yes" } else { "No" });
}
'''
```

# Q&A

* Q. 実数を比較するテストは書きやすい？
    * A. 数値の誤差に対応しています。書きやすいです。文字列一致はキツイです。
* Q. 複数解やタイムアウトのためがテストケースが通らないけれど、自信があるので提出したい、ということはできる？
    * A. `cargo compete submit --no-test` できます。
* Q. タイムアウトが厳しくて、AC のはずのコードでも手元では Timelimit Exceeded してしまう
    * A. 初期設定では dev ビルド設定のため、10倍ほど実行時間が延びることがあります。テストファイル yml の時間制限を `timelimit: 30s` など増やすのはありです。
        * compete.toml でリリースビルド設定にすれば良いのかも。未確認です。 
* Q. まず 1つのテストだけ通したいけれど、`cargo compete test` では問題全体に対して実行してしまう。`cargo test <TESTNAME>` のように絞り込みたい。
    * A. yml ファイルをコメントアウトして一時的にテスト対象から除けば良いです。テスト関数単位でコメントアウトするより簡単です。
* Q. 関数単位で単体テストを書きたい
    * A. `cargo test` はこれまで通りできます。a-ex すべて対象になります。
* Q. デバッグ実行できる？
    * A. これまで通り、VS Code + CodeLLDB でできます。
* Q. printf デバッグできる？
    * A. `> ..\target\debug\abc265-a.exe` のように実行すればできます。`cargo compete test` は出力文字数が多いときには表示しないようです。 

# 最後に

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">AtCoder ABC265 お疲れさまでした。ポカミスがありましたが、はじめての5問正解で満足です。 <a href="https://t.co/F1HxiAtvEz">pic.twitter.com/F1HxiAtvEz</a></p>&mdash; ほっしー (@hossie) <a href="https://twitter.com/hossie/status/1561349436474736640?ref_src=twsrc%5Etfw">August 21, 2022</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

5分前に5問目提出。cargo-compete がなければ時間切れでした。cargo-compete お勧めです。

そんな、嬉しくて勢いで書いた記事でした。