⚙️

Rustのcargo-competeを使ってAtCoderに挑む

2024/03/02に公開

概要

Rust で AtCoder に挑む際、cargo-compete を使うと
ソースをローカルで管理できる上、テストや提出時の煩わしさを軽減できて快適でした。

https://github.com/qryxip/cargo-compete

環境構築と実際のコンテスト時の手順をまとめました。

どちらも初心者なので拙い部分はあるかと思いますが、
参考にしていただければ幸いです。

環境構築

Rustup のインストール

rustup と併せて rust のパッケージ管理ツールである cargo および、
rust コンパイラの rustc もインストールされます。

brew install rustup-init # rustup-initをインストール
rustup-init # rustup-initを実行

cargo-compete のインストール

cargo install cargo-compete

ジャッジに合わせた Rust のインストール

ジャッジ更新によってバージョンが変動するため、

適宜 AtCoder 公式の言語一覧をご参照ください。

https://img.atcoder.jp/file/language-update/language-list.html

rustup install 1.70.0

cargo-compete 初期設定

AtCoder のログイン情報の入力

cargo compete login atcoder
# 自身のログイン情報を入力します。

AtCoder 用のファイル群の作成

cargo compete init atcoder
Do you use crates on AtCoder?
1 No
2 Yes
3 Yes, but I submit base64-encoded programs
1..3: # 迷った場合はとりあえず2で大丈夫です

2を選択した場合、以下のファイル群が作成されます。

.
├── .cargo
│   └── config.toml
├── compete.toml
└── template-cargo-lock.toml

compete.toml の編集

長くなるので、各テーブルごとに分けて記載します。

[template.new]

edition2018
dependances は現在のジャッジで使用可能なクレート群に変更します。

compete.toml
[template.new]
edition = "2018"
dependencies = '''
ac-library-rs = "=0.1.1"
once_cell = "=1.18.0"
static_assertions = "=1.1.0"
varisat = "=0.2.2"
memoise = "=0.3.2"
argio = "=0.2.0"
bitvec = "=1.0.1"
counter = "=0.5.7"
hashbag = "=0.1.11"
pathfinding = "=4.3.0"
recur-fn = "=2.2.0"
indexing = "=0.4.1"
amplify = "=3.14.2"
amplify_derive = "=2.11.3"
amplify_num = "=0.4.1"
easy-ext = "=1.0.1"
multimap = "=0.9.0"
btreemultimap = "=0.1.1"
bstr = "=1.6.0"
az = "=1.2.1"
glidesort = "=0.1.2"
tap = "=1.0.1"
omniswap = "=0.1.0"
multiversion = "=0.7.2"
num = "=0.4.1"
num-bigint = "=0.4.3"
num-complex = "=0.4.3"
num-integer = "=0.1.45"
num-iter = "=0.1.43"
num-rational = "=0.4.1"
num-traits = "=0.2.15"
num-derive = "=0.4.0"
ndarray = "=0.15.6"
nalgebra = "=0.32.3"
alga = "=0.9.3"
libm = "=0.2.7"
rand = "=0.8.5"
getrandom = "=0.2.10"
rand_chacha = "=0.3.1"
rand_core = "=0.6.4"
rand_hc = "=0.3.2"
rand_pcg = "=0.3.1"
rand_distr = "=0.4.3"
petgraph = "=0.6.3"
indexmap = "=2.0.0"
regex = "=1.9.1"
lazy_static = "=1.4.0"
ordered-float = "=3.7.0"
ascii = "=1.1.0"
permutohedron = "=0.2.4"
superslice = "=1.0.0"
itertools = "=0.11.0"
itertools-num = "=0.1.3"
maplit = "=1.0.2"
either = "=1.8.1"
im-rc = "=15.1.0"
fixedbitset = "=0.4.2"
bitset-fixed = "=0.1.0"
proconio = { version = "=0.4.5", features = ["derive"] }
text_io = "=0.1.12"
rustc-hash = "=1.1.0"
smallvec = "=1.11.0"
'''
dev-dependencies = '''
#atcoder-202004-lock = { git = "https://github.com/qryxip/atcoder-202004-lock" }
'''

[test]

toolchain のバージョンを現在のジャッジシステムに合わせます。

compete.toml
[test]
toolchain = "1.70.0"

[submit]

language_id を "5054" に変更します。

compete.toml
[submit]
kind = "file"
path = "{{ src_path }}"
language_id = "5054"

[template]

後述の cargo compete new時に生成される.rsファイルの初期状態です。

お好みで編集してください。
例えば下記のような形です。

compete.toml
[template]
src = '''
#[allow(unused_imports)]
use itertools::{iproduct, Itertools};
#[allow(unused_imports)]
use num_traits::pow;
#[allow(unused_imports)]
use proconio::{
    fastout, input,
    marker::{Chars, Usize1},
};
#[allow(unused_imports)]
use std::cmp::{max, min};
#[allow(unused_imports)]
use std::collections::{HashMap, HashSet, VecDeque};
#[allow(unused_imports)]
use std::iter::FromIterator;

#[fastout]
fn main() {
    input!{
        h: usize, w: usize,
        s: [Chars; h],
        mut plan: [(usize, usize, usize); h]
    }
}
'''

回答時の手順

コンテスト用ファイル群の作成

cargo compete new {コンテスト名}

{コンテスト名}は、
コンテストページ URL のhttps://atcoder.jp/contests/{コンテスト名}{コンテスト名}部分です。

例えば AtCoder Bigger Contest338 ↓ であれば abc338
https://atcoder.jp/contests/abc338

鉄則本の演習問題 ↓ であれば tessoku-book です
https://atcoder.jp/contests/tessoku-book

abc338の場合、以下のようなファイル群が生成されます。

abc338/
├── Cargo.lock
├── Cargo.toml
├── src
│   └── bin
│       ├── a.rs
│       ├── b.rs
│       ├── c.rs
│       ├── d.rs
│       ├── e.rs
│       ├── f.rs
│       └── g.rs
└── testcases
    ├── a
    │   ├── in
    │   └── out
    ├── a.yml
    ├── b
    │   ├── in
    │   └── out
    ├── b.yml
    ├── c
    │   ├── in
    │   └── out
    ├── c.yml
    ├── d
    │   ├── in
    │   └── out
    ├── d.yml
    ├── e
    │   ├── in
    │   └── out
    ├── e.yml
    ├── f
    │   ├── in
    │   └── out
    ├── f.yml
    ├── g
    │   ├── in
    │   └── out
    └── g.yml

.rsが回答用のソース、.ymlが問題文中の各テストケースです。
/testcases配下の各ディレクトリにテストケースを配置することで、
後述のcargo compete testで併せてテストできます。

cd {コンテスト名}

以降の手順はコンテストのディレクトリに移動して行います。

テストケースの実行

cargo compete test {問題名}

{問題名}は、a 問題であれば a です。

各テストケースの結果が表示されます。

提出

cargo compete submit {問題名}

自動でテストが実行され、全て AC だった場合に提出されます。

また、提出後の判定状況も表示されます。

--no-testオプションをつけることで、テストせずに提出することも可能です。

まとめ

cargo-competeを使うことで AtCoder に少し楽に挑めます。

Discussion