Everything you need to start building an Eternity II solver, minus the solver
itself. The starter kit
is one folder in the repo: a small Rust workspace that already does the plumbing.
Scoring, board generation, batch generation with pinned clues, format conversion,
benchmarking, and a full solve → sweep → compare iteration loop are all there.
You write one Solver; the rest keeps working around it.
Nothing in the kit re-implements scoring, generation, or formats. Those come from
the same shared crates the site itself runs on, so a score from the kit is the
same number the viewer and every other engine produce: the one
canonical rim-excluding matched-edge count. Copy the folder, drop in your idea,
and iterate.
✨Set this up with your coding agent
Using Claude Code, Cursor, or another coding agent? Paste this in — it fetches the kit's setup instructions, builds it, and helps you write your first solver.
Follow the instructions from
https://raw.githubusercontent.com/raphael-anjou/eternity2/main/research/starter-kit/PROMPT.md
and ask me questions as needed.
No web access in your agent? Clone the repo and open research/starter-kit/AGENTS.md instead.
- Score and verify any board, from an
eternity2.dev / e2.bucas.name URL
or a bare board_edges blob, through the canonical scorer, and check it
against the real official piece set (all-distinct-pieces, clue compliance),
which the kit now ships.
- Generate boards with real Eternity-II colour balance: five border colours
confined to the frame, the interior balanced, every piece distinct, fully
deterministic per seed.
- Batch-generate ("give me 100 boards, these seeds, five clues pinned") as
reproducible site-schema JSON you can read straight back.
- Convert between every format the community uses:
board_edges,
board_pieces, e2pieces.txt, the eternity2.dev and legacy bucas URLs, and
CSV. See the format reference.
- Benchmark the plumbing single-core, so you know your solver's overhead
budget.
- The iteration loop: a stable
Solver trait, a sweep runner that writes
reproducible run directories, and a compare tool that diffs two runs, with
the variance discipline this puzzle demands baked in.
On Eternity II the score swings a lot from seed to seed: the standard deviation
across seeds is roughly 12 to 20 points for a whole-board solver. So a one- or
two-point difference in mean between two solver versions is almost always noise.
The kit's compare tool refuses to call a sub-noise difference a win, tells you
to sweep at least 40 seeds, and always reports the spread. Keep everything
single-core, as the site's benchmarks do, and your
numbers stay comparable to everyone else's.
The whole kit is built around one trait:
use e2_kit::{Board, Budget, Instance, SolveOutcome, Solver};
struct MySolver;
impl Solver for MySolver {
fn name(&self) -> String { "my-solver".into() }
fn solve(&mut self, instance: &Instance, start: &Board, budget: Budget) -> SolveOutcome {
let mut board = start.clone(); // `start` already carries any pinned clues
// ...your search here. Poll budget.expired().
SolveOutcome::complete(board) // or ::improved / ::exhausted / ::bound
}
}
Copy examples/my_solver.rs (a complete, working greedy baseline), replace the
body of solve, then sweep it:
cargo run --release --example sweep -- --n 40 --budget 3
cargo run --release --bin e2kit -- compare runs/<A> runs/<B>
Full recipes (scoring, generation, batch, convert, benchmark) are in the kit's
README.
Boards to test a solver against live in the CC0
dataset; the approaches to try are surveyed in the
map of every known approach.
The kit's generator, in the browser: the same WASM engine, no install. Pick a
shape and a seed range and it makes a reproducible batch; click any board to open
it in the viewer and score it edge by edge.
Want the same thing on the command line, or 10,000 boards with clues pinned? Use
the kit's generate_batch example: it writes each board as JSON you can feed
straight back to a solver.