DEV Community

SEN LLC
SEN LLC

Posted on

Castle Wall: the number on a clue can never tell you its colour

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

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↑  .   .   .   .   .   .     │           │   │       │
                                    └───┐   #   │   └───┐   └───┐
                                        │       │       │       │
                                    #   │   ·   │   ·   └───┐   │
                                        │       │           │   │
                                    #   └───┐   │   #   ·   │   │
                                            │   │           │   │
                                    ·   #   └───┘   ·   ·   └───┘
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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}
Enter fullscreen mode Exit fullscreen mode

(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:

  1. 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.
  2. 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)
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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)