Castle Wall in the browser with a five-rung solver. A clue has two
halves: a number and arrow giving the total length of the loop's segments
in that direction, and a colour saying whether the clue cell itself ends
up inside the loop (white) or outside (black). They look like they
ought to overlap. They cannot. The segments an eastward arrow counts are the
horizontal edges of that row — they lie along the ray, collinear with it,
and a ray that runs along a piece of curve never crosses it. Nudge the ray
down by epsilon and the only loop edges it can meet are vertical; by the
Jordan curve theorem the parity of that count is the inside/outside bit.
So the arrow counts the edges the ray runs along, and the colour is the parity
of the edges the ray runs across. Two disjoint sets. Measured across all 9,349
cycles of a 5×5 grid, the mutual information between colour and number is
0.0051 bits, against a control of 0.2808 bits — the colour's whole
entropy. The naive "odd number means inside" scores 68.4%, but always saying
"outside" scores 80.9%: reading the parity is worse than not reading it.
The corollary is that one colour clue is four parity constraints, and that
even with no clues at all a closed curve crosses any straight line an even
number of times, so every row gap and column gap carries a free one. Exact
cycle counts from a plug DP match OEIS A140517 on all ten grids from 2×2
to 11×11. A uniformly drawn cycle covers 74.2% of an 8×8 board, which
leaves nowhere to put walls, so the generator tilts the measure — exactly,
in bigints. Even a board carrying every clue it possibly could is unique only
50.3% of the time on 5×5. Erase every number from the shipped boards and
0 of 64 survive; erase every colour and 19 of 24 survive at 6×6 but only
2 of 16 at 10×10. 64 boards, 44 tests. Solver-backed puzzle #69.
Demo: https://sen.ltd/portfolio/castle-wall/
Repo: https://github.com/sen-ltd/castle-wall
The rules
Read from the primary source before writing a line (The Art of Puzzles' rules page):
- Draw a single closed loop through the centres of the empty cells. It never crosses itself and it never enters a clue cell.
- A clue's number and arrow give the total length of the loop's segments in that direction — equivalently, the number of cell borders the loop crosses if you walk out of the cell that way.
- A clue's colour says where the clue cell itself ends up: white is inside the loop, black is outside, grey says nothing and is simply a wall.
A shipped 8×8 board, with the answer next to it:
the board the answer
B1↓ . . . . G . . # ┌───┐ ┌───┐ # · ·
. . . . . . . B2← │ │ │ │
G . . . G W1↓ . B1← · │ │ │ └───────┐ #
. . . . . W2← . G │ │ │ │
. . W2→ . . . . . # │ └───┘ # # │ #
B1→ . . . . . . . │ │
B1→ . . . G . . . ┌───┘ · ┌───┐ # │ #
. B5↑ . . . . . . │ │ │ │
└───┐ # │ └───┐ └───┐
│ │ │ │
# │ · │ · └───┐ │
│ │ │ │
# └───┐ │ # · │ │
│ │ │ │
· # └───┘ · · └───┘
W is white (the wall finishes inside the loop), B is black (outside), G is a grey wall that says nothing. 14 walls — 9 coloured, 9 numbered — one loop of 40 segments, exactly one answer.
The number and the colour never talk about the same edges
Sixty-eight puzzles into this series, this is why I picked Castle Wall: a clue has two halves that look like they overlap, and geometrically they cannot.
Walk east out of the clue cell at (r,c). The segments the arrow counts are the horizontal edges of row r. The ray runs along the row's centre line, so those edges are collinear with the ray. A ray that runs along a piece of curve does not cross it. Therefore the arrow's number says nothing at all about which side of the loop the cell is on.
Now nudge the ray down by a hair. The only loop edges it can meet are the vertical edges spanning rows r and r+1, and by the Jordan curve theorem the parity of that count is exactly the inside/outside bit.
arrow = a count of the edges the ray runs ALONG
colour = the parity of the edges the ray runs ACROSS
Two disjoint edge sets. Neither half can be computed from the other.
That is a claim, so it gets measured. Over every cycle of a grid, for every cell the loop misses and each of the four directions, record the number an arrow would print and the colour the cell would get, then take the mutual information — pooled per (cell, direction) so that no correlation can sneak in from the cell's position.
| grid | (cell, dir) pairs | samples | P(inside) | guess from number parity | always say "outside" | I(colour ; number) | worst pair | I(colour ; across parity) | H(colour) |
|---|---|---|---|---|---|---|---|---|---|
| 4 × 4 | 64 | 4,464 | 10.0% | 74.0% | 90.0% | 0.0023 bits | 0.0187 bits | 0.2333 bits | 0.2333 bits |
| 5 × 5 | 100 | 281,812 | 19.1% | 68.4% | 80.9% | 0.0051 bits | 0.0336 bits | 0.2808 bits | 0.2808 bits |
The second-to-last column is the control. Run the identical measurement against the parity of the across ray — the edge set that defines the colour — and the colour's whole entropy comes back (0.2808 = 0.2808). The instrument is not broken. It is not broken, and it still reads five thousandths of a bit against the number.
There is a trap worth naming. "The number is odd exactly when the wall is inside" scores 68.4% on a 5×5 board, which sounds respectable, until you notice that always answering "outside" scores 80.9%. Reading the parity of the number is worse than not reading it.
One colour clue is four parity constraints
The same argument runs in all four directions, so a single colour is four parity constraints all asserting the same bit:
west {vEdge(rb, c') : c' < c} east {vEdge(rb, c') : c' > c}
north {hEdge(r', cb) : r' < r} south {hEdge(r', cb) : r' > r}
(rb/cb are the row and column the epsilon-nudge lands in; at the board's edge you nudge the other way and the argument is unchanged.)
And with no clues at all, a closed curve crosses any straight line an even number of times, so every row gap and every column gap carries a free parity constraint. Those two facts together are the parity rung.
Counting the loops, exactly
An answer here is a simple cycle of the grid graph that misses the walls, so before any clue is read the question is how many cycles a grid has. A connectivity-profile ("plug") DP answers it: sweep the cells in reading order carrying a frontier of w+1 plugs, remember which is paired with which, canonicalise the pairing by first appearance.
Two things are not in the textbook version:
- Cells may be skipped. A Hamiltonian-cycle DP forces every cell onto the loop; this loop wanders, so "this cell is not on the loop" is a legal move — and with it the DP counts all simple cycles.
-
Inside/outside costs one bit. Sweeping left to right along row
r, carry the running parity of the vertical edges already laid down in that row. At cell(r,c)that bit is the answer to "is(r,c)inside the loop" — it is the west parity ray, evaluated incrementally. Reset it at each row start.
The square grids have a published answer to check against, OEIS A140517:
| grid | cycles | matches A140517 | frontier states | time |
|---|---|---|---|---|
| 2 × 2 | 1 | yes | 7 | 1 ms |
| 3 × 3 | 13 | yes | 41 | 1 ms |
| 4 × 4 | 213 | yes | 199 | 0 ms |
| 5 × 5 | 9,349 | yes | 800 | 1 ms |
| 6 × 6 | 1,222,363 | yes | 3,236 | 5 ms |
| 7 × 7 | 487,150,371 | yes | 11,712 | 13 ms |
| 8 × 8 | 603,841,648,931 | yes | 42,562 | 41 ms |
| 9 × 9 | 2,318,527,339,461,265 | yes | 145,962 | 154 ms |
| 10 × 10 | 27,359,264,067,916,806,101 | yes | 499,441 | 764 ms |
| 11 × 11 | 988,808,811,046,283,595,068,099 | yes | 1,657,823 | 3.2 s |
All ten match. The rectangles have no OEIS entry, so 22 of them are checked against a depth-first enumeration sharing no code with the sweep.
A loop drawn at random is too long to be a puzzle
Walls go where the loop is not, so a long loop is a board with few walls. Split the same sweep by length and you get the density the generator is fighting:
| grid | cycles | mean loop length | coverage | most common length |
|---|---|---|---|---|
| 4 × 4 | 213 | 10.76 | 67.3% | 12 |
| 5 × 5 | 9,349 | 17.46 | 69.9% | 18 |
| 6 × 6 | 1,222,363 | 25.77 | 71.6% | 26 |
| 7 × 7 | 487,150,371 | 35.81 | 73.1% | 36 |
| 8 × 8 | 603,841,648,931 | 47.48 | 74.2% | 48 |
Coverage goes up with the grid. That is the wrong direction entirely: on an 8×8 board a uniform cycle sits on 47.5 of the 64 cells, leaving sixteen for walls.
So do not sample uniformly — tilt. Give every edge the loop leaves alone a weight of skip and every edge it takes a weight of take, so a loop of length L weighs skip^(E-L) * take^L. Keep both as bigints and the tilted counts stay exact.
| grid | skip / take | mean loop length | coverage |
|---|---|---|---|
| 8 × 8 | 1 / 1 | 47.48 | 74.2% |
| 8 × 8 | 9 / 8 | 44.55 | 69.6% |
| 8 × 8 | 5 / 4 | 41.43 | 64.7% |
| 8 × 8 | 4 / 3 | 39.27 | 61.4% |
| 8 × 8 | 3 / 2 | 34.81 | 54.4% |
| 8 × 8 | 2 / 1 | 14.54 | 22.7% |
The ratio is sharp: between 1 and 2 the coverage falls from 74.2% to 22.7%, and every board worth generating lives in that sliver. The shipped boards use 3/2. Reporting the three points separately, because a uniform sampler does not make the shipped boards uniform:
| grid | uniform coverage | tilted sampler | shipped boards | walls per board |
|---|---|---|---|---|
| 6x6 | 71.6% | 49.8% | 45.6% | 6.4 |
| 8x8 | 74.2% | 54.9% | 53.8% | 11.5 |
| 10x10 | — | 57.3% | 54.9% | 16.3 |
Even a board that says everything it can is unique only half the time
Before minimising anything, measure the genre's ceiling: hand every cell the loop misses a colour and its longest arrow — more than any legal board would ever print — and count the answers.
| grid | cycles | most walls a loop leaves | max-information boards with one answer | rate |
|---|---|---|---|---|
| 2 × 2 | 1 | 0 | 1 | 100.0% |
| 2 × 3 | 3 | 2 | 2 | 66.7% |
| 3 × 3 | 13 | 5 | 9 | 69.2% |
| 3 × 4 | 40 | 8 | 30 | 75.0% |
| 4 × 4 | 213 | 12 | 139 | 65.3% |
| 3 × 5 | 108 | 11 | 78 | 72.2% |
| 4 × 5 | 1,049 | 16 | 559 | 53.3% |
| 3 × 6 | 275 | 14 | 175 | 63.6% |
| 5 × 5 | 9,349 | 21 | 4,702 | 50.3% |
Every cycle, not a sample. The rate falls as the grid grows and it is already at a half. Half of all loops cannot be pinned down by any set of clues at all — not because the clues are weak, but because the cells the loop leaves behind are not enough to carry them. That ceiling is what sets the floor on how often the generator has to redraw.
(The tiny grids at the top are degenerate and worth naming as such: 2×2 has one cycle and no spare cell to put a wall on, so its "max-information board" is a blank grid that happens to have one answer.)
Erase the numbers and nothing survives; erase the colours and most small boards do
The two halves are independent. They are not worth the same.
| grid | boards | walls | coloured | numbered | colours erased: still unique | median answers | numbers erased: still unique | median answers | walls only: median answers |
|---|---|---|---|---|---|---|---|---|---|
| 6x6 | 24 | 154 | 123 | 122 | 19 / 24 | 1 | 0 / 24 | ≥ 500 | ≥ 500 |
| 8x8 | 24 | 275 | 213 | 209 | 12 / 24 | 1.5 | 0 / 24 | ≥ 500 | ≥ 500 |
| 10x10 | 16 | 261 | 208 | 205 | 2 / 16 | 14.5 | 0 / 16 | ≥ 500 | ≥ 500 |
Rub out every number and 0 of 64 boards keep a single answer; the count runs straight past the 500-answer cap the search stops at. Rub out every colour and 19 of 24 survive at 6×6, but only 2 of 16 at 10×10.
That is the shape the geometry predicts. A number is a count on a ray whose length grows with the grid; a colour is one bit however big the board is. The bigger the board, the more the arrows are already saying — and yet the further apart the answers sit. Which is why the colour stops being decorative exactly when the search starts to hurt.
The ladder, measured both ways
Five rungs, weakest first:
-
degree— a wall takes no gaps; every other cell takes two or none. -
arrow— each number as an interval on its ray. -
parity— each colour as four parity constraints, plus the free even-crossing law on every row gap and column gap. -
loop— one loop: a gap that would close a short circuit while another fragment is alive is unusable, and a fragment that can no longer reach the rest is dead. -
probe— assume a gap, run the cheap rungs, drop the assumption if the board dies.
Going up the ladder, the share of the answer's gaps that propagation alone settles from an empty board:
| grid | degree |
arrow |
parity |
loop |
probe |
|---|---|---|---|---|---|
| 6x6 | 37.5% | 48.3% | 52.5% | 52.5% | 100.0% |
| 8x8 | 34.8% | 45.5% | 56.3% | 58.0% | 100.0% |
| 10x10 | 31.1% | 35.8% | 41.4% | 41.4% | 48.1% |
Taking one rung out of the full ladder:
| grid | full − arrow
|
full − parity
|
full − loop
|
full ladder |
|---|---|---|---|---|
| 6x6 | 39.2% | 100.0% | 70.8% | 100.0% |
| 8x8 | 39.7% | 57.6% | 63.4% | 100.0% |
| 10x10 | 35.6% | 45.0% | 44.7% | 48.1% |
The leave-one-out table is where the colour earns its keep. At 6×6, removing parity costs 0.0 points — probing puts back everything the colours were saying. By 10×10 it costs 3.1 points, and removing arrow costs 12.5. Same crossover as the clue-half ablation, seen from the other side.
Read as pruning:
| grid | median nodes, degree
|
arrow |
parity |
loop |
probe |
|---|---|---|---|---|---|
| 6x6 | 5,729 | 27 | 17 | 11 | 1 |
| 8x8 | ≥ 400,001 | 270 | 62 | 27 | 1 |
| 10x10 | ≥ 400,001 | 44,117 | 5,325 | 917 | 18 |
A search that knows only degree burns its 400,000-node budget on all 24 boards at 8×8 and all 16 at 10×10 (≥ marks a median whose own board ran out of budget, so the true figure is larger). Each rung above takes roughly an order of magnitude off.
The dial has a fork in it
Minimisation here is not "which cells carry a clue". The clue cells are walls either way, and a wall blocks the loop whether or not it says anything. What comes off is how much each wall tells you:
full (colour and number) → colour (the bit alone) / arrow (the number alone, wall grey)
→ wall (a grey blank) → none (hand the cell back to the loop)
Weakening only ever admits more answers, so the greedy pass has a fixed point and reaching it is the whole minimisation. But the two middle levels are incomparable — which is the genre's own claim restated — so the dial forks rather than chaining.
The shipped boards take the chain none → wall → colour → full, the way the genre prints a clue: a wall that keeps its number keeps its colour. Running the same seeds down the full fork answers what that costs:
| grid | seeds | clues on the chain | clues on the fork | chain levels | fork levels |
|---|---|---|---|---|---|
| 6x6 | 24 | 6.4 | 6.4 | full 119, wall 32, colour 3 | arrow 114, wall 32, full 5, colour 3 |
| 8x8 | 24 | 11.2 | 11.3 | wall 45, full 219, colour 5 | wall 46, arrow 209, full 11, colour 5 |
The answer is nothing either way: 6.42 clues a board against 6.42 at 6×6, 11.21 against 11.29 at 8×8. The fork does not shrink a single board. What it does is strip the colours — 114 of 6×6's 119 numbered walls turn grey, and 209 of 8×8's 220 — because a number that survives on its own always prefers to and the greedy takes the first level that works. Colours are free to keep and free to state, so the chain is the right branch.
Implementation notes
src/castlewall.ts rules, the rays, the five rungs, the search
src/count.ts the plug DP: exact cycle counts, the inside bit, the tilted sampler
src/generate.ts draw a loop, wall the rest, turn every wall down as far as it goes
src/main.ts the page
tools/*.mts run the censuses, build the bank, measure, regenerate the prose
TypeScript, no runtime dependencies. npm run notes folds counts.json and stats.json back into the README and the page, so no number in either — including every table in this article — was typed in by hand.
The inside bit is checked by making the DP audit itself: for each cell of a 5×5 grid, count the cycles that miss it and enclose it, once by enumerating all 9,349 cycles and once through the plug DP's parity bit. They agree on all 25 cells, and that agreement is a test. 44 tests total.
Takeaway
I picked Castle Wall because a clue has two halves that look like they overlap and geometrically cannot. The arrow counts the edges the ray runs along; the colour is the parity of the edges the ray runs across. The proof is one epsilon-nudge; the measurement is 0.0051 bits over every cycle of a 5×5 grid.
And "independent" does not mean "equally valuable". Erase the numbers and all 64 boards collapse; erase the colours and the small ones barely notice. The colour starts mattering only as the board grows — and the same crossover shows up in the ladder's leave-one-out (0.0 points at 6×6, 3.1 at 10×10) and in the clue-half ablation (19/24 down to 2/16). What one bit is worth depends on how big the board is.
Solver-backed puzzle #69.

Top comments (0)