A Cargo subcommand for competitive programming.
Supports AtCoder, Codeforces, and yukicoder. Other websites are available via online-judge-tools/api-client.
| | Registeration | Sample Test Cases | System Test Cases | Submiting | Watching Submissions | Submission Details | | :------------: | :--------------------: | :---------------------------: | :---------------------------: | :---------------------------: | :---------------------: | :----------------: | | AtCoder | :heavycheckmark: | :heavycheckmark: | :heavycheckmark: | :heavycheckmark: | :greyquestion: | :x: | | Codeforces | :x: | :heavycheckmark: | N/A | :heavycheckmark: | :x: | :x: | | yukicoder | N/A | :heavycheckmark: | :heavycheckmark: | :heavycheck_mark: | :x: | :x: | | Other websites | :x: | Depends on online-judge-tools | Depends on online-judge-tools | Depends on online-judge-tools | :x: | :x: |
console
$ cargo install cargo-compete
If the build fails, adding --locked
may help.
master
branchconsole
$ cargo install --git https://github.com/qryxip/cargo-compete
We provide the binaries in GitHub Releases.
cargo compete init
Generates some files for other commands.
Run this command first. It generates the following files.
Required for other commands.
Sets build/target-dir
to share the target
directory.
template-cargo-lock.toml
A template of Cargo.lock
for cargo compete new
.
Generated only if you answer 2 Yes
to Do you use crates on AtCoder?
question.
If this file is generated, file path to it is added to new.template.lockfile
in compete.toml
.
cargo compete migrate cargo-atcoder
See the section in the Japanese readme.
cargo compete login
Logges in a website.
This is not a command for a package.
You don't have to run this command beforehand, because cargo-compete asks credentials if necessary.
cargo compete participate
Registeres in a contest.
This is not a command for a package.
You don't have to run this command beforehand, because cargo-compete registers in the contest if necessary.
cargo compete new
Retrieves test cases and creates a package for the contest.
Requires compete.toml
.
Generate it with cargo compete init
first.
You can opens the pages in your browser with the --open
option.
And you can also open the source files and the test cases in your browser by testing open
in compete.toml
.
If you forget to add --open
, cd
to the generated package and run cargo compete open
.
cargo compete add
Generates bin
targets and retrieves the test cases for them.
Requires compete.toml
.
Generate it with cargo compete init
first.
To use this function, configure add
in the compete.toml
like this.
```toml
[add] url = '{% case args[0] %}{% when "contest" %}https://yukicoder.me/contests/{{ args[1] }}{% when "problem" %}https://yukicoder.me/problems/no/{{ args[1] }}{% endcase %}' is-contest = ["bash", "-c", '[[ $(cut -d / -f 4) == "contests" ]]'] # optional
bin-name = '{% assign segments = url | split: "/" %}{{ segments[5] }}'
```
console
❯ cargo compete a contest 296
Added `1358` (bin) for https://yukicoder.me/problems/no/1358
Added `1359` (bin) for https://yukicoder.me/problems/no/1359
Added `1360` (bin) for https://yukicoder.me/problems/no/1360
Added `1361` (bin) for https://yukicoder.me/problems/no/1361
Added `1362` (bin) for https://yukicoder.me/problems/no/1362
Added `1363` (bin) for https://yukicoder.me/problems/no/1363
Added `1364` (bin) for https://yukicoder.me/problems/no/1364
Added `1365` (bin) for https://yukicoder.me/problems/no/1365
Saved 1 test case to /home/ryo/src/competitive/yukicoder/testcases/1358.yml
Saved 3 test cases to /home/ryo/src/competitive/yukicoder/testcases/1359.yml
Saved 3 test cases to /home/ryo/src/competitive/yukicoder/testcases/1360.yml
Saved 3 test cases to /home/ryo/src/competitive/yukicoder/testcases/1361.yml
Saved 3 test cases to /home/ryo/src/competitive/yukicoder/testcases/1362.yml
Saved 1 test case to /home/ryo/src/competitive/yukicoder/testcases/1363.yml
Saved 3 test cases to /home/ryo/src/competitive/yukicoder/testcases/1364.yml
Saved 3 test cases to /home/ryo/src/competitive/yukicoder/testcases/1365.yml
❯ cargo compete a problem 9001
Added `9001` (bin) for https://yukicoder.me/problems/no/9001
Saved 1 test case to /home/ryo/src/competitive/yukicoder/testcases/9001.yml
cargo compete retrieve testcases
/ cargo compete download
Retrieves test cases for an existing package.
This is a command for a package.
cd
to the package generated with cargo compete new
.
With --open
option, you can download system test cases instead of sample ones.
For AtCoder, we have to use Dropbox API. Generate an access token with these two permissions in some way,
files.metadata.read
sharing.read
and save a JSON file in the following format to {local data directory}/cargo-compete/tokens/dropbox.json
.
(I'm thinking of better way)
json
{
"access_token": "<access token>"
}
cargo compete retrieve submission-summaries
Retrieves your submissions, and outputs as JSON.
This is a command for a package.
cd
to the package generated with cargo compete new
.
For example, you can get "the URL for the latest submission" by adding | jq -r '.summaries[0].detail
.
console
$ # for Linux
$ xdg-open "$(cargo compete r ss | jq -r '.summaries[0].detail')"
cargo compete open
Opens pages in your browser, and opens source and test cases in your editor.
This is a command for a package.
cd
to the package generated with cargo compete new
.
cargo compete test
Runs tests.
This is a command for a package.
cd
to the package generated with cargo compete new
.
You don't have to run this command beforehand, because the tests are run in the submit
command.
cargo compete submit
Submits your code.
This is a command for a package.
cd
to the package generated with cargo compete new
.
You can convert code with a tool such as cargo-equip and cargo-executable-payload by setting submit.transpile
in the compete.toml
.
```toml [submit.transpile] kind = "command" args = ["cargo", "equip", "--exclude-atcoder-crates", "--resolve-cfgs", "--remove", "docs", "--minify", "libs", "--rustfmt", "--check", "--bin", "{{ bin_name }}"]
```
```toml [submit.transpile] kind = "command" args = ["cargo", "executable-payload", "--bin", "{{ bin_name }}"]
```
Here is an example for compete.toml
.
```toml
#
#
manifest_dir
: Package directorycontest
: Contest ID (e.g. "abc100")bin_name
: Name of a bin
target (e.g. "abc100-a")bin_alias
: "Alias" for a bin
target defined in pacakge.metadata.cargo-compete
(e.g. "a")problem
: Alias for bin_alias
(deprecated)#
#
kebabcase
: Convert to kebab case (by using the heck
crate)test-suite = "{{ manifestdir }}/testcases/{{ binalias }}.yml"
jq
command that outputs string[] | string[][]
)#
[template] src = ''' fn main() { todo!(); } '''
[template.new]
edition
for Cargo.toml
.edition = "2018"
profile
for Cargo.toml
.#
opt-level=3
while enabling debug-assertions
and overflow-checks
.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 = ["smallrng"] } getrandom = "=0.1.14" randchacha = "=0.2.2" randcore = "=0.5.1" randhc = "=0.2.0" randpcg = "=0.2.1" randdistr = "=0.2.2" petgraph = "=0.5.0" indexmap = "=1.3.2" regex = "=1.3.6" lazystatic = "=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"] } textio = "=0.1.8" whiteread = "=0.5.0" rustc-hash = "=1.1.0" smallvec = "=1.2.0" ''' dev-dependencies = '''
'''
[template.new.copy-files] "./template-cargo-lock.toml" = "Cargo.lock"
[new] kind = "cargo-compete"
#
platform = "atcoder"
#
#
contest
: Contest ID. May be nilpackage_name
: Package namepath = "./{{ contest }}"
[test]
toolchain = "1.42.0"
cargo build
. ("dev" | "release")#
"dev"
.```
And here is an example for package.metadata
in Cargo.toml
.
```toml [package] name = "practice" version = "0.1.0" authors = ["Ryo Yamashita qryxip@gmail.com"] edition = "2018"
[package.metadata.cargo-compete.bin] practice-a = { alias = "a", problem = "https://atcoder.jp/contests/practice/tasks/practice1" } practice-b = { alias = "b", problem = "https://atcoder.jp/contests/practice/tasks/practice2" }
[[bin]] name = "practice-a" path = "src/bin/a.rs"
[[bin]] name = "practice-b" path = "src/bin/b.rs"
[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 = ["smallrng"] } getrandom = "=0.1.14" randchacha = "=0.2.2" randcore = "=0.5.1" randhc = "=0.2.0" randpcg = "=0.2.1" randdistr = "=0.2.2" petgraph = "=0.5.0" indexmap = "=1.3.2" regex = "=1.3.6" lazystatic = "=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"] } textio = "=0.1.8" whiteread = "=0.5.0" rustc-hash = "=1.1.0" smallvec = "=1.2.0"
[dev-dependencies] ```
Test cases are saved as YAML files.
```yaml
type: Batch timelimit: 2s match: Lines
cases: - name: sample1 in: | 1 2 3 test out: | 6 test - name: sample2 in: | 72 128 256 myonmyon out: | 456 myonmyon
extend: - type: Text path: "./a" in: /in/.txt out: /out/.txt ```
```yaml
type: Batch timelimit: 2s match: Float: relativeerror: 1e-8 absoluteerror: 1e-8
cases: - name: sample1 in: | 5 -->-- out: | 3.83333333333333 - name: sample2 in: | 7 ------- out: | 6.5 - name: sample3 in: | 10 -->>>-->-- out: | 6.78333333333333
extend: - type: Text path: "./a" in: /in/.txt out: /out/.txt ```
```yaml
type: Batch timelimit: 10s match: Checker: cmd: ~/.cache/online-judge-tools/library-checker-problems/math/sqrtmod/checker "$INPUT" "$ACTUALOUTPUT" "$EXPECTED_OUTPUT" shell: Bash
cases: []
extend: - type: SystemTestCases ```
The format is TestSuite
in the following schemas.
TestSuite
TestSuite::Batch
A test suite for a normal problem.
Field | Type | Default | Description |
---|---|---|---|
timelimit |
Duration | null |
~ |
Time limit |
match |
Match |
Judging method | |
cases |
Case[] |
[] |
Sets of input and output |
extend |
Extend[] |
[] |
Additional sets of input and output |
Duration
A string that can parsed with humantime::format_duration
.
Match
An untagged ADT.
Match::Exact
= "Exact"
Compares whole strings.
Match::SplitWhiteSpace
= "SplitWhitespace"
Compares words splitted by whitespace.
Match::Lines
= "Lines"
Compares lines.
Match::Float
Compares words splitted by whitespace.
absolute_error
and relative_error
are applied for pairs of words that can parsed as floating point numbers.
Field | Type | Default | Description |
---|---|---|---|
relative_error |
PositiveFiniteFloat64 | null |
~ |
Relative error |
absolute_error |
PositiveFiniteFloat64 | null |
~ |
Absolute error |
PositiveFiniteFloat64
A 64-bit floating point number that is positive and is not inf
.
Match::Checker
Checks with a shell script.
The following environment variables are given for the script.
INPUT
ACTUAL_OUTPUT
EXPECTED_OUTPUT
(only if the Case.out
is present)Field | Type | Default | Description |
---|---|---|---|
cmd |
str |
Command | |
shell |
Shell |
Shell |
Shell
An untagged ADT.
Shell::Bash
= "Bash"
Bash.
Case
Field | Type | Default | Description |
---|---|---|---|
name |
str |
"" |
Name |
in |
str |
Input | |
out |
str | null |
~ |
Output |
timelimit |
Duration | null |
~ |
Overrides timelimit |
match |
Match | null |
~ |
Overrides match |
Extend
Extend::Text
Field | Type | Default | Description |
---|---|---|---|
path |
str |
Directory | |
in |
Glob |
Text files for input | |
out |
Glob |
Text files for output | |
timelimit |
Duration | null |
~ |
Overrides timelimit |
match |
Match | null |
~ |
Overrides match |
Glob
A glob.
Extend::SystemTestCases
System test cases.
System test cases are stored under { cache directory }/cargo-compete/system-test-cases
.
They are automatically downloaded if missing when test
ing code.
Field | Type | Default | Description |
---|---|---|---|
problem |
Url | null |
~ | URL of the problem |
Url
A URL.
TestSuite::Interactive
A test suite for an interactive problem.
Field | Type | Default | Description |
---|---|---|---|
timelimit |
Duration | null |
~ |
Time limit |
TestSuite::Unsubmittable
A dummy test suite for dummy problems such as ones in APG4b.
Field | Type | Default | Description |
---|
The cookies and tokens are saved under { local data directory }/cargo-compete
.
console
.
├── cookies.jsonl
└── tokens
├── codeforces.json
├── dropbox.json
└── yukicoder.json
cargo-compete reads these environment variables if they exist, and use them.
$DROPBOX_ACCESS_TOKEN
$YUKICODER_API_KEY
$CODEFORCES_API_KEY
$CODEFORCES_API_SECRET
For unsupported websites, oj-api(.exe)
in the $PATH
is used when download
ing and submit
ting.
```toml [package] name = "library-checker" version = "0.0.0" edition = "2018" publish = false
[package.metadata.cargo-compete.bin] aplusb = { problem = "https://judge.yosupo.jp/problem/aplusb" } ```
See the section in the Japanese readme.
Dual-licensed under MIT or Apache-2.0.