#test-cases #competitive #cargo-subcommand #cli

bin+lib cargo-compete

用于编程竞赛的 Cargo 子命令

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 插件

Download history 73/week @ 2024-04-21 66/week @ 2024-04-28 32/week @ 2024-05-05 33/week @ 2024-05-12 16/week @ 2024-05-19 33/week @ 2024-05-26 169/week @ 2024-06-02 74/week @ 2024-06-09 36/week @ 2024-06-16 29/week @ 2024-06-23 48/week @ 2024-06-30 24/week @ 2024-07-07 22/week @ 2024-07-14 21/week @ 2024-07-21 32/week @ 2024-07-28 13/week @ 2024-08-04

92 每月下载次数

MIT/Apache

220KB
5K SLoC

cargo-compete

CI codecov dependency status Crates.io Crates.io Join the chat at https://gitter.im/cargo-compete/community

日语

编程竞赛的 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

为其他命令生成一些文件。

首先运行此命令。它将生成以下文件。

  • compete.toml

    其他命令所需的文件。

  • .cargo/config.toml

    设置 build/target-dir 以共享 target 目录

  • template-cargo-lock.toml

    这是用于cargo compete newCargo.lock模板。只有当你回答Do you use crates on AtCoder?问题为“2 Yes”时才会生成。如果生成了此文件,将其文件路径添加到compete.toml中的new.template.lockfile

Screenshot

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

Record

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生成的包。

Screenshot

使用--open选项,您可以下载系统测试用例而不是示例测试用例。

对于AtCoder,我们必须使用Dropbox API。以某种方式生成具有以下两个权限的访问令牌,

  • 文件.元数据.读取
  • 共享.读取

并将JSON文件保存为以下格式到{本地数据目录}/cargo-compete/tokens/dropbox.json。(我在想更好的方法)

{
  "access_token": "<access token>"
}

asciicast

cargocompete retrieve submission-summaries

检索您的提交,并以JSON格式输出。

这是一个包的命令。转到使用cargo compete new生成的包。

asciicast

例如,您可以通过添加| 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生成的包。

asciicast

您可以通过设置 submit 来使用 cargo-equipcargo-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.tomlpackage.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_errorrelative_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) 进行 downloadsubmit

[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" }

Video

与 cargo-atcoder 的比较

请参阅 日语说明中的部分

许可

双许可下 MITApache-2.0

依赖

~39–55MB
~1M SLoC