A board is a simple thing, 256 tiles, each with four coloured edges, each
placed at a cell and a rotation, but the community has written it down a dozen
ways over nineteen years, and the ways never quite line up. A letter string, a
digit string, a URL, a CSV, a JSON. They say the same thing in different
alphabets, and the moment you move a board between two tools you hit the seam.
This page is the seam, written down: every format a board or puzzle travels in
here, with the byte-level rules, including the one detail that bites everyone,
how each format encodes the grey border, and, for each, a plain note on
what it can and cannot recover. If you only take one thing away: paste any board
into the format converter and read the others straight back.
One input, one output
The IO contract is symmetric and small. In: one puzzle instance as JSON
(the site Puzzle schema, below); every algorithm is invoked with
--puzzle <file>.json. Out: one board document as JSON (the BoardDoc,
below), carrying a ready-to-open eternity2.dev URL as a field. That
is the whole thing: puzzle-JSON in, board-JSON out, both single self-describing
files. Everything else on this page is either an input the tools also accept
(CSV, a bare board_edges blob, a bucas link) or a derived format the
converter can hand you. There is no .url-here, .json-there,
two-files-sometimes split.
A colour is a small integer. 0 is the grey outer border; interior colours
run 1..=22 for the official puzzle (22 is exactly how many motifs exist). An
edge quad is a cell's four colours in URDL order (up, right, down, left),
reading the tile as placed and rotated, not as a catalogue tile. A cell is
either filled (a real quad) or empty; an empty cell is written as if it were all
border, [0, 0, 0, 0].
One fact follows from "as placed", and it is the source of most format
confusion: a board carries rotated edges, not a rotation number. But this is
not a loss. Eternity II pieces are all distinct up to rotation (the official
set is, and any faithful generator keeps it that way), so a cell's edge quad
identifies exactly one piece, and the rotation is the turn that maps that
piece's catalogue quad onto the placed one. Matching the quad against the piece
set recovers both the identity and the rotation.
So the edges are the whole board: they render it, score it, and name every
piece and its orientation. The only case where they fall short is a contrived
set with two pieces sharing an edge pattern up to rotation, which real Eternity
II never has, and there a piece-number channel disambiguates. That is the one
job board_pieces exists for.
The lingua franca. Four lowercase letters per cell, row by row, URDL, with
letter = 'a' + colour. So the border is a, interior colour 1 is b, up
to colour 22 = w. An empty cell is aaaa, indistinguishable from a real
all-border tile, which never happens on a legal board, so the ambiguity is
harmless. The official 16×16 board is 256 × 4 = 1024 letters.
adca beaa … cell 0 = [0,3,2,0], cell 1 = [1,4,0,0], …
- Border: the letter
a (colour 0).
- Recovers: everything about the board, the full rendering, the exact score,
and, because pieces are distinct up to rotation, each piece's identity and its
rotation by matching against the set.
- Cannot recover: which cells were given as clues rather than solved, that
is a property of the puzzle, not the board, and it travels in
hints.
A rare wrinkle: some tools permute which glyph each letter draws
(motifs_order). The orders marie and jblackwood are identical to each
other; jef is a different permutation. The converter and viewer translate
these back to the default alphabet on the way in, so you never have to think
about it, but if you see a board whose colours look scrambled, an untranslated
motifs_order is why.
A board and the clues it was built from belong in one place, addressed the same
way. hints lists the pinned clue cells, each as pos.rot, the row-major cell
index and clockwise quarter-turn, joined by -. Five official clues are about
thirty characters.
hints=34.1-45.2-135.0-210.3-221.0
The piece at each hinted cell is already known from board_edges, so a clue
needs only its position and orientation, never a piece id. This is the same
(cell, rotation) shape every durable format uses for a pinned tile: the CSV's
x,y,rotation, the site JSON's {pos, rot}.
- Recovers: which cells are clues, so the viewer can mark them and a solver
can start from them. Absent means "no clues", a plain solved or partial board.
- Pairs with:
board_edges. Together they carry a full puzzle-with-clues
in one link, which a bare board never could.
Some community tools, notably e2.bucas.name links, carry an explicit piece
channel: three decimal digits per cell, the 1-based piece number, 000 for
an empty cell (the official board is 256 × 3 = 768 digits). We read it when
it is present, but never need to emit it, because board_edges already names
every piece on a distinct-piece set.
001 005 007 … piece 1 at cell 0, piece 5 at cell 1, …
- Border / empty:
000.
- Recovers: piece identity directly (and rotation, matched against the set),
the same thing the edges recover on their own for a real board.
- On its own: useless without the edges; it is an overlay, not a board. Its
one irreplaceable use is a contrived set with pieces that repeat up to
rotation, where the edges alone are ambiguous.
The oldest interchange format, written down by the community in 2007 (see the
toolbox census). One line per filled cell, in
reading order, four whitespace-separated edge integers in URDL order.
0 3 2 0
1 4 0 0
…
- Border: the integer
0.
- Recovers: rendering and score, same as
board_edges; it is the same data
in decimal. It lists the pieces as placed and rotated, so it is not a
canonical rotation-0 catalogue, and a board alone cannot turn it back into one.
The format McGavin's C and Blackwood's C# consume, and the shape the benchmark's
variant_NN.csv files are written in. A size header, then one row per piece:
top,right,bottom,left followed optionally by x,y,rotation for a pinned hint.
16
1111111111111111,0000000000000001,0000000000000010,1111111111111111,0,0,0
…
Each colour is a 16-bit zero-padded binary word. And here is the detail that
trips everyone, and the reason this page exists:
The border is all ones in the CSV
In the puzzle CSV, the grey border is 1111111111111111, all ones, the
16-bit word 65535, not all zeros. Interior colours are their small integer
in binary, so colour 1 is 0000000000000001. A reader maps the 65535 word
back to interior id 0. This is the opposite of every other format on this
page, where the border is the low value (a, 0, 000). It is a legacy
sentinel choice, kept for byte-compatibility with the engines that read it.
- Border: the all-ones word
1111111111111111 (65535).
- Recovers: the full puzzle, pieces and hints. This is a puzzle format
(the tile set), not just a placed board.
The one format every algorithm is fed: --puzzle variant_NN.json. The site's
engine, the DFS/repair studies and the single-core benchmark all read the same
schema (byte-compatible with the web's Puzzle type), so every experiment runs
the same instances. It carries the piece set at rotation 0 and the pinned hints
explicitly, which is what makes it an input a solver can start from, rather than
a board it has already filled.
{
"name": "e2_official_variant00_pin3corners",
"width": 16, "height": 16, "numColors": 22,
"pieces": [[0,1,2,0], [0,0,3,1], …],
"hints": [{ "pos": 34, "piece": 118, "rot": 2 }, …]
}
- Border: colour
0, as an integer in the pieces quads.
- Recovers: everything about the instance: canonical rotation-0 tiles,
colour count, and every pinned clue with its exact rotation. This is the one
format that carries rotation and catalogue order by construction, because it
describes the puzzle, not a placement on it.
What every solver on this site now writes: one self-describing .json per
board. It folds the board, its score, its content hash, both letter strings, and
the viewer URL into a single document, so a downstream tool needs nothing else.
{
"name": "…",
"size": 16,
"score": 466,
"breaks": 14,
"board": [3, 16, 24, …],
"board_hash": 2059303548241384230,
"board_edges": "abda…",
"board_pieces": "001005…",
"url": "https://eternity2.dev/viewer?puzzle=…&puzzle_size=16&board_edges=…"
}
board is the row-major piece*4 + rot placement vector (-1 for an empty
cell), the same encoding the site's Puzzle round-trips through. breaks is
max_score − score (the unmatched interior edges; on a full board, the break
count). board_hash is an FNV-1a hash of the placement grid, the bit-identical
gate for "did these two runs produce the same board".
- Border: as in
board_edges (a) and board_pieces (000); the board
vector uses -1 for empty.
- Recovers: everything a board can: rendering, score, identity and rotation
(via
board_pieces and board), plus provenance (name, board_hash) and a
one-click view (url).
Two URLs, same board, two hosts.
eternity2.dev, the canonical link. The format every algorithm here emits.
The board rides entirely in board_edges; any pinned clues ride in hints.
Square boards, so a single puzzle_size (the viewer also reads bucas's
board_w/board_h), and every value stays in the URL-safe range so the link
needs no percent-encoding:
https://eternity2.dev/viewer?puzzle=NAME&puzzle_size=16&board_edges=…&hints=135.0-210.1
hints is omitted for a board with no clues. Because the edges carry piece
identity, there is no piece channel here: the board and its clues fit in these
two fields.
e2.bucas.name, the community viewer. Jef Bucas's original, the viewer whose
URL format became this whole vocabulary (the toolbox
tells that story). Fully supported as an input, and available as a derived
output using its board_w/board_h pair and a # fragment. We emit it
edges-only (bucas recovers the pieces from the edges for a distinct set), though
bucas links from other tools often also carry a board_pieces channel, which we
read on input:
https://e2.bucas.name/#puzzle=NAME&board_w=16&board_h=16&board_edges=…
The viewer reads either transparently; the converter
hands you both. The eternity2.dev form is canonical here only because it opens
this site's viewer, with its scoring, clue overlay and piece-set verification;
the bucas form remains the community's shared original, credited accordingly.
| Format | Border | Carries rotation? | Carries identity? | It is a… |
|---|
board_edges | a | yes (by match) | yes (by match) | placed board |
hints | n/a | yes (pos.rot) | via edges | clue set |
board_pieces | 000 | with edges | yes | overlay |
e2pieces.txt | 0 | yes (by match) | yes (by match) | placed board |
| Puzzle CSV | 1111…1 (all ones) | hints only | yes (tiles) | puzzle |
| Site JSON | 0 | yes | yes | puzzle |
BoardDoc JSON | a / 000 / -1 | yes | yes | placed board |
| eternity2.dev URL | a | yes (by match) | yes (by match) | link to a board |
| bucas URL | a | with pieces | with pieces | link to a board |
Every conversion in that table is one paste away in the
format converter: drop in a URL, a bare board_edges string, or a
params blob, and read back the eternity2.dev URL, the canonical JSON, the CSV,
board_pieces, e2pieces.txt, and the bucas URL, with a live preview and the
score, so you can see the file is right before you trust it.