追記(2020/08/10)
このエントリで紹介している cargo-atcoder
の進化版として、@qryxip さんにより、cargo-compete
が開発されました。
↓↓↓詳しくはご本人による紹介エントリをご覧ください!↓↓↓
cargo-atcoderの代替品を作った - Qiita
(追記終わり)
Rust で競技プログラミングをやっている方であれば、
Rustで競技プログラミングの入力をスッキリ記述するマクロ - Qiita
で紹介されている input!
マクロのことを見聞きしたことがある方が多いのではないかと思います。競プロにおいて第一級市民である C++ に比べて標準入力からの受け取りが冗長になりがちな Rust において、さまざまな入力形式に対応する汎用性と記述の短さをもつ input!
マクロがもたらす恩恵はとても大きなものです。
さて、このマクロを作成した @tanakh さんによって、Rust での AtCoder ライフを超絶快適にするツールが開発されています。その名は cargo-atcoder
このエントリでは、cargo-atcoder の導入方法や使い方について紹介し、Rust で AtCoder に参加していらっしゃる方々の競プロライフを豊かにする手助けができればなと思います。
なお、このエントリで紹介する内容はほとんど GitHub の README に書かれていますので、一次ソースを確認したい方はそちらをぜひご覧ください。
↓リポジトリへのリンク↓
tanakh/cargo-atcoder: Cargo subcommand for AtCoder
【更新履歴】
- 2020/08/10 次世代ツール
cargo-compete
の紹介エントリへのリンクを貼りました。 - 2020/06/06
Cargo.toml
に書く dependencies を欲張りすぎるとビルド時間が長くなって大変だという旨の記述を追加しました。 - 2020/05/10 インストール方法を変更しました (crates.io に公開されたため)
cargo-atcoder とは
@tanakh さんによって作成された、Rust での AtCoder ライフを豊かにするためのツールです。
豊かにするというのは、具体的には以下のようなことができます。
-
Cargo.toml
や 提出コードの雛形を決めておけば、コンテスト名を指定するだけでコンテスト用のプロジェクトディレクトリが作成できます。- 例:
cargo atcoder new abc164
(ABC164 のためのディレクトリを作成)
- 例:
- 書いたコードがテストケースをパスするかどうかをコマンド一発で確認できます。
- 解答の提出がコマンド一発でできます。
- 例:
$ cargo atcoder submit a
(A問題のコードを提出)
- 例:
- 提出結果をコマンドで習得できます。リアルタイム更新です。
- 例:
$ cargo atcoder status
- 例:
導入方法
インストール
もし cargo
が入っていない場合は、何よりもまずインストールしてください。
以下のページにあるコマンドをコピペして実行すればインストールできます。
rustup.rs - The Rust toolchain installer
cargo
が入ったら以下のコマンドを実行すればOKです。ビルドをするので結構時間かかります。コーヒーでも飲みながら気長にお待ちください。(手元の環境では3分ほどかかりました)
$ cargo install cargo-atcoder
インストールが完了したら、以下のコマンドを打ってみてください。コマンドの説明がずらずら〜と出てきたらOKです。
$ cargo atcoder --help
cargo-atcoder 0.1.0
USAGE:
cargo atcoder <SUBCOMMAND>
FLAGS:
-h, --help Prints help information
-V, --version Prints version information
(以下略)
セットアップ
ログインする
まず、AtCoder へのログイン情報 (Cookie) をローカルに保存する必要があります。
以下のコマンドを実行すると、ユーザー名とパスワードを聞かれるので、指示通り入力してください。
$ cargo atcoder login
成功すると Login succeeded.
と表示されます。
(ちなみに Cookie の有効期限は180日間のようです。)
設定ファイルを用意する
各プロジェクトの雛形を設定ファイルに書く必要があります。
設定ファイルの場所は OS や設定している環境変数ごとに異なるので、下記を参考にしてください。
OS | 設定ファイルの場所 | 例 |
---|---|---|
Linux | $XDG_CONFIG_HOME/cargo-atcoder.toml または $HOME/.config/cargo-atcoder.toml | /home/maguro/.config/cargo-atcoder.toml |
macOS | $HOME/Library/Preferences/cargo-atcoder.toml | /Users/maguro/Library/Preferences/cargo-atcoder.toml |
Windows | {FOLDERID_RoamingAppData}\cargo-atcoder.toml | C:\Users\maguro\AppData\Roaming\cargo-atcoder.toml |
ログイン済みであればすでに上記の場所に cargo-atcoder.toml
が作成されているはずですので、中身を覗いてみてください。
いくつかの項目について簡単に説明します。
submit_via_binary
闇の力です。Rust の真のパワーを発揮するべく、ローカルでビルドし、バイナリでの提出を行います。
つまり、このオプションが true
にセットされている場合、ローカルでビルドして生成された実行バイナリを提出して、ジャッジサーバー上ではそのバイナリが実行されます。
ジャッジサーバー上の実行環境に関係なく、最新バージョン、nightly バージョンの Rust を使ったり、好きなクレートを使ったりすることができます。
闇の力の代償として、
- 提出ファイルサイズが極めて大きくなる(設定にもよりますが、ABC の A問題程度のコード量であっても、300KB を超えます)
- 実行時のオーバーヘッドが発生する(最低でも 4ms の実行時間がかかる)
- 手元でビルドするので、提出までに少し時間がかかる
といったデメリットがあります。しかし、メリットの大きさはデメリットを補って余りあるものでしょう。
use_cross
ジャッジサーバーは Linux 環境です。上記の闇の力を使用してバイナリ提出を行う場合、Linux 向けの実行バイナリを生成する必要があります。
use_cross
オプションを true
にしておくと、cross
という設定要らずのクロスコンパイル環境を使ってコンパイルが行われるようになります。
お使いの環境が Linux ではない場合、とりあえず true
にしておくほうが面倒事が少なくて良いかなと思います。
なお、cross
を使うのに Docker
が必要となるので、事前にご準備ください。
↓cross
のリポジトリ↓
rust-embedded/cross: “Zero setup” cross compilation and “cross testing” of Rust crates
strip_path
バイナリで提出をする際、ファイルサイズを減らすために strip
というコマンドで処理されます。その strip
コマンドへのパスを指定するためのオプションです。
PATH が通った場所に strip
がある場合は特に指定する必要はありません。
GNU 版の strip
が必要なので、macOS ユーザーの方は以下のコマンドでインストールしてください。
$ brew install binutils
target
デフォルトで "x86_64-unknown-linux-musl"
が入っていると思いますが、そのままでOKです。
[dependencies]
ここに書いたクレートが、プロジェクト作成時に Cargo.toml
へとコピーされます。
とりあえず新ジャッジサーバーで使えるクレートを全部指定しておきたい場合は、以下をコピペしてください。
(以下のクレートは、バイナリ提出せずとも使えるクレートです)
※依存クレートが多くなるとビルド時間がとても長くなるので、実際には本当に使うクレートだけに絞って書いたほうが良いと思います。
[dependencies]
num = "0.2.1"
num-bigint = "0.2.6"
num-complex = "0.2.4"
num-integer = "0.1.42"
num-iter = "0.1.40"
num-rational = "0.2.4"
num-traits = "0.2.11"
num-derive = "0.3.0"
ndarray = "0.13.0"
nalgebra = "0.20.0"
alga = "0.9.3"
libm = "0.2.1"
rand = { version = "0.7.3", features = ["small_rng"] }
getrandom = "0.1.14"
rand_chacha = "0.2.2"
rand_core = "0.5.1"
rand_hc = "0.2.0"
rand_pcg = "0.2.1"
rand_distr = "0.2.2"
petgraph = "0.5.0"
indexmap = "1.3.2"
regex = "1.3.6"
lazy_static = "1.4.0"
ordered-float = "1.0.2"
ascii = "1.0.0"
permutohedron = "0.2.4"
superslice = "1.0.0"
itertools = "0.9.0"
itertools-num = "0.1.3"
maplit = "1.0.2"
either = "1.5.3"
im-rc = "14.3.0"
fixedbitset = "0.2.0"
bitset-fixed = "0.1.0"
proconio = { version = "0.3.6", features = ["derive"] }
text_io = "0.1.8"
whiteread = "0.5.0"
rustc-hash = "1.1.0"
smallvec = "1.2.0"
template
ここに書いた内容が、問題ごとのコードファイルの初期コードとして展開されます。
例えば、以下のように設定ファイルに書いておくと
template = """
use proconio::{input, fastout};
#[fastout]
fn main() {
todo!();
}
"""
プロジェクト作成したときに、以下のように展開されます。
use proconio::{input, fastout};
#[fastout]
fn main() {
todo!();
}
使い方
プロジェクトを作成する
AtCoder Beginner Contest 163 のためのプロジェクトを作成することを考えます。
以下のコマンドを実行します。
$ cargo atcoder new abc163
abc163
というディレクトリができます。ディレクトリ構造は以下のような感じです。
abc163
├── Cargo.lock
├── Cargo.toml
└── src
└── bin
├── a.rs
├── b.rs
├── c.rs
├── d.rs
├── e.rs
└── f.rs
Cargo.toml
の dependencies
にさきほど設定ファイルで書いたものが、そして src/bin/
以下にある a.rs
などにも設定ファイルの templates
に書いた内容があることが確認できると思います。
ちなみに、プロジェクト作成時に指定した abc163
というのは、コンテストページのURLの末尾に書いてあるものです。
例えば パナソニックプログラミングコンテスト2020 のプロジェクトを作成したいときは、このコンテストのURLが
https://atcoder.jp/contests/panasonic2020
なので、以下のようにすればOKです。
$ cargo atcoder new panasonic2020
テストケースを試す
ABC163 の A問題を解いてみました。
use proconio::{fastout, input};
#[fastout]
fn main() {
input! {
r: f64,
}
println!("{}", 2.0 * r * std::f64::consts::PI);
}
テストケースが通るか確認してみます。以下のコマンドを実行します。
$ cargo atcoder test a
以下のように実行され、テストが通ることが確認できました。テストケースをブラウザからコピペして1つ1つ試す必要はもうありません。
提出する
テストが通ったので、提出しましょう。A問題を提出する場合は以下のコマンドを実行します。
$ cargo atcoder submit a
このようになります。🎉 AC 🎉
なお、 submit
する時にもテストケースが通るかどうかの確認がされます。なので test
せずにいきなり submit
でも良いと思います。
ちなみに、submit
コマンドは、デフォルトでは提出前のテストケースチェックで通過しなかった場合には提出を行わない仕様となっています。
「いくつか答えがありうるけど、そのうち1つが出力されてればOK」というタイプの問題については、用意されているテストの出力例と一致しなくても正解である、という場合がありえます。
この問題タイプの場合には submit
に --force
オプションをつけてください。テストが通らなくても提出を行うようになります。
(-f
でもOKです)
$ cargo atcoder submit a --force
最後に
cargo-atcoder の導入方法と主要機能の使い方をご紹介しました。
超強力な機能であるバイナリ提出に関して「闇の力」という表現をしましたが、運営サイドとしてもこれはグレーであるという認識のようで、chokudaiさんが以下のようなツイートをしています。
バイナリ提出については、アップデート頻度が落ち着き次第、何かしらの制限をかける可能性が結構あります。そのあたりはご了承くださいな。
— chokudai(高橋 直大)🌸🍆🍡 (@chokudai) January 31, 2020
どのような制限になるかは分かりませんが、さきほど書いた通りバイナリ提出はファイルサイズが大きくなるという欠点があります。例えば提出ファイルサイズの上限が現在の 512KiB から 64KB に下げられるだけでも、バイナリ提出は厳しくなるものと思われます。
(Codeforces のファイズサイズ上限が 64KB です)
バイナリ提出は cargo-atcoder の超強力な機能の1つであることは間違いないですが、それを抜きにしても、コマンドラインからのテストケースの実行や提出などはとても体験が良いものなので、ぜひお試しください。
別の cargo-xxx として、@hatoo@github さん作の cargo-snippet があります。スニペット管理をスマートに行えるこれまた素晴らしいツールです。
こちらもおすすめです!
Rustで競技プログラミングをするときの"スニペット管理"をまじめに考える(cargo-snippetの紹介) - Qiita