atcoder-crystal-workspace

Version, currently main branch1 version
  • main branchlatestJul 31, 2026

github.com/ReiAkidzuki/atcoder-crystal-workspace

AtCoder Crystal 1.17.0 workspace with testing, bundling, random tests, and AI contest safeguards

0 stars
0 dependents
License: MIT

Installation

# Add this to your shard.yml
dependencies:
  atcoder-crystal-workspace:
    github: ReiAkidzuki/atcoder-crystal-workspace
    branch: main

main is a branch, not a release, so this tracks it rather than pinning a version.

Then run:

shards install

shard.yml

Crystal
1.17.0
License
MIT

Dependencies

Runtime Dependencies

  • gsl*github: konovod/crystal-gsl, commit: b1fc1b0
  • atcoder*github: hakatashi/ac-library.cr, commit: c57c18d
  • avltree0.1.2github: ngng628/avltree
  • graphlb0.1.0github: mettuaditya/graphlb
  • immutable0.1.24github: lucaong/immutable

README

AtCoder Crystal workspace

English | 日本語

This workspace targets AtCoder's Crystal 1.17.0 environment. It is a companion to AtCoder Ruby workspace for problems whose time limits are difficult to meet in Ruby, while keeping the same commands and layout. Solutions and custom libraries remain separate during development and are bundled into one submission.cr for execution and submission.

Why this is a separate workspace

This is maintained as an independent GitHub template instead of being merged into the Ruby workspace. Crystal needs its own compiler, Shards dependencies, native libraries, and build cache; keeping those concerns separate makes setup and CI easier to understand. The contest, tasks, new, test, run, random, bundle, and submit commands deliberately match the Ruby workspace.

You can copy downloaded metadata and tests from a Ruby workspace one task at a time without overwriting a solution:

make import-task FROM=../atcoder-ruby-workspace TARGET=abc468/a

This copies .problem-url, .contest.json when available, test/*.in, test/*.out, and .samples-complete, then creates a fresh main.cr. It neither converts nor copies Ruby solutions, custom libraries, or random-test programs. If source and destination data conflict, it stops without overwriting the existing files.

Start from GitHub

Choose “Use this template” and then “Create a new repository” on GitHub. A repository made from the template has independent history, so a fork is unnecessary unless you specifically want the fork relationship.

To share solutions and custom libraries across computers, create one repository from the template and clone that same repository on each computer. Cookies and contest locks are not committed, so configure them separately on every device.

Generative AI during live contests

AtCoder's rules against generative AI apply to ongoing ABCs, ARCs of every division, and AGCs, including Unrated participation. AHCs have separate rules. Rules can change, so check the current official version before every contest.

This repository uses a stricter fail-closed policy for general-purpose coding agents to reduce accidental use. During a covered contest, do not use generative AI for problem summaries, algorithms, code, language conversion, code completion, compiler errors, or debugging.

Device-wide contest lock

Before participating in a covered contest, lock AI assistance and open VS Code without extensions:

make contest-lock CONTEST=abc469
make vscode-safe

contest-lock creates two markers:

  • .atcoder-contest-lock in this repository
  • ${XDG_STATE_HOME:-$HOME/.local/state}/atcoder-workspace/contest-lock for the device

The device-wide marker lets a lock created from the Crystal workspace also block agents in the Ruby workspace on that computer. If you override its location with ATCODER_GLOBAL_LOCK_FILE, configure the same absolute path in both workspaces. As a rule, unlock from the same workspace in which you created the lock.

The existence of either marker is authoritative, even if its contents are invalid. Locks never expire automatically. After verifying on the official site that the contest has ended, the user must unlock the workspace:

make contest-unlock

Check both manual lock scopes without network access:

make contest-status

Target-specific automatic check

Compatible agents are instructed to run status and a target-specific check before contest-related work. You can also run these checks manually:

make contest-check CONTEST=abc469
bin/contest-guard check --contest abc469 abc469/a
bin/contest-guard check abc469/a

The guard compares the official contest page with AtCoder's server time. For ABC, ARC, and AGC it blocks from five minutes before the listed start through twenty minutes after the listed end. It also fails closed when the contest is live, the network fails, the page format changes, metadata conflicts, or the result is indeterminate. AHC and other contest types are never automatically cleared because their rules differ. The check only knows about its specified target and cannot detect your participation in another live contest, so it does not replace the official page or the manual lock.

Disable AI in VS Code

.vscode/settings.json disables built-in AI, GitHub Copilot, and inline suggestions in this workspace. make vscode-safe opens a new window with code --new-window --disable-extensions, which disables every extension in that window.

These controls reduce accidental use but cannot disable AI in another editor, browser, CLI, desktop app, or already-open window. Before a contest begins, verify every tool you might use.

Installation

This workspace targets macOS and Debian/Ubuntu-based Linux. On Windows, use Ubuntu under WSL.

Install these prerequisites:

  • Git
  • Python 3.10 or newer
  • uv
  • Crystal 1.17.0, or asdf capable of installing it
  • Homebrew and Xcode Command Line Tools on macOS when setup should install native dependencies

After cloning the repository, run:

make setup
make doctor
make self-test

make setup verifies Crystal 1.17.0 from .tool-versions and installs it through asdf when necessary. It then prepares GSL, the pinned Shards dependencies, online-judge-tools (oj) for sample tests, and the aclogin login helper. It follows Brewfile on macOS and uses libatlas-base-dev, libgsl-dev, and pkg-config on Debian/Ubuntu. On CI images where native packages are already present, use bin/setup --skip-system-dependencies.

make doctor checks the exact Crystal version, Shards, GSL, oj, aclogin, dependency consistency, and an AtCoder-compatible release build that requires every provided shard. make self-test runs the workspace's regression tests in temporary directories.

AtCoder Crystal 1.17.0 environment

This repository follows AtCoder's available languages and libraries for Crystal 1.17.0. The nonstandard libraries provided by AtCoder are pinned through shard.yml and shard.lock.

AtCoder libraryWorkspace requireVersion
ac-library_crrequire "atcoder"0.1.0 / commit c57c18d
avltreerequire "avltree"0.1.2
graphlbrequire "graphlb"0.1.0
crystal-gslrequire "gsl"0.2.0 / commit b1fc1b0
immutablerequire "immutable"0.1.24

The default prelude for ABCs, ARCs, and AGCs loads only atcoder and avltree. This makes AtCoder::DSU, priority queues, Fenwick trees, segment trees, lazy segment trees, ModInt, flows, SCC, 2-SAT, prime and string algorithms, plus AVLTree::SortedSet, SortedMap, and SortedMultiset available without more require statements. Crystal's own prelude already includes Set, Deque, Random, and basic Math.

graphlb, gsl, and immutable remain opt-in because their use cases are more specialized. Add an explicit require in the solution or a custom library when needed. They are already installed by make setup, so enabling one later needs no additional setup. In particular, gsl is not loaded into solutions that do not need its native linkage.

AtCoder builds a Shards project containing main/src/main.cr. This workspace instead bundles CONTEST/TASK/main.cr and custom libraries into one temporary source, then compiles it against the pinned Shards at the repository root. AtCoder receives the resulting submission.cr as ordinary Crystal source.

Submission builds use --release --no-debug --no-color -Donline_judge, matching the relevant AtCoder release settings. By default, local test and run omit release optimization to reduce compile time. Add --release for a production-style check:

bin/atcoder test abc468/a --release
bin/atcoder run abc468/a input.txt --release

submit always tests the exact bundled source and executable from a release build. The official command's --quiet option is deliberately omitted locally so compiler diagnostics remain visible.

Browser login and the optional oj cookie

AtCoder protects source submissions with CAPTCHA, so this workspace does not perform the final submission through a raw HTTP request. When you run submit while logged in to AtCoder in your regular browser, it copies the validated submission.cr to the clipboard and opens the task's submission page. Confirm the task and language, complete the human verification, and submit in the browser.

Normal browser submission, public task listing, problem scaffolding, sample download, and local testing do not require make login. Only when an authenticated, read-only oj operation needs its own session, copy the REVEL_SESSION cookie value from your browser and run:

make login

The cookie is stored in oj's user-data directory, never in this repository. Do not put cookie values in source files, commits, or chats.

Usage

List every task in a contest:

bin/atcoder tasks abc468

Create main.cr files and download samples for the entire contest:

bin/atcoder contest abc468

To create one task, provide a contest ID and task label or a task URL:

bin/atcoder new abc468 a
bin/atcoder new https://atcoder.jp/contests/abc001/tasks/abc001_1

The resulting layout is:

abc468/
├── .contest.json
├── a/
│   ├── .problem-url
│   ├── main.cr
│   └── test/
│       ├── .samples-complete
│       ├── sample-1.in
│       └── sample-1.out
├── b/
└── ...

.samples-complete is an automatically managed marker for a complete sample download.

After writing a solution, use test for official samples and manual cases, or run with standard input. Both commands compile the bundled solution only once:

bin/atcoder test abc468/a
bin/atcoder run abc468/a
bin/atcoder run abc468/a input.txt

The equivalent Make targets are:

make test TARGET=abc468/a
make run TARGET=abc468/a INPUT=input.txt

Custom libraries

Place custom .cr files under library/. Subdirectories are supported. library/00_core/00_contest_dependencies.cr is bundled first, followed by every other library/**/*.cr file in lexicographic order by its complete path relative to library/.

library/
├── 00_core/
│   ├── 00_contest_dependencies.cr
│   └── input.cr
├── 10_data_structure/
│   └── fenwick_tree.cr
└── 20_graph/
    └── dijkstra.cr

Dependencies are not analyzed automatically. When dependencies cross directory boundaries, add numeric prefixes to the directory names as shown above. Rename a work-in-progress file to something such as .cr.disabled to exclude it. Names beginning with a dot are also excluded. Symbolic links are not allowed anywhere below library/.

New main.cr files load library.cr when compiled directly. test, run, random, bundle, and submit remove that marked local loader and place the latest libraries before main.cr. They never rewrite the original main.cr. During random tests, libraries are bundled only with the solution; the generator and oracle remain independent.

00_core/00_contest_dependencies.cr is bundled first and loads the pinned atcoder and avltree shards. Later custom libraries can therefore use types from both shards directly. The random-test generator and oracle do not receive this prelude, keeping all three programs from becoming unnecessarily heavy.

When compiling main.cr without a workspace command, invoke Crystal from the repository root so it can resolve the pinned shards:

crystal build abc468/a/main.cr

The regular bin/atcoder test, run, bundle, and submit commands already use the correct working directory.

Libraries may use normal require statements for the standard library or a pinned shard. Do not use require "./..." or require "../..." to load another custom file, because that path will not exist after single-file bundling. See library/README.md for the complete bundling notes in Japanese.

Check only the custom library:

bin/atcoder check-library

Manual test cases

Add existing input and expected-output files to the regular test suite:

bin/atcoder add-case abc468/a custom-1 input.txt expected.txt
# or
make add-case TARGET=abc468/a NAME=custom-1 INPUT=input.txt EXPECTED=expected.txt

This creates abc468/a/test/custom-1.in and custom-1.out. Existing cases are never overwritten.

Random tests

Create a generator and a small-input reference solution:

bin/atcoder init-random abc468/a

Edit random/generator.cr to accept a seed as its first argument and print one input. Edit random/oracle.cr to read that input from standard input and print the expected output. The solution, generator, and oracle are each compiled once at startup:

bin/atcoder random abc468/a 1000 1
# or
make random TARGET=abc468/a COUNT=1000 SEED=1

On a mismatch, timeout, or abnormal exit, reproduction input and metadata are saved below random/failures/. Seeds must fit Crystal's UInt64 range (0..18446744073709551615). Each process has a 10-second timeout and a combined 16 MiB output limit by default; ATCODER_RANDOM_TIMEOUT changes only the timeout.

Bundling and submission

Create one manually submittable file at abc468/a/submission.cr:

bin/atcoder bundle abc468/a
# or
make bundle TARGET=abc468/a

submission.cr is excluded from Git. On repeated runs, the command updates only files carrying its generated marker and refuses to overwrite a hand-written file with the same name. Edit main.cr or library/, not generated output.

Prepare a submission with:

make submit TARGET=abc468/a

Only after bundling, a release build, and all tests succeed does it save submission.cr and hand it to the clipboard and browser. The command itself does not submit to AtCoder.

Pulling template updates

Repositories created from a GitHub template do not receive source-template updates automatically. Commit every local change so the worktree is clean, then run:

make update-template

On first use, it adds a template remote for the public source repository. It uses .atcoder-template-version to cherry-pick newer template commits in order, preserving solution and library commits and never pushing automatically. A conflicting local customization stops as a normal cherry-pick conflict:

# After resolving conflicts
git add <files>
git cherry-pick --continue

# To cancel the entire update
git cherry-pick --abort

Revalidate after an update:

make setup
make doctor
make self-test

When publishing this source template, advance .atcoder-template-version to a new unique value in the final commit of each release batch. Do not amend or force-push published release commits.