44 个版本
0.10.7 | 2024年6月8日 |
---|---|
0.10.6 | 2023年8月13日 |
0.10.4 | 2022年2月19日 |
0.10.2 | 2021年12月15日 |
0.6.4 | 2020年11月24日 |
#98 in Cargo 插件
92 每月下载次数
220KB
5K SLoC
cargo-compete
编程竞赛的 Cargo 子命令。
支持 AtCoder、Codeforces 和 yukicoder。其他网站可通过 online-judge-tools/api-client 使用。
功能
- 登录网站,
- (自动) 注册比赛,
- 检索示例/系统测试用例,并将其保存为 YAML 文件,
- 为 YAML 文件测试您的代码,
- 提交您的代码,
- 查看您的提交。(仅 AtCoder 可用)
注册 | 示例测试用例 | 系统测试用例 | 提交 | 查看提交 | 提交详情 | |
---|---|---|---|---|---|---|
AtCoder | ✔️ | ✔️ | ✔️ | ✔️ | ❔ | ❌ |
Codeforces | ❌ | ✔️ | N/A | ✔️ | ❌ | ❌ |
yukicoder | N/A | ✔️ | ✔️ | ✔️ | ❌ | ❌ |
其他网站 | ❌ | 依赖于 online-judge-tools | 依赖于 online-judge-tools | 依赖于 online-judge-tools | ❌ | ❌ |
安装
从 Crates.io
$ cargo install cargo-compete
如果构建失败,添加 --locked
可能有所帮助。
从 master
分支
$ cargo install --git https://github.com/qryxip/cargo-compete
从 GitHub 发布版
我们在 GitHub 发布版中提供了二进制文件。
用法
cargocompete init
为其他命令生成一些文件。
首先运行此命令。它将生成以下文件。
-
其他命令所需的文件。
-
设置
build/target-dir
以共享target
目录。 -
template-cargo-lock.toml
这是用于
cargo compete new
的Cargo.lock
模板。只有当你回答Do you use crates on AtCoder?
问题为“2 Yes”时才会生成。如果生成了此文件,将其文件路径添加到compete.toml
中的new.template.lockfile
。
cargocompete migrate cargo-atcoder
请参阅日语文档中的该部分。
cargocompete login
登录网站。
这不是一个包的命令。
您不需要事先运行此命令,因为cargo-compete在需要时会请求凭据。
cargocompete participate
注册比赛。
这不是一个包的命令。
您不需要事先运行此命令,因为cargo-compete在需要时会注册比赛。
cargocompete new
检索测试用例并为比赛创建一个包。
需要compete.toml
。首先使用cargo compete init
生成。
您可以使用--open
选项在浏览器中打开页面。您还可以通过在compete.toml
中测试open
来在浏览器中打开源文件和测试用例。如果您忘记添加--open
,请转到生成的包的目录并运行cargo compete open
。
cargocompete add
生成bin
目标并检索它们的测试用例。
需要compete.toml
。首先使用cargo compete init
生成。
要使用此功能,请按照以下方式配置compete.toml
中的add
。
# for yukicoder
[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
#target-kind = "bin" # ["bin", "example"]. default to "bin"
bin-name = '{% assign segments = url | split: "/" %}{{ segments[5] }}'
#bin-alias = '{% assign segments = url | split: "/" %}{{ segments[5] }}' # optional
#bin-src-path = './src/bin/{{ bin_alias }}.rs' # optional
❯ 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
为现有包检索测试用例。
这是一个包的命令。转到使用cargo compete new
生成的包。
使用--open
选项,您可以下载系统测试用例而不是示例测试用例。
对于AtCoder,我们必须使用Dropbox API。以某种方式生成具有以下两个权限的访问令牌,
文件.元数据.读取
共享.读取
并将JSON文件保存为以下格式到{本地数据目录}/cargo-compete/tokens/dropbox.json
。(我在想更好的方法)
{
"access_token": "<access token>"
}
cargocompete retrieve submission-summaries
检索您的提交,并以JSON格式输出。
这是一个包的命令。转到使用cargo compete new
生成的包。
例如,您可以通过添加| jq -r '.summaries[0].detail
来获取“最新提交的URL”。
$ # for Linux
$ xdg-open "$(cargo compete r ss | jq -r '.summaries[0].detail')"
cargocompete open
在浏览器中打开页面,并在编辑器中打开源代码和测试用例。
这是一个包的命令。转到使用cargo compete new
生成的包。
cargocompete test
运行测试。
这是一个包的命令。转到使用cargo compete new
生成的包。
您不需要事先运行此命令,因为测试是在 “submit” 命令 中运行的。
cargocompete submit
提交您的代码。
这是一个包的命令。转到使用cargo compete new
生成的包。
您可以通过设置 submit
来使用 cargo-equip 和 cargo-executable-payload 工具将代码进行转换,并在 compete.toml
中进行配置。
[submit]
kind = "command"
args = ["cargo", "+1.70.0", "equip", "--exclude-atcoder-202301-crates", "--remove", "docs", "--minify", "libs", "--bin", "{{ bin_name }}"]
language_id = "5054"
[submit]
kind = "command"
args = ["cargo", "executable-payload", "--bin", "{{ bin_name }}"]
language_id = "5054"
配置
以下是一个 compete.toml
的示例。
# Path to the test file (Liquid template)
#
# Variables:
#
# - `manifest_dir`: Package directory
# - `contest`: 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)
#
# Additional filters:
#
# - `kebabcase`: Convert to kebab case (by using the `heck` crate)
test-suite = "{{ manifest_dir }}/testcases/{{ bin_alias }}.yml"
# Open files with the command (`jq` command that outputs `string[] | string[][]`)
#
# VSCode:
#open = '[["code", "-a", .manifest_dir], ["code"] + (.paths | map([.src, .test_suite]) | flatten)]'
# Emacs:
#open = '["emacsclient", "-n"] + (.paths | map([.src, .test_suite]) | flatten)'
[template]
src = '''
fn main() {
todo!();
}
'''
[template.new]
# `edition` for `Cargo.toml`.
edition = "2018"
# `profile` for `Cargo.toml`.
#
# By setting this, you can run tests with `opt-level=3` while enabling `debug-assertions` and `overflow-checks`.
#profile = '''
#[dev]
#opt-level = 3
#'''
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"
'''
dev-dependencies = '''
#atcoder-202004-lock = { git = "https://github.com/qryxip/atcoder-202004-lock" }
'''
[template.new.copy-files]
"./template-cargo-lock.toml" = "Cargo.lock"
[new]
kind = "cargo-compete"
# Platform
#
# - atcoder
# - codeforces
# - yukicoder
platform = "atcoder"
# Path (Liquid template)
#
# Variables:
#
# - `contest`: Contest ID. **May be nil**
# - `package_name`: Package name
path = "./{{ contest }}"
#[new]
#kind = "oj-api"
#url = "https://atcoder.jp/contests/{{ id }}"
#path = "./{{ contest }}"
# for Library-Checker
#[add]
#url = "https://judge.yosupo.jp/problem/{{ args[0] }}"
##is-contest = ["false"] # optional
##target-kind = "bin" # ["bin", "example"]. default to "bin"
#bin-name = '{{ args[0] }}'
##bin-alias = '{{ args[0] }}' # optional
##bin-src-path = './src/bin/{{ bin_alias }}.rs' # optional
# for yukicoder
#[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
##target-kind = "bin" # ["bin", "example"]. default to "bin"
#bin-name = '{% assign segments = url | split: "/" %}{{ segments[5] }}'
##bin-alias = '{% assign segments = url | split: "/" %}{{ segments[5] }}' # optional
##bin-src-path = './src/bin/{{ bin_alias }}.rs' # optional
[test]
# Toolchain for the test. (optional)
toolchain = "1.42.0"
# Profile for `cargo build`. ("dev" | "release")
#
# Defaults to `"dev"`.
#profile = "dev"
[submit]
kind = "file"
path = "{{ src_path }}"
language_id = "5054"
#[submit]
#kind = "command"
#args = ["cargo", "+1.70.0", "equip", "--exclude-atcoder-202301-crates", "--remove", "docs", "--minify", "libs", "--bin", "{{ bin_name }}"]
#language_id = "5054"
以下是 Cargo.toml
中 package.metadata
的一个示例。
[package]
name = "practice"
version = "0.1.0"
authors = ["Ryo Yamashita <[email protected]>"]
edition = "2018"
[package.metadata.cargo-compete.bin]
practice-a = { alias = "a", problem = "https://atcoder.jp/contests/practice/tasks/practice_1" }
practice-b = { alias = "b", problem = "https://atcoder.jp/contests/practice/tasks/practice_2" }
#[package.metadata.cargo-compete.example]
[[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 = ["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"
[dev-dependencies]
测试套件
测试用例保存为 YAML 文件。
# https://atcoder.jp/contests/practice/tasks/practice_1
---
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
# https://atcoder.jp/contests/ddcc2019-final/tasks/ddcc2019_final_a
---
type: Batch
timelimit: 2s
match:
Float:
relative_error: 1e-8
absolute_error: 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
# https://judge.yosupo.jp/problem/sqrt_mod
---
type: Batch
timelimit: 10s
match:
Checker:
cmd: ~/.cache/online-judge-tools/library-checker-problems/math/sqrt_mod/checker "$INPUT" "$ACTUAL_OUTPUT" "$EXPECTED_OUTPUT"
shell: Bash
cases: []
extend:
- type: SystemTestCases
以下格式中包含 TestSuite
。
TestSuite
一个内部标记的 ADT。
TestSuite::批量
一个普通问题的测试套件。
字段 | 类型 | 默认值 | 描述 |
---|---|---|---|
timelimit |
持续时间 | null |
~ |
时间限制 |
match |
匹配 |
判断方法 | |
cases |
案例[] |
[] |
输入和输出集合 |
extend |
扩展[] |
[] |
额外的输入和输出集合 |
持续时间
一个可以与 humantime::format_duration
解析的字符串。
匹配
一个未标记的 ADT。
Match::Exact
= "Exact"
比较整个字符串。
Match::SplitWhitespace
= "SplitWhitespace"
比较通过空白分隔的单词。
Match::Lines
= "Lines"
比较行。
匹配::Float
比较通过空白分隔的单词。
absolute_error
和 relative_error
用于可以解析为浮点数的单词对。
字段 | 类型 | 默认值 | 描述 |
---|---|---|---|
relative_error |
正有限浮点64 | null |
~ |
相对误差 |
absolute_error |
正有限浮点64 | null |
~ |
绝对误差 |
PositiveFiniteFloat64
一个正数,且不是 inf
的 64 位浮点数。
匹配::Checker
使用 shell 脚本进行验证。
以下环境变量提供给脚本。
INPUT
ACTUAL_OUTPUT
EXPECTED_OUTPUT
(如果存在Case.out
)
字段 | 类型 | 默认值 | 描述 |
---|---|---|---|
cmd |
str |
命令 | |
shell |
Shell |
Shell |
Shell
一个未标记的 ADT。
Shell::Bash
= "Bash"
Bash.
案例
字段 | 类型 | 默认值 | 描述 |
---|---|---|---|
名称 |
str |
"" |
名称 |
在 |
str |
输入 | |
输出 |
str | null |
~ |
输出 |
timelimit |
持续时间 | null |
~ |
覆盖 timelimit |
match |
匹配 | null |
~ |
覆盖 match |
扩展
一个内部标记的 ADT。
扩展::文本
字段 | 类型 | 默认值 | 描述 |
---|---|---|---|
路径 |
str |
目录 | |
在 |
通配符 |
输入文本文件 | |
输出 |
通配符 |
输出文本文件 | |
timelimit |
持续时间 | null |
~ |
覆盖 timelimit |
match |
匹配 | null |
~ |
覆盖 match |
通配符
一个通配符。
扩展::系统测试用例
系统测试用例。
系统测试用例存储在 { 缓存目录 }/cargo-compete/system-test-cases
。当执行 test
代码时,如果缺失则自动下载。
字段 | 类型 | 默认值 | 描述 |
---|---|---|---|
问题 |
URL | null |
~ | 问题的URL |
URL
一个URL。
TestSuite::交互式
交互式问题的测试套件。
字段 | 类型 | 默认值 | 描述 |
---|---|---|---|
timelimit |
持续时间 | null |
~ |
时间限制 |
TestSuite::不可提交
用于像 APG4b 中的示例的哑测试套件。
字段 | 类型 | 默认值 | 描述 |
---|
Cookies和令牌
Cookies和令牌保存在 { 本地数据目录 }/cargo-compete
。
.
├── cookies.jsonl
└── tokens
├── codeforces.json
├── dropbox.json
└── yukicoder.json
环境变量
cargo-compete 如果存在则读取这些环境变量,并使用它们。
$DROPBOX_ACCESS_TOKEN
$YUKICODER_API_KEY
$CODEFORCES_API_KEY
$CODEFORCES_API_SECRET
使用 online-judge-tools
对于不支持的网站,在 $PATH
中使用 oj-api(.exe)
进行 download
和 submit
。
[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" }
与 cargo-atcoder 的比较
请参阅 日语说明中的部分。
许可
双许可下 MIT 或 Apache-2.0。
依赖
~39–55MB
~1M SLoC