Understanding contest.nix
contest.nix defines one contest.
A Minimal Example
Minimal example:
{
hull,
...
}:
{
# Basic metadata for the contest
name = "myFirstContest";
displayName.en = "my first contest";
# A list of paths to the problems included in this contest.
# Hull will evaluate the problem definition in each of these directories.
problems = [
./problems/aPlusB
./problems/anotherProblem
];
# Defines how to package the final contest.
targets = {
# The 'default' target is the one built by `hull build-contest`.
default = hull.contestTarget.common {
# This tells the contest target to find and use the 'default'
# target from each individual problem's `problem.nix` file.
problemTarget = "default";
};
};
}Core Options
Let’s break down the essential options available in contest.nix.
Basic Metadata
These options define the fundamental properties of your contest.
name: A unique, machine-readable identifier for the contest (e.g.,day1,finalRound). It should be a simple string without spaces or special characters and is used for internal references.displayName: An attribute set containing human-readable titles for the contest in different languages. The keys are language codes (e.g.,en,zh).
Defining Problems
This is the most important part of the file, where you specify which problems are part of the contest.
problems: A list of problems.
{
problems = [
../problems/aPlusB # Path to the 'aPlusB' problem directory
../problems/hello # Path to the 'hello' problem directory
];
}Defining Targets
Similar to problem.nix, the targets attribute set defines different packaging formats for the contest. A contest target specifies how to structure the final output directory, combining the outputs of all included problems.
targets: An attribute set where each attribute defines a packaging target. Thedefaulttarget is special, as it’s the one built by thehull build-contestcommand without additional arguments and is evaluated after runtime analysis for each problem. Hull provides built-in contest targets likecommon,lemonandcnoiParticipant.
Building the Contest
Once your contest.nix is configured, you can build the entire package using the hull build-contest command.
Prerequisite: This command must be run from within the Nix development shell (nix develop).
hull build-contestBy default, this command looks for a default contest defined in your flake.nix (which usually points to ./contest.nix) and builds its default target. If you have multiple contests or targets, you can specify them with flags:
# Build the 'day1' contest using its 'lemon' target
hull build-contest --contest day1 --target lemonUpon successful completion, Hull creates a result symbolic link in your project directory. The structure of this output depends on the target used. For the hull.contestTarget.common target shown in the example, the output would look like this:
result/
├── aPlusB/
│ ├── data/
│ ├── solution/
│ ├── overview.pdf
│ └── ... (contents of the 'default' target for the aPlusB problem)
└── anotherProblem/
├── data/
├── solution/
├── overview.pdf
└── ... (contents of the 'default' target for the anotherProblem)Relationship Between Contest and Problem Targets
Contest targets often collect outputs of problem targets.
Consider the hull.contestTarget.common target. It takes an argument named problemTarget.
targets.default = hull.contestTarget.common {
problemTarget = "default";
};When you run hull build-contest, the following happens:
- Hull loads the contest metadata and resolves the list of problems in the contest.
- It analyzes each problem through the Rust runtime, including validator checks, official output generation, and solution judging.
- It injects the analyzed runtime data into each problem configuration.
- It builds the selected problem target for every problem.
- It evaluates the contest target and combines the packaged problem outputs into the final contest directory.
Use -j / --jobs to control how many problems Hull analyzes in parallel. Arguments after -- are forwarded to the final nix build, so debugging flags like --show-trace remain available.
Contest packaging is composed from problem targets.