<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: SEN LLC</title>
    <description>The latest articles on DEV Community by SEN LLC (@sendotltd).</description>
    <link>https://dev.to/sendotltd</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3871729%2F54856949-f27c-4da1-a1c3-3db40b93c8d8.png</url>
      <title>DEV Community: SEN LLC</title>
      <link>https://dev.to/sendotltd</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sendotltd"/>
    <language>en</language>
    <item>
      <title>Heteromino: when the clues are holes, local reasoning dies completely</title>
      <dc:creator>SEN LLC</dc:creator>
      <pubDate>Sun, 06 Sep 2026 00:39:36 +0000</pubDate>
      <link>https://dev.to/sendotltd/heteromino-when-the-clues-are-holes-local-reasoning-dies-completely-4gpk</link>
      <guid>https://dev.to/sendotltd/heteromino-when-the-clues-are-holes-local-reasoning-dies-completely-4gpk</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Heteromino&lt;/strong&gt; in the browser with a &lt;strong&gt;four-rung solver&lt;/strong&gt;. This puzzle has no&lt;br&gt;
numbers. No arrows, no region boundaries, no circles. The only thing a setter&lt;br&gt;
can hand you is &lt;strong&gt;which cells are black&lt;/strong&gt; — the clue language &lt;em&gt;is&lt;/em&gt; a subset of&lt;br&gt;
cells. Two things fell out of that. First, a black cell does &lt;strong&gt;two jobs at&lt;br&gt;
once&lt;/strong&gt;: it removes a cell from the tiling, and it stands &lt;em&gt;between&lt;/em&gt; pieces so&lt;br&gt;
that same-shaped neighbours become legal. 65 of the 72 shipped boards depend on&lt;br&gt;
the second job. Second, and more interesting: if nothing is written on the&lt;br&gt;
board then there is &lt;strong&gt;nothing to propagate from&lt;/strong&gt;. The bottom three rungs&lt;br&gt;
settle &lt;strong&gt;2.1%&lt;/strong&gt; of an untouched 8×8 and then stop. One level of lookahead takes&lt;br&gt;
it to &lt;strong&gt;100%&lt;/strong&gt;. Puzzle #56 in the solver series.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Demo: &lt;a href="https://sen.ltd/portfolio/heteromino/" rel="noopener noreferrer"&gt;https://sen.ltd/portfolio/heteromino/&lt;/a&gt;&lt;br&gt;
Repo: &lt;a href="https://github.com/sen-ltd/heteromino" rel="noopener noreferrer"&gt;https://github.com/sen-ltd/heteromino&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8d36iz7erlyfxto5ac66.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8d36iz7erlyfxto5ac66.png" alt="Heteromino" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Rules
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Cut every white cell of the board into &lt;strong&gt;trominoes&lt;/strong&gt; — three-cell pieces, so
either a straight &lt;strong&gt;bar&lt;/strong&gt; or an &lt;strong&gt;L&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Two pieces of the &lt;strong&gt;same shape&lt;/strong&gt; may not share an edge.&lt;/li&gt;
&lt;li&gt;"Shape" means shape &lt;strong&gt;as drawn&lt;/strong&gt;. Rotate an L a quarter turn and it counts as
a different piece, so there are &lt;strong&gt;six&lt;/strong&gt; shapes (2 bars + 4 Ls).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That is all of it. There is not a single number anywhere.&lt;/p&gt;

&lt;p&gt;Rule 3 — distinguishing rotations — is the hinge. Later I compare it against the&lt;br&gt;
LITS convention, which merges rotations. Spoiler: merging them leaves &lt;strong&gt;all 72&lt;br&gt;
shipped boards with no answer at all&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  For the first time in this series, the clue is not a written thing
&lt;/h2&gt;

&lt;p&gt;Numberlink prints numbers. Sashigane prints circles and arrows. Heyawake prints&lt;br&gt;
regions and numbers. Every puzzle in this series has a setter who &lt;strong&gt;writes&lt;br&gt;
something on the board&lt;/strong&gt;. Heteromino's setter writes nothing. They &lt;strong&gt;delete&lt;br&gt;
cells&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;What makes that more than a subset-picking exercise is that one black cell does&lt;br&gt;
two jobs, and you cannot buy one without the other:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The hole job.&lt;/strong&gt; That cell drops out of the tiling.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The wall job.&lt;/strong&gt; Pieces on opposite sides of it do not share an edge, so
&lt;strong&gt;two pieces of the same shape become legal&lt;/strong&gt; there.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Job 2, measured. I walked the answers to all 72 shipped boards and counted pairs&lt;br&gt;
of same-shaped pieces facing each other across a single black cell:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;boards with at least one such pair&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;65 / 72 (90.3%)&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;total pairs&lt;/td&gt;
&lt;td&gt;263&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;total pieces&lt;/td&gt;
&lt;td&gt;1,968&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;median / max per board&lt;/td&gt;
&lt;td&gt;3 / 11&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Take that one black cell away and those two pieces are touching twins, in&lt;br&gt;
violation. The wall job is not decoration.&lt;/p&gt;
&lt;h2&gt;
  
  
  1. The blank board — one-row strips are almost all dead
&lt;/h2&gt;

&lt;p&gt;With no clues at all: how many ways does an empty h×w grid fall into&lt;br&gt;
heterominoes? Exhaustively counted. Rectangles whose cell count is not divisible&lt;br&gt;
by three are disqualified before we start, marked &lt;code&gt;·&lt;/code&gt;.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;1&lt;/th&gt;
&lt;th&gt;2&lt;/th&gt;
&lt;th&gt;3&lt;/th&gt;
&lt;th&gt;4&lt;/th&gt;
&lt;th&gt;5&lt;/th&gt;
&lt;th&gt;6&lt;/th&gt;
&lt;th&gt;7&lt;/th&gt;
&lt;th&gt;8&lt;/th&gt;
&lt;th&gt;9&lt;/th&gt;
&lt;th&gt;10&lt;/th&gt;
&lt;th&gt;11&lt;/th&gt;
&lt;th&gt;12&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;1×n&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;·&lt;/td&gt;
&lt;td&gt;·&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;·&lt;/td&gt;
&lt;td&gt;·&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;·&lt;/td&gt;
&lt;td&gt;·&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;·&lt;/td&gt;
&lt;td&gt;·&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;2×n&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;·&lt;/td&gt;
&lt;td&gt;·&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;·&lt;/td&gt;
&lt;td&gt;·&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;·&lt;/td&gt;
&lt;td&gt;·&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;·&lt;/td&gt;
&lt;td&gt;·&lt;/td&gt;
&lt;td&gt;16&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;3×n&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;14&lt;/td&gt;
&lt;td&gt;28&lt;/td&gt;
&lt;td&gt;70&lt;/td&gt;
&lt;td&gt;144&lt;/td&gt;
&lt;td&gt;304&lt;/td&gt;
&lt;td&gt;688&lt;/td&gt;
&lt;td&gt;1476&lt;/td&gt;
&lt;td&gt;3168&lt;/td&gt;
&lt;td&gt;6956&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;4×n&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;·&lt;/td&gt;
&lt;td&gt;·&lt;/td&gt;
&lt;td&gt;14&lt;/td&gt;
&lt;td&gt;·&lt;/td&gt;
&lt;td&gt;·&lt;/td&gt;
&lt;td&gt;130&lt;/td&gt;
&lt;td&gt;·&lt;/td&gt;
&lt;td&gt;·&lt;/td&gt;
&lt;td&gt;1414&lt;/td&gt;
&lt;td&gt;·&lt;/td&gt;
&lt;td&gt;·&lt;/td&gt;
&lt;td&gt;14894&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;5×n&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;·&lt;/td&gt;
&lt;td&gt;·&lt;/td&gt;
&lt;td&gt;28&lt;/td&gt;
&lt;td&gt;·&lt;/td&gt;
&lt;td&gt;·&lt;/td&gt;
&lt;td&gt;686&lt;/td&gt;
&lt;td&gt;·&lt;/td&gt;
&lt;td&gt;·&lt;/td&gt;
&lt;td&gt;20077&lt;/td&gt;
&lt;td&gt;·&lt;/td&gt;
&lt;td&gt;·&lt;/td&gt;
&lt;td&gt;584442&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;6×n&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;70&lt;/td&gt;
&lt;td&gt;130&lt;/td&gt;
&lt;td&gt;686&lt;/td&gt;
&lt;td&gt;4552&lt;/td&gt;
&lt;td&gt;15218&lt;/td&gt;
&lt;td&gt;70654&lt;/td&gt;
&lt;td&gt;372124&lt;/td&gt;
&lt;td&gt;1525273&lt;/td&gt;
&lt;td&gt;6893222&lt;/td&gt;
&lt;td&gt;10887414*&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;7×n&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;·&lt;/td&gt;
&lt;td&gt;·&lt;/td&gt;
&lt;td&gt;144&lt;/td&gt;
&lt;td&gt;·&lt;/td&gt;
&lt;td&gt;·&lt;/td&gt;
&lt;td&gt;15218&lt;/td&gt;
&lt;td&gt;·&lt;/td&gt;
&lt;td&gt;·&lt;/td&gt;
&lt;td&gt;2001412&lt;/td&gt;
&lt;td&gt;·&lt;/td&gt;
&lt;td&gt;·&lt;/td&gt;
&lt;td&gt;5375356*&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;*&lt;/code&gt; is a &lt;strong&gt;lower bound&lt;/strong&gt; — the count hit its node budget. Everything else is&lt;br&gt;
exact, and the small entries are recomputed from scratch on every test run.&lt;/p&gt;

&lt;p&gt;The first row is the whole rule in miniature. &lt;strong&gt;A 1×n strip has no tiling for any&lt;br&gt;
n except 3.&lt;/strong&gt; In a single row the only piece that fits is the horizontal bar, and&lt;br&gt;
two horizontal bars in one row always share an edge. So a strip holds one piece&lt;br&gt;
and never two.&lt;/p&gt;

&lt;p&gt;Which also means 1×3 is &lt;strong&gt;the only board in this puzzle that is a legal puzzle&lt;br&gt;
with zero clues&lt;/strong&gt;: exactly one answer, nothing printed on it.&lt;/p&gt;

&lt;p&gt;None of 3×n, 4×n, 5×n or 6×n returns anything from OEIS.&lt;/p&gt;
&lt;h2&gt;
  
  
  2. Two rows, and the answer is a power of two
&lt;/h2&gt;

&lt;p&gt;The second row is not a mess either.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;strip&lt;/th&gt;
&lt;th&gt;2×3&lt;/th&gt;
&lt;th&gt;2×6&lt;/th&gt;
&lt;th&gt;2×9&lt;/th&gt;
&lt;th&gt;2×12&lt;/th&gt;
&lt;th&gt;2×15&lt;/th&gt;
&lt;th&gt;2×18&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;tilings&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;16&lt;/td&gt;
&lt;td&gt;32&lt;/td&gt;
&lt;td&gt;64&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2^m&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;16&lt;/td&gt;
&lt;td&gt;32&lt;/td&gt;
&lt;td&gt;64&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;bars used&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;pieces crossing a 3-column block&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;tilings of a blank 2 × 3m strip = 2^m&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Matched through m = 9 (2×27 = 512). But &lt;strong&gt;the count is the least interesting part&lt;br&gt;
of that claim&lt;/strong&gt; — numeric agreement can be coincidence, so the test suite checks&lt;br&gt;
the structure behind it instead. That is the bottom two rows: across every one of&lt;br&gt;
those tilings, &lt;strong&gt;no bar is ever used&lt;/strong&gt; and &lt;strong&gt;no piece ever crosses a three-column&lt;br&gt;
boundary&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;So a two-row strip is not a strip. It is a row of &lt;strong&gt;independent 2×3 blocks&lt;/strong&gt;, each&lt;br&gt;
cuttable by two Ls in two ways, and 2^m is just the product.&lt;/p&gt;

&lt;p&gt;The argument is short enough to do by hand. Put a bar in the top row of the&lt;br&gt;
leftmost three columns. The cell directly beneath it still needs a piece. Every L&lt;br&gt;
that could take that cell wants a top-row cell, and the bar already has them all.&lt;br&gt;
The only thing left is the bar directly underneath — same shape, touching, and so&lt;br&gt;
illegal. &lt;strong&gt;No bar can start at the left edge&lt;/strong&gt;, and the same trap propagates&lt;br&gt;
rightwards.&lt;/p&gt;

&lt;p&gt;This is the rule doing it, not the shape inventory: switch the same-shape rule off&lt;br&gt;
and a blank 2×6 has more than four tilings again, bars included. That check is in&lt;br&gt;
the test suite too.&lt;/p&gt;
&lt;h2&gt;
  
  
  3. Clue space is thin — and small enough to enumerate
&lt;/h2&gt;

&lt;p&gt;Because a clue set is nothing but a subset of cells, "how good is this as a clue&lt;br&gt;
language" is a question you can answer by &lt;strong&gt;brute force&lt;/strong&gt;. For small boards I&lt;br&gt;
walked &lt;strong&gt;every black-cell set of every legal size&lt;/strong&gt; and counted the answers each&lt;br&gt;
one admits.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;board&lt;/th&gt;
&lt;th&gt;black cells&lt;/th&gt;
&lt;th&gt;clue sets&lt;/th&gt;
&lt;th&gt;no answer&lt;/th&gt;
&lt;th&gt;many answers&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;exactly one&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;3×4&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;220&lt;/td&gt;
&lt;td&gt;37.3%&lt;/td&gt;
&lt;td&gt;20.0%&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;42.7%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3×4&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;924&lt;/td&gt;
&lt;td&gt;79.7%&lt;/td&gt;
&lt;td&gt;1.6%&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;18.7%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3×5&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;455&lt;/td&gt;
&lt;td&gt;34.3%&lt;/td&gt;
&lt;td&gt;42.9%&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;22.9%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3×6&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;816&lt;/td&gt;
&lt;td&gt;28.2%&lt;/td&gt;
&lt;td&gt;54.2%&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;17.6%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3×6&lt;/td&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;48,620&lt;/td&gt;
&lt;td&gt;91.8%&lt;/td&gt;
&lt;td&gt;1.1%&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;7.1%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4×5&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;190&lt;/td&gt;
&lt;td&gt;2.1%&lt;/td&gt;
&lt;td&gt;90.5%&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;7.4%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4×5&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;15,504&lt;/td&gt;
&lt;td&gt;57.9%&lt;/td&gt;
&lt;td&gt;20.0%&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;22.1%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4×6&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;134,596&lt;/td&gt;
&lt;td&gt;65.6%&lt;/td&gt;
&lt;td&gt;18.8%&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;15.6%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4×6&lt;/td&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;1,307,504&lt;/td&gt;
&lt;td&gt;89.5%&lt;/td&gt;
&lt;td&gt;3.3%&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;7.2%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5×6&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;4,060&lt;/td&gt;
&lt;td&gt;4.6%&lt;/td&gt;
&lt;td&gt;93.5%&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1.9%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5×6&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;593,775&lt;/td&gt;
&lt;td&gt;48.2%&lt;/td&gt;
&lt;td&gt;40.1%&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;11.7%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6×6&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;7,140&lt;/td&gt;
&lt;td&gt;2.6%&lt;/td&gt;
&lt;td&gt;97.0%&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.3%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6×6&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;1,947,792&lt;/td&gt;
&lt;td&gt;33.7%&lt;/td&gt;
&lt;td&gt;58.7%&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;7.6%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;(An excerpt; the complete table is on the demo page.)&lt;/p&gt;

&lt;p&gt;Two things read off it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Unique boards are rare everywhere.&lt;/strong&gt; The best cell in the entire census is a 3×4&lt;br&gt;
with 3 clues, and even there only 42.7% of clue sets work.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;And the failure mode flips.&lt;/strong&gt; With few black cells, boards fail by having too&lt;br&gt;
many answers. With many, they fail by having none — because the black cells have&lt;br&gt;
chopped the grid into regions whose sizes are not multiples of three. Uniqueness&lt;br&gt;
lives in a narrow band between "hasn't said enough" and "has said something&lt;br&gt;
impossible", and the band narrows as the board grows.&lt;/p&gt;

&lt;p&gt;Since the census is exhaustive, the minimum clue count is an &lt;strong&gt;exact bound, not a&lt;br&gt;
search result&lt;/strong&gt;:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;board&lt;/th&gt;
&lt;th&gt;cells&lt;/th&gt;
&lt;th&gt;sparsest clue set that pins an answer&lt;/th&gt;
&lt;th&gt;density&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;3×4&lt;/td&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;25.0%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3×5&lt;/td&gt;
&lt;td&gt;15&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;20.0%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4×4&lt;/td&gt;
&lt;td&gt;16&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;25.0%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3×6&lt;/td&gt;
&lt;td&gt;18&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;16.7%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4×5&lt;/td&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;2&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;10.0%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4×6&lt;/td&gt;
&lt;td&gt;24&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;12.5%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5×5&lt;/td&gt;
&lt;td&gt;25&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;16.0%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5×6&lt;/td&gt;
&lt;td&gt;30&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;10.0%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6×6&lt;/td&gt;
&lt;td&gt;36&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;8.3%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Smallest by count is 4×5 with &lt;strong&gt;2&lt;/strong&gt; — a twenty-cell board pinned by two black&lt;br&gt;
cells. Smallest by density is 6×6 at &lt;strong&gt;8.3%&lt;/strong&gt;. (4×4 and 5×5 need 4 only because&lt;br&gt;
their cell counts are 1 mod 3, so the legal clue counts are 1, 4, 7, … and 1 is&lt;br&gt;
not enough.)&lt;/p&gt;
&lt;h2&gt;
  
  
  4. A setter cannot scatter clues
&lt;/h2&gt;

&lt;p&gt;Scale up and sample, and the band closes fast. Random black-cell placements, with&lt;br&gt;
the &lt;strong&gt;peak&lt;/strong&gt; unique rate over all legal clue counts:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;board&lt;/th&gt;
&lt;th&gt;samples per clue count&lt;/th&gt;
&lt;th&gt;best clue count&lt;/th&gt;
&lt;th&gt;unique rate there&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;6×6&lt;/td&gt;
&lt;td&gt;4,000&lt;/td&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;8.1%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8×8&lt;/td&gt;
&lt;td&gt;1,500&lt;/td&gt;
&lt;td&gt;13&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1.5%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10×10&lt;/td&gt;
&lt;td&gt;600&lt;/td&gt;
&lt;td&gt;22&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.7%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;12×12&lt;/td&gt;
&lt;td&gt;300&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;On 12×12: &lt;strong&gt;17 legal clue counts × 300 draws = 5,100 boards, and not one of them&lt;br&gt;
had exactly one answer.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;So the generator does not sample. And here is where generating this puzzle&lt;br&gt;
diverges from every other one in the series.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The other generators all have the same shape:&lt;/strong&gt; draw an answer, read the clues&lt;br&gt;
off it, then erase clues one at a time while the board stays unique. Heteromino&lt;br&gt;
permits &lt;strong&gt;none&lt;/strong&gt; of that.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The clues are &lt;strong&gt;not a function of the answer&lt;/strong&gt;. Blacking a cell in or out
changes which cells even need covering.&lt;/li&gt;
&lt;li&gt;The number of white cells must stay a multiple of three, so black cells cannot
be &lt;strong&gt;added or removed one at a time&lt;/strong&gt; at all.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;There is no legal single-step edit that removes a clue, so a minimisation phase&lt;br&gt;
cannot be written.&lt;/strong&gt; What is left is: scatter &lt;code&gt;k&lt;/code&gt; black cells, count the answers,&lt;br&gt;
and &lt;strong&gt;walk the black cells around the board&lt;/strong&gt; one move at a time.&lt;/p&gt;

&lt;p&gt;There was one implementation trap here. Scoring naively by solution count&lt;br&gt;
&lt;strong&gt;cannot move&lt;/strong&gt;. As the census shows, in the interesting density band most random&lt;br&gt;
placements have &lt;em&gt;no&lt;/em&gt; answer rather than too many, so most of the search space is a&lt;br&gt;
flat plateau of "zero solutions". I gave unsolvable boards a secondary gradient —&lt;br&gt;
&lt;strong&gt;how many open regions have a size that is not a multiple of three&lt;/strong&gt;. That is a&lt;br&gt;
necessary condition for solvability and never a sufficient one, but it is a&lt;br&gt;
usable slope out of the impossible region.&lt;/p&gt;

&lt;p&gt;What the search reaches inside a fixed budget:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;board&lt;/th&gt;
&lt;th&gt;sparsest clue set reached&lt;/th&gt;
&lt;th&gt;density&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;6×6&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;8.3%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8×8&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;10.9%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10×10&lt;/td&gt;
&lt;td&gt;13&lt;/td&gt;
&lt;td&gt;13.0%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;12×12&lt;/td&gt;
&lt;td&gt;24&lt;/td&gt;
&lt;td&gt;16.7%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;That is &lt;strong&gt;a bound on the search, not on the puzzle&lt;/strong&gt;. The exhaustive table above&lt;br&gt;
is the one that says what exists.&lt;/p&gt;
&lt;h2&gt;
  
  
  5. The main result — the ladder is flat, then falls off a cliff
&lt;/h2&gt;

&lt;p&gt;Branch points needed to prove the shipped boards unique, summed per rung:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;fit&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;region&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;hetero&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;probe&lt;/code&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;8×8, 40 boards&lt;/td&gt;
&lt;td&gt;7,046&lt;/td&gt;
&lt;td&gt;6,547&lt;/td&gt;
&lt;td&gt;6,537&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;12×12, 32 boards&lt;/td&gt;
&lt;td&gt;103,060&lt;/td&gt;
&lt;td&gt;78,098&lt;/td&gt;
&lt;td&gt;77,459&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;39&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;That is a strange-looking ladder. &lt;code&gt;region&lt;/code&gt; — "an open region has a multiple of&lt;br&gt;
three cells", which sounds like it should carry the puzzle — takes 7.1% off &lt;code&gt;fit&lt;/code&gt;&lt;br&gt;
at 8×8 and 24.2% at 12×12. &lt;code&gt;hetero&lt;/code&gt;, &lt;strong&gt;the rung that encodes the puzzle's own&lt;br&gt;
rule&lt;/strong&gt;, takes off another 0.2% and 0.8%. Then &lt;code&gt;probe&lt;/code&gt; takes 8×8 to &lt;strong&gt;0&lt;/strong&gt; and&lt;br&gt;
12×12 to &lt;strong&gt;39&lt;/strong&gt;. Almost flat, then a cliff.&lt;/p&gt;

&lt;p&gt;Asking what each rung can prove from an &lt;strong&gt;untouched&lt;/strong&gt; board makes the reason&lt;br&gt;
plain (this is exactly what the checkbox on the demo page displays):&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;cells proved before any guess&lt;/th&gt;
&lt;th&gt;&lt;code&gt;fit&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;region&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;hetero&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;probe&lt;/code&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;8×8&lt;/td&gt;
&lt;td&gt;2.1%&lt;/td&gt;
&lt;td&gt;2.1%&lt;/td&gt;
&lt;td&gt;2.1%&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;100%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;12×12&lt;/td&gt;
&lt;td&gt;3.9%&lt;/td&gt;
&lt;td&gt;3.9%&lt;/td&gt;
&lt;td&gt;4.2%&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;88.1%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;There is nothing to propagate from.&lt;/strong&gt; Every other puzzle in this series prints&lt;br&gt;
something — a number, an arrow, a region edge — that pins a cell or two locally&lt;br&gt;
and gives the fixpoint computation somewhere to start. Heteromino prints &lt;strong&gt;holes&lt;/strong&gt;.&lt;br&gt;
Each open cell begins with &lt;strong&gt;9.5 candidate pieces&lt;/strong&gt; on average and no local rule&lt;br&gt;
eliminates a single one of them. The bottom three rungs between them settle 2.1%&lt;br&gt;
and 4.2% of the board and stop.&lt;/p&gt;

&lt;p&gt;Add &lt;strong&gt;one level of lookahead&lt;/strong&gt; — assume a piece, propagate, kill it if that&lt;br&gt;
contradicts — and it goes to 100% and 88.1%. &lt;strong&gt;Heteromino is, to a good&lt;br&gt;
approximation, exactly singleton-consistency-hard&lt;/strong&gt;: nothing below probe works,&lt;br&gt;
and probe needs almost no search on top of it.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;hetero&lt;/code&gt; rung is still the interesting inference, because it &lt;strong&gt;reasons about a&lt;br&gt;
piece it has not identified yet&lt;/strong&gt;: if every surviving candidate for some cell has&lt;br&gt;
the same shape, then whoever ends up owning that cell has that shape, whichever&lt;br&gt;
one it turns out to be — so every piece of that shape touching that cell is&lt;br&gt;
already dead. It just turns out that on a board with no numbers, that inference&lt;br&gt;
has almost nothing to fire on until a guess has been made.&lt;/p&gt;
&lt;h2&gt;
  
  
  6. Dropping each half of the rule
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;rule set&lt;/th&gt;
&lt;th&gt;boards that stop being unique&lt;/th&gt;
&lt;th&gt;of those, boards left with no answer&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;nothing removed&lt;/td&gt;
&lt;td&gt;0 / 72&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;no same-shape rule (pure tromino packing)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;72 / 72&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;rotations count as the same shape (LITS convention)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;72 / 72&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;72&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The same-shape rule is not a garnish on a packing puzzle; it is structural for&lt;br&gt;
every board.&lt;/p&gt;

&lt;p&gt;The other direction is the interesting one. &lt;strong&gt;Tightening&lt;/strong&gt; the rule — merging&lt;br&gt;
rotations, as LITS does — does not make boards more constrained and more unique.&lt;br&gt;
It makes them &lt;strong&gt;unsolvable&lt;/strong&gt;, all 72 of them, because the intended answer itself&lt;br&gt;
stops being legal.&lt;/p&gt;
&lt;h2&gt;
  
  
  7. Two things I expected and did not get
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Bars are barely suppressed.&lt;/strong&gt; A bar has one long flat side, and a long flat side&lt;br&gt;
is a lot of edge on which to run into a twin, so the rule ought to punish it.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;I—&lt;/th&gt;
&lt;th&gt;I|&lt;/th&gt;
&lt;th&gt;L┌&lt;/th&gt;
&lt;th&gt;L┐&lt;/th&gt;
&lt;th&gt;L└&lt;/th&gt;
&lt;th&gt;L┘&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;bars&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;shipped answers&lt;/td&gt;
&lt;td&gt;16.1%&lt;/td&gt;
&lt;td&gt;15.5%&lt;/td&gt;
&lt;td&gt;16.5%&lt;/td&gt;
&lt;td&gt;16.5%&lt;/td&gt;
&lt;td&gt;17.7%&lt;/td&gt;
&lt;td&gt;17.7%&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;31.6%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;every tiling of a blank 6×6&lt;/td&gt;
&lt;td&gt;14.9%&lt;/td&gt;
&lt;td&gt;14.9%&lt;/td&gt;
&lt;td&gt;17.5%&lt;/td&gt;
&lt;td&gt;17.5%&lt;/td&gt;
&lt;td&gt;17.5%&lt;/td&gt;
&lt;td&gt;17.5%&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;29.9%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;every tiling of a blank 2×12&lt;/td&gt;
&lt;td&gt;0%&lt;/td&gt;
&lt;td&gt;0%&lt;/td&gt;
&lt;td&gt;25%&lt;/td&gt;
&lt;td&gt;25%&lt;/td&gt;
&lt;td&gt;25%&lt;/td&gt;
&lt;td&gt;25%&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;An unweighted shape set would give 33.3%. Measured: 31.6% and 29.9%. &lt;strong&gt;Two or&lt;br&gt;
three points.&lt;/strong&gt; Recorded as a null result rather than quietly dropped.&lt;/p&gt;

&lt;p&gt;The exception is the one place the effect is not statistical at all: in a blank&lt;br&gt;
2×12, bars are &lt;strong&gt;0%&lt;/strong&gt; — the two-row strip cannot use one, as shown above. Where&lt;br&gt;
the geometry is tight enough the rule excludes bars outright; where it is not, it&lt;br&gt;
barely leans on them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Every clue is load-bearing — more than I wanted.&lt;/strong&gt; Move a single black cell on a&lt;br&gt;
shipped board to a random empty cell, leaving the clue &lt;strong&gt;count&lt;/strong&gt; untouched:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;board&lt;/th&gt;
&lt;th&gt;single-clue moves tried&lt;/th&gt;
&lt;th&gt;still exactly one answer&lt;/th&gt;
&lt;th&gt;no answer at all&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;8×8&lt;/td&gt;
&lt;td&gt;1,440&lt;/td&gt;
&lt;td&gt;6.2%&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;30.8%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;12×12&lt;/td&gt;
&lt;td&gt;3,888&lt;/td&gt;
&lt;td&gt;3.4%&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;41.0%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Almost every move destroys the puzzle, and the dominant failure is not "ambiguous"&lt;br&gt;
but "unsolvable" — the same asymmetry the exhaustive census shows, seen from&lt;br&gt;
inside a board that works.&lt;/p&gt;
&lt;h2&gt;
  
  
  8. The bug the second engine caught
&lt;/h2&gt;

&lt;p&gt;There are two engines and they share no code. The first makes each cell a variable&lt;br&gt;
whose domain is the trominoes that could still cover it, and propagates the four&lt;br&gt;
rungs to a fixpoint. The second builds no domain at all: it walks the grid and, at&lt;br&gt;
the first uncovered cell, tries every piece that would cover it, checking legality&lt;br&gt;
directly against the pieces already down.&lt;/p&gt;

&lt;p&gt;The search branches on "&lt;strong&gt;which piece owns this cell&lt;/strong&gt;". That partitions the answer&lt;br&gt;
space, so the subtrees are disjoint and &lt;strong&gt;nothing needs excluding between them&lt;/strong&gt;.&lt;br&gt;
The first version excluded each tried candidate from the parent state anyway and&lt;br&gt;
re-propagated — it looks like a tidy optimisation.&lt;/p&gt;

&lt;p&gt;It breaks. After excluding a candidate and propagating, propagation can commit a&lt;br&gt;
&lt;strong&gt;later&lt;/strong&gt; candidate to that same cell. Then when that candidate's own branch comes&lt;br&gt;
up, &lt;code&gt;commit&lt;/code&gt; finds the cell already owned, returns &lt;code&gt;false&lt;/code&gt;, and &lt;strong&gt;the branch is&lt;br&gt;
skipped in silence&lt;/strong&gt;. No error. Just fewer answers.&lt;/p&gt;

&lt;p&gt;The propagator reported &lt;strong&gt;5&lt;/strong&gt; tilings of a blank 3×4. The scanner reported &lt;strong&gt;14&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Nothing about the propagator looked wrong on its own. It took a second engine&lt;br&gt;
sharing no code with it to say so.&lt;/p&gt;

&lt;p&gt;The test suite carries a soundness property for this: any cell the propagator&lt;br&gt;
assigns an owner to must have &lt;strong&gt;that same owner in every answer the scanner&lt;br&gt;
finds&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Implementation
&lt;/h2&gt;

&lt;p&gt;TypeScript + Vite, no runtime dependencies, plain arrays in the solver.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;src/heteromino.ts    rules, candidate generation, the four rungs, engine 1
src/brute.ts         engine 2 — shares no code
src/generate.ts      the clue-walking generator
src/ledger.json      blank-board tiling counts  (npm run ledger)
src/stats.json       every figure in this article (npm run stats)
tools/notes.mts      generates the demo page's notes from stats.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every number on the demo page is generated by &lt;code&gt;tools/notes.mts&lt;/code&gt; out of&lt;br&gt;
&lt;code&gt;src/stats.json&lt;/code&gt;, so &lt;strong&gt;not one figure there is transcribed by hand&lt;/strong&gt; — re-run the&lt;br&gt;
measurements and the prose follows them. 39 tests.&lt;/p&gt;

&lt;p&gt;Puzzle #56 in the solver series.&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>algorithms</category>
      <category>gamedev</category>
      <category>puzzle</category>
    </item>
    <item>
      <title>Sashigane: which end the arrow goes on is not a matter of taste</title>
      <dc:creator>SEN LLC</dc:creator>
      <pubDate>Fri, 04 Sep 2026 23:48:08 +0000</pubDate>
      <link>https://dev.to/sendotltd/sashigane-which-end-the-arrow-goes-on-is-not-a-matter-of-taste-541p</link>
      <guid>https://dev.to/sendotltd/sashigane-which-end-the-arrow-goes-on-is-not-a-matter-of-taste-541p</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Sashigane&lt;/strong&gt; (さしがね, "carpenter's square") in the browser with a&lt;br&gt;
&lt;strong&gt;four-rung solver&lt;/strong&gt;. This one has a property most Nikoli puzzles do not:&lt;br&gt;
&lt;strong&gt;every circle is given&lt;/strong&gt;. A circle always sits on a piece's bend, so the&lt;br&gt;
circles printed on the board &lt;em&gt;are&lt;/em&gt; the set of corners — you know how many&lt;br&gt;
pieces there are and where every corner is before you place a single square.&lt;br&gt;
The only unknown is how far the arms reach. So what are the clues doing? I&lt;br&gt;
measured it, and the load-bearing part is &lt;strong&gt;which cell the arrow sits on&lt;/strong&gt;;&lt;br&gt;
which way it &lt;em&gt;points&lt;/em&gt; is worth about a tenth of that. And the one freedom a&lt;br&gt;
setter has left — which of two ends the arrow goes on — swings the odds of the&lt;br&gt;
board being a puzzle at all between 11.3% and 29.8% on a 12×12. Puzzle #55 in&lt;br&gt;
the solver series.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Demo: &lt;a href="https://sen.ltd/portfolio/sashigane/" rel="noopener noreferrer"&gt;https://sen.ltd/portfolio/sashigane/&lt;/a&gt;&lt;br&gt;
Repo: &lt;a href="https://github.com/sen-ltd/sashigane" rel="noopener noreferrer"&gt;https://github.com/sen-ltd/sashigane&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsen.ltd%2Fportfolio%2Fsashigane%2Fassets%2Fscreenshot.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsen.ltd%2Fportfolio%2Fsashigane%2Fassets%2Fscreenshot.png" alt="Sashigane" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Rules
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Cut the board into &lt;strong&gt;L-shaped pieces of width one&lt;/strong&gt; — two straight arms of at
least one cell each, meeting at a right angle. The smallest piece is three
cells.&lt;/li&gt;
&lt;li&gt;Every piece holds exactly one &lt;strong&gt;circle&lt;/strong&gt;, on the &lt;strong&gt;bend&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Every piece holds exactly one &lt;strong&gt;arrow&lt;/strong&gt;, on one of its two far &lt;strong&gt;ends&lt;/strong&gt;,
pointing back along its arm at the bend.&lt;/li&gt;
&lt;li&gt;A number inside a circle is that piece's cell count. Circles may be bare.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Rule 2 does a lot of work. Every piece has a circle and it is always on the bend,&lt;br&gt;
so the printed circles are exactly the corners of the answer. Piece count and&lt;br&gt;
corner positions come free.&lt;/p&gt;

&lt;p&gt;And the arrow has a property that most puzzle arrows do not. It is &lt;em&gt;on&lt;/em&gt; an end&lt;br&gt;
and it points home, which means it &lt;strong&gt;fixes one whole arm outright&lt;/strong&gt;: the arm runs&lt;br&gt;
in the reverse of the arrow's direction, and its length is the distance from the&lt;br&gt;
arrow to the bend. The arrow is not one bit of directional information — it is a&lt;br&gt;
complete specification of one arm.&lt;/p&gt;

&lt;p&gt;Put those together and the shape of the problem is clear. Every corner is known;&lt;br&gt;
one arm of every piece is known. &lt;strong&gt;All that is left is which of two perpendicular&lt;br&gt;
sides the other arm falls on, and how far it goes.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  1. The blank board is not always solvable
&lt;/h2&gt;

&lt;p&gt;Before any clue, count how many ways an empty grid falls into L-shapes at all.&lt;/p&gt;

&lt;p&gt;On a one-cell-wide strip, none — an L needs two dimensions. On 2×2, none. And on&lt;br&gt;
&lt;strong&gt;3×3, none&lt;/strong&gt;: nine cells would have to split as 3+3+3 or 4+5 (the largest L that&lt;br&gt;
fits in a 3×3 is five cells), and neither can be done. It is the &lt;strong&gt;only square&lt;br&gt;
that fails&lt;/strong&gt;, and it sits between 2×3, which works two ways, and 3×4, which works&lt;br&gt;
twenty.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;2×n&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;14&lt;/td&gt;
&lt;td&gt;26&lt;/td&gt;
&lt;td&gt;46&lt;/td&gt;
&lt;td&gt;74&lt;/td&gt;
&lt;td&gt;126&lt;/td&gt;
&lt;td&gt;218&lt;/td&gt;
&lt;td&gt;366&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;3×n&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;td&gt;64&lt;/td&gt;
&lt;td&gt;234&lt;/td&gt;
&lt;td&gt;664&lt;/td&gt;
&lt;td&gt;2220&lt;/td&gt;
&lt;td&gt;7476&lt;/td&gt;
&lt;td&gt;25882&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;4×n&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;td&gt;110&lt;/td&gt;
&lt;td&gt;752&lt;/td&gt;
&lt;td&gt;4522&lt;/td&gt;
&lt;td&gt;27380&lt;/td&gt;
&lt;td&gt;167078&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;5×n&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;64&lt;/td&gt;
&lt;td&gt;752&lt;/td&gt;
&lt;td&gt;7720&lt;/td&gt;
&lt;td&gt;84846&lt;/td&gt;
&lt;td&gt;908020&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;6×n&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;234&lt;/td&gt;
&lt;td&gt;4522&lt;/td&gt;
&lt;td&gt;84846&lt;/td&gt;
&lt;td&gt;1557970&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The strip has a linear recurrence. Every term past the third satisfies&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;a(n) = a(n−1) + 2·a(n−3)&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;which is OEIS &lt;a href="https://oeis.org/A052537" rel="noopener noreferrer"&gt;A052537&lt;/a&gt;, generating function&lt;br&gt;
&lt;code&gt;(1−x)/(1−x−2x³)&lt;/code&gt;. I have no bijective proof, so it lives in the repository as an&lt;br&gt;
identity re-checked against every computed term on every test run. None of the&lt;br&gt;
other rows, and not the square diagonal &lt;code&gt;0, 0, 0, 110, 7720, 1557970&lt;/code&gt;, returns&lt;br&gt;
anything from OEIS (searched 2026-09-05). Every value past &lt;code&gt;4×6&lt;/code&gt; is cross-checked&lt;br&gt;
by computing the transpose, which the scanner walks in a completely different&lt;br&gt;
order.&lt;/p&gt;

&lt;p&gt;Pieces are at least three cells, so a board carries at most &lt;code&gt;⌊h·w/3⌋&lt;/code&gt; circles —&lt;br&gt;
and that ceiling is reached: 4×6 admits partitions into all eight pieces.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Print every number and the puzzle stops being one
&lt;/h2&gt;

&lt;p&gt;The arrow already fixes one arm. Add the number and the other arm's &lt;strong&gt;length&lt;/strong&gt; is&lt;br&gt;
fixed too. The only thing left is which side it falls on.&lt;/p&gt;

&lt;p&gt;So a fully clued circle has &lt;strong&gt;at most two shapes&lt;/strong&gt;. Over &lt;strong&gt;136,576&lt;/strong&gt; fully clued&lt;br&gt;
circles drawn from every partition of 3×5, 4×4 and 4×5, &lt;strong&gt;80.3% had exactly one&lt;br&gt;
shape and 19.7% had two&lt;/strong&gt;. Never three.&lt;/p&gt;

&lt;p&gt;And the tiling always picks between them. Cross every partition of a board with&lt;br&gt;
every one of the &lt;code&gt;2^k&lt;/code&gt; ways to place the arrows, with all numbers printed:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;board&lt;/th&gt;
&lt;th&gt;(partition, arrow-mask) pairs&lt;/th&gt;
&lt;th&gt;with exactly one answer&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;2×6&lt;/td&gt;
&lt;td&gt;72&lt;/td&gt;
&lt;td&gt;100.0%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3×4&lt;/td&gt;
&lt;td&gt;192&lt;/td&gt;
&lt;td&gt;100.0%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3×5&lt;/td&gt;
&lt;td&gt;896&lt;/td&gt;
&lt;td&gt;100.0%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3×6&lt;/td&gt;
&lt;td&gt;6,432&lt;/td&gt;
&lt;td&gt;100.0%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4×4&lt;/td&gt;
&lt;td&gt;1,888&lt;/td&gt;
&lt;td&gt;100.0%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4×5&lt;/td&gt;
&lt;td&gt;24,416&lt;/td&gt;
&lt;td&gt;100.0%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;33,896 boards, not one ambiguous&lt;/strong&gt;, plus a random search from 5×5 up to 10×10&lt;br&gt;
that also found none. I have no proof, so this is a measurement and not a&lt;br&gt;
theorem — but what it says is that &lt;strong&gt;the interesting Sashigane board is the one&lt;br&gt;
with the numbers taken off&lt;/strong&gt;, which is why this generator erases as many as it&lt;br&gt;
can.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Take the numbers away and the arrow end starts to matter
&lt;/h2&gt;

&lt;p&gt;The same exhaustion with the circles left bare:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;board&lt;/th&gt;
&lt;th&gt;pairs&lt;/th&gt;
&lt;th&gt;unique&lt;/th&gt;
&lt;th&gt;answers no arrow placement can pin&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;2×6&lt;/td&gt;
&lt;td&gt;72&lt;/td&gt;
&lt;td&gt;100.0%&lt;/td&gt;
&lt;td&gt;0 of 6&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3×4&lt;/td&gt;
&lt;td&gt;192&lt;/td&gt;
&lt;td&gt;87.5%&lt;/td&gt;
&lt;td&gt;0 of 20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3×5&lt;/td&gt;
&lt;td&gt;896&lt;/td&gt;
&lt;td&gt;81.3%&lt;/td&gt;
&lt;td&gt;0 of 64&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3×6&lt;/td&gt;
&lt;td&gt;6,432&lt;/td&gt;
&lt;td&gt;73.5%&lt;/td&gt;
&lt;td&gt;0 of 234&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4×4&lt;/td&gt;
&lt;td&gt;1,888&lt;/td&gt;
&lt;td&gt;87.3%&lt;/td&gt;
&lt;td&gt;0 of 110&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4×5&lt;/td&gt;
&lt;td&gt;24,416&lt;/td&gt;
&lt;td&gt;74.8%&lt;/td&gt;
&lt;td&gt;0 of 752&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4×6&lt;/td&gt;
&lt;td&gt;284,000&lt;/td&gt;
&lt;td&gt;70.9%&lt;/td&gt;
&lt;td&gt;0 of 4,522&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The last column is the reassuring one: &lt;strong&gt;no answer is unprintable&lt;/strong&gt;. Every&lt;br&gt;
partition counted here has at least one arrow placement that pins it. But more&lt;br&gt;
than a quarter of the choices are wrong, and the setter has to find a right one.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. The arrow end is the only choice the setter has, and it is worth 2.6×
&lt;/h2&gt;

&lt;p&gt;Circles are forced onto the bends and the numbers get erased, so the only thing a&lt;br&gt;
Sashigane setter really decides is &lt;strong&gt;which of a piece's two ends carries the&lt;br&gt;
arrow&lt;/strong&gt; — a choice that is completely invisible in the answer. Take the same&lt;br&gt;
random answers and draw each of them three ways: every arrow on its piece's&lt;br&gt;
longer arm, every arrow on the shorter arm, and one coin flip per piece.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;board&lt;/th&gt;
&lt;th&gt;pieces&lt;/th&gt;
&lt;th&gt;all on the long arm&lt;/th&gt;
&lt;th&gt;all on the short arm&lt;/th&gt;
&lt;th&gt;coin flip&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;6×6&lt;/td&gt;
&lt;td&gt;median 6&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;57.9%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;49.8%&lt;/td&gt;
&lt;td&gt;49.9%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8×8&lt;/td&gt;
&lt;td&gt;median 9&lt;/td&gt;
&lt;td&gt;41.8%&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;44.8%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;30.4%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;12×12&lt;/td&gt;
&lt;td&gt;median 14&lt;/td&gt;
&lt;td&gt;20.8%&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;29.8%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;11.3%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The first two columns are 1200, 1200 and 400 answers; the coin-flip column is&lt;br&gt;
eight independent masks per answer, so 9,600, 9,600 and 3,200 boards.&lt;/p&gt;

&lt;p&gt;Two things come out, and only one of them is what I expected.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A consistent convention beats an inconsistent one, every time.&lt;/strong&gt; At 12×12 the&lt;br&gt;
short-arm convention pins the answer 29.8% of the time and a coin flip 11.3% —&lt;br&gt;
same answers, same circles, same number of arrows, differing only in which end&lt;br&gt;
each arrow went on. I do not have a mechanism for it. Ambiguity is a property of&lt;br&gt;
the printed board alone and the solver never learns the convention, so all a&lt;br&gt;
convention can do is change &lt;em&gt;which&lt;/em&gt; boards you land on. Apparently it lands on&lt;br&gt;
better ones.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;And which convention is better flips with the board size.&lt;/strong&gt; Long arm wins at&lt;br&gt;
6×6 by eight points; short arm wins at 12×12 by nine. At 8×8 they are within a&lt;br&gt;
couple of points, which is inside the sampling error here. So there is no rule of&lt;br&gt;
thumb to hand a setter — only the fact that guessing is the one thing that is&lt;br&gt;
reliably wrong.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. The numbers really are nearly free
&lt;/h2&gt;

&lt;p&gt;The generator prints every number, confirms uniqueness, then erases numbers one&lt;br&gt;
at a time and keeps every erasure that survives. Very little survives:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;bank&lt;/th&gt;
&lt;th&gt;pieces&lt;/th&gt;
&lt;th&gt;numbers left&lt;/th&gt;
&lt;th&gt;unique with &lt;em&gt;no&lt;/em&gt; numbers&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;8×8, 40 boards&lt;/td&gt;
&lt;td&gt;median 9&lt;/td&gt;
&lt;td&gt;0–2, median &lt;strong&gt;0&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;22 of 40&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;12×12, 32 boards&lt;/td&gt;
&lt;td&gt;median 17&lt;/td&gt;
&lt;td&gt;0–4, median 1&lt;/td&gt;
&lt;td&gt;10 of 32&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;More than half the 8×8 boards shipped here carry no number anywhere. The circles&lt;br&gt;
and the arrows are the puzzle.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Which clause is load-bearing — position beats direction ten to one
&lt;/h2&gt;

&lt;p&gt;Each clause switched off in turn, over all 72 shipped boards:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;rule removed&lt;/th&gt;
&lt;th&gt;boards that stop being unique&lt;/th&gt;
&lt;th&gt;median answers when they do&lt;/th&gt;
&lt;th&gt;branch points&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;em&gt;nothing&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;0 / 72&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;the arrow points home&lt;/td&gt;
&lt;td&gt;5 / 72&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;the arrow sits at an end&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;52 / 72&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;1,006&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;the circle sits on the bend&lt;/td&gt;
&lt;td&gt;22 / 72&lt;/td&gt;
&lt;td&gt;2.5&lt;/td&gt;
&lt;td&gt;146&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;a number equals the piece size&lt;/td&gt;
&lt;td&gt;40 / 72&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;386&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;The arrow's position is worth ten times the arrow's direction.&lt;/strong&gt; That is the&lt;br&gt;
opposite of where the rule puts its weight. "An arrow at an end pointing at the&lt;br&gt;
circle" reads like one clue whose content is the direction, with the position as&lt;br&gt;
the peg it hangs on. It is the other way round: knowing which cell is an end is&lt;br&gt;
nearly all of it, and knowing which way it points adds a little on top.&lt;/p&gt;

&lt;p&gt;The last row is a self-check rather than a finding — the numbers were minimised,&lt;br&gt;
so every surviving number is load-bearing by construction, and exactly the 40&lt;br&gt;
boards that still carry one lose uniqueness when the size rule goes.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. The ladder, and how much of it never fires
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;rung&lt;/th&gt;
&lt;th&gt;what it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;fit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;build each circle's candidate list: an L is admissible if it holds this circle at its bend, no other circle, exactly one arrow, at an end, pointing home, and the right cell count&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;cover&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;every cell has exactly one owner. If only one circle can reach a cell, its piece takes it. If every survivor of a circle covers a cell, nobody else may&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;area&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;sizes add to &lt;code&gt;h·w&lt;/code&gt;, so a candidate whose size leaves the rest an impossible remainder dies&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;probe&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;force each survivor in turn and run the rungs below&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Branch points needed to prove the answer unique, summed over the shipped boards:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;fit&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;cover&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;area&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;probe&lt;/code&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;8×8, 40 boards&lt;/td&gt;
&lt;td&gt;4,053,280*&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;12×12, 32 boards&lt;/td&gt;
&lt;td&gt;9,600,032*&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;* five 8×8 boards and every 12×12 board hit a 300,000-branch cap, so those two&lt;br&gt;
cells are lower bounds.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;cover&lt;/code&gt; finishes every board on this bank without a guess, so &lt;code&gt;area&lt;/code&gt; and &lt;code&gt;probe&lt;/code&gt;&lt;br&gt;
never fire in anger. They stay because &lt;code&gt;area&lt;/code&gt; is what rejects a board whose&lt;br&gt;
numbers cannot add up, and &lt;code&gt;probe&lt;/code&gt; is what the generator leans on while deciding&lt;br&gt;
whether a draft is unique.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;fit&lt;/code&gt; alone — pure exact cover with no propagation — settles 94.4% of an 8×8 by&lt;br&gt;
construction and then needs millions of branch points for the rest. &lt;strong&gt;One rung&lt;br&gt;
buys the last 5.6% and all of the search.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  8. A size budget that needs no search at all
&lt;/h2&gt;

&lt;p&gt;The pieces cover the board, so their sizes add to &lt;code&gt;h·w&lt;/code&gt;. Every printed number&lt;br&gt;
takes its share off the top. Every piece without a number needs at least 3 cells&lt;br&gt;
and can hold at most &lt;code&gt;h+w−1&lt;/code&gt;. So the leftover has to land inside&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;[3 · anon, (h+w−1) · anon]&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;and if it does not, the board has no answer — no partial solution, nothing to&lt;br&gt;
unwind. &lt;code&gt;budgetOf&lt;/code&gt; in &lt;code&gt;src/sashigane.ts&lt;/code&gt; is the whole implementation, and it runs&lt;br&gt;
live in the panel beside the demo board.&lt;/p&gt;

&lt;h2&gt;
  
  
  9. The bug the second engine caught
&lt;/h2&gt;

&lt;p&gt;There are two solvers and they share no code. One turns each circle into a&lt;br&gt;
variable whose domain is the L-shapes it could still be, and propagates coverage&lt;br&gt;
and area to a fixpoint. The other never mentions a circle: it walks the grid in&lt;br&gt;
row-major order and, at every unclaimed cell, tries each L-shape that would cover&lt;br&gt;
it.&lt;/p&gt;

&lt;p&gt;They disagreed on a board the generator had just produced — the propagator said&lt;br&gt;
one answer, the scanner said two. The cause was a &lt;strong&gt;stale index&lt;/strong&gt;. The &lt;code&gt;cover&lt;/code&gt;&lt;br&gt;
rung builds a table of how many of each circle's survivors reach each cell, then&lt;br&gt;
sweeps the cells killing candidates, and the first version kept sweeping on the&lt;br&gt;
table it had built &lt;em&gt;before&lt;/em&gt; the kills. A stale count compared against a fresh&lt;br&gt;
survivor count reads as "every survivor of this circle covers this cell" when it&lt;br&gt;
no longer does, which evicts other circles from a cell they were entitled to and&lt;br&gt;
silently deletes real answers. The rung now returns the moment it kills anything,&lt;br&gt;
so the caller rebuilds the table.&lt;/p&gt;

&lt;p&gt;The test suite keeps a soundness property for it: for random boards, &lt;strong&gt;every cell&lt;br&gt;
the propagator pins to an owner must really have that owner in every answer the&lt;br&gt;
scanner finds&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Every circle is given and every circle is a bend, so the unknown in Sashigane
is only how far the arms reach.&lt;/li&gt;
&lt;li&gt;The arrow sits at an end and points home, so it specifies &lt;strong&gt;one whole arm&lt;/strong&gt;.
Add the number and the candidate set collapses to &lt;strong&gt;at most two shapes&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;A board with every number printed was unique in all 33,896 exhaustive cases and
in every random case up to 10×10. Erasing the numbers is what makes it a
puzzle.&lt;/li&gt;
&lt;li&gt;In the ablation, the &lt;strong&gt;arrow's position outweighs its direction ten to one&lt;/strong&gt; —
the opposite of where the rule statement puts its emphasis.&lt;/li&gt;
&lt;li&gt;The setter's only remaining freedom, which end each arrow goes on, moves the
uniqueness rate from 11.3% to 29.8% on a 12×12. A consistent convention always
beats a coin flip; which convention is best flips with the board size.&lt;/li&gt;
&lt;li&gt;The blank 3×3 cannot be cut into L-shapes at all. The 2×n counts are OEIS
A052537.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;TypeScript, no runtime dependencies, 68 tests. Every number here is reproducible&lt;br&gt;
with &lt;code&gt;npm run stats&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Demo: &lt;a href="https://sen.ltd/portfolio/sashigane/" rel="noopener noreferrer"&gt;https://sen.ltd/portfolio/sashigane/&lt;/a&gt;&lt;br&gt;
Repo: &lt;a href="https://github.com/sen-ltd/sashigane" rel="noopener noreferrer"&gt;https://github.com/sen-ltd/sashigane&lt;/a&gt;&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>algorithms</category>
      <category>gamedev</category>
      <category>puzzle</category>
    </item>
    <item>
      <title>Numberlink: colour the grid and the clues are constrained before you draw a single line</title>
      <dc:creator>SEN LLC</dc:creator>
      <pubDate>Fri, 04 Sep 2026 00:17:08 +0000</pubDate>
      <link>https://dev.to/sendotltd/numberlink-colour-the-grid-and-the-clues-are-constrained-before-you-draw-a-single-line-29bg</link>
      <guid>https://dev.to/sendotltd/numberlink-colour-the-grid-and-the-clues-are-constrained-before-you-draw-a-single-line-29bg</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Numberlink&lt;/strong&gt; in the browser with a &lt;strong&gt;four-rung solver&lt;/strong&gt;. What I look for in&lt;br&gt;
this series is something you can read off the board without solving it. This&lt;br&gt;
time it turned up in the &lt;em&gt;clue placement itself&lt;/em&gt;: checkerboard-colour the grid&lt;br&gt;
and one pass over the numbers tells you whether the board can have an answer&lt;br&gt;
at all. Puzzle #54 in the solver series.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Demo: &lt;a href="https://sen.ltd/portfolio/numberlink/" rel="noopener noreferrer"&gt;https://sen.ltd/portfolio/numberlink/&lt;/a&gt;&lt;br&gt;
Repo: &lt;a href="https://github.com/sen-ltd/numberlink" rel="noopener noreferrer"&gt;https://github.com/sen-ltd/numberlink&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fs5a4uyhdl2v0tlmdlkx8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fs5a4uyhdl2v0tlmdlkx8.png" alt="Numberlink" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Rules
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Join each pair of equal numbers with a path of orthogonally adjacent cells.&lt;/li&gt;
&lt;li&gt;No two paths share a cell, and no path crosses itself.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Every cell of the grid is used.&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Rule 3 is Nikoli's, and a lot of connect-the-dots games drop it. There is also a&lt;br&gt;
convention that no path ever &lt;em&gt;runs alongside itself&lt;/em&gt; — two cells of one path&lt;br&gt;
that touch on the grid are consecutive on that path. That one is normally&lt;br&gt;
presented as a matter of taste. I measured it. It is not a matter of taste.&lt;/p&gt;
&lt;h2&gt;
  
  
  The identity that only mentions the clues
&lt;/h2&gt;

&lt;p&gt;Colour the grid like a checkerboard: cell &lt;code&gt;(r, c)&lt;/code&gt; is dark when &lt;code&gt;r + c&lt;/code&gt; is even.&lt;/p&gt;

&lt;p&gt;A path steps one cell at a time, so it &lt;strong&gt;alternates colours&lt;/strong&gt;. For a path of &lt;code&gt;m&lt;/code&gt;&lt;br&gt;
cells:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;the path's two ends&lt;/th&gt;
&lt;th&gt;length&lt;/th&gt;
&lt;th&gt;dark − light&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;both dark&lt;/td&gt;
&lt;td&gt;odd&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;+1&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;both light&lt;/td&gt;
&lt;td&gt;odd&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;−1&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;different colours&lt;/td&gt;
&lt;td&gt;even&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;In a solution the paths cover every cell of the grid. So summing those &lt;code&gt;±1&lt;/code&gt;s&lt;br&gt;
over all the paths has to give the board's own imbalance — and what is left is&lt;br&gt;
an equation that never mentions a path:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;#(pairs with both ends dark) − #(pairs with both ends light) =&lt;br&gt;
(dark cells) − (light cells)&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The right-hand side is fixed by &lt;code&gt;h&lt;/code&gt; and &lt;code&gt;w&lt;/code&gt; alone: &lt;code&gt;0&lt;/code&gt; when the area is even,&lt;br&gt;
&lt;code&gt;1&lt;/code&gt; when it is odd. So:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;On any even-area board, the numbers whose two ends share the dark colour must&lt;br&gt;
be exactly as many as those sharing the light colour.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You check that in one pass over the clues. No search, no partial solution,&lt;br&gt;
nothing to back out of. The implementation is about twenty lines (&lt;code&gt;parityOf&lt;/code&gt; in&lt;br&gt;
&lt;code&gt;src/numberlink.ts&lt;/code&gt;), and the demo page runs the tally live in a panel next to&lt;br&gt;
the board.&lt;/p&gt;

&lt;p&gt;The test suite verifies the identity against &lt;strong&gt;every&lt;/strong&gt; partition of the 3×4 and&lt;br&gt;
4×4 grids — 102,749 of them, zero violations — on every run. &lt;code&gt;npm run stats&lt;/code&gt;&lt;br&gt;
extends it to 2×3, 3×3 and 3×5 for 137,789 in total.&lt;/p&gt;
&lt;h2&gt;
  
  
  Necessary, and not sufficient. The witness is 2×3
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;. 1 .
. 1 .
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The two &lt;code&gt;1&lt;/code&gt;s are on cells of different colours, so the count balances. There is&lt;br&gt;
still no answer. Whichever way you leave the top middle cell you strand a&lt;br&gt;
corner, and a corner has only two neighbours, so it cannot be an &lt;em&gt;interior&lt;/em&gt; cell&lt;br&gt;
of any path — interior cells need degree two and a stranded corner is a dead&lt;br&gt;
end.&lt;/p&gt;

&lt;p&gt;Give a board exactly one pair and the puzzle collapses into a classical&lt;br&gt;
question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Is there a Hamiltonian path between these two cells?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;One path using every cell &lt;em&gt;is&lt;/em&gt; a Hamiltonian path, and the colour count above is&lt;br&gt;
exactly the classical colour condition on grid graphs. Enumerating every&lt;br&gt;
single-pair placement:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;board&lt;/th&gt;
&lt;th&gt;balance, solvable&lt;/th&gt;
&lt;th&gt;balance, no answer&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;2×2&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2×3&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2×4&lt;/td&gt;
&lt;td&gt;14&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2×5&lt;/td&gt;
&lt;td&gt;22&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3×3&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3×4&lt;/td&gt;
&lt;td&gt;29&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3×5&lt;/td&gt;
&lt;td&gt;28&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4×4&lt;/td&gt;
&lt;td&gt;64&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The interesting part is that it is &lt;strong&gt;not monotone&lt;/strong&gt;. 2×3 has a witness and 3×3&lt;br&gt;
has none; 3×4 has seven and both 3×5 and 4×4 have none. The gap is a function of&lt;br&gt;
the board's shape, not its size.&lt;/p&gt;
&lt;h2&gt;
  
  
  The convention turns out to be nearly all of the uniqueness
&lt;/h2&gt;

&lt;p&gt;Generation in this series runs backwards: cut the grid into paths first, then&lt;br&gt;
write a number on each path's two ends. Every board produced that way&lt;br&gt;
&lt;strong&gt;already has an answer&lt;/strong&gt; by construction — the only question is whether it has&lt;br&gt;
more than one.&lt;/p&gt;

&lt;p&gt;So I sampled partitions and measured how often the board is unique:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;board&lt;/th&gt;
&lt;th&gt;partitions sampled&lt;/th&gt;
&lt;th&gt;drawn without the convention&lt;/th&gt;
&lt;th&gt;with it&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;7×7&lt;/td&gt;
&lt;td&gt;800 each&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;0.0%&lt;/strong&gt; unique&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;72.8%&lt;/strong&gt; unique&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;9×9&lt;/td&gt;
&lt;td&gt;300 each&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;0.0%&lt;/strong&gt; unique&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;58.7%&lt;/strong&gt; unique&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Zero out of 800, against 583 out of 800.&lt;/p&gt;

&lt;p&gt;There is a confound, and it is worth naming rather than hiding: taut paths grow&lt;br&gt;
less far, so they are shorter, so a taut partition leaves &lt;em&gt;more pairs&lt;/em&gt; — and&lt;br&gt;
boards with more pairs are easier to pin down. So I bucketed by pair count and&lt;br&gt;
compared inside each bucket:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;pairs&lt;/th&gt;
&lt;th&gt;loose&lt;/th&gt;
&lt;th&gt;taut&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;0.1% of 1274&lt;/td&gt;
&lt;td&gt;40.0% of 55&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;0.0% of 1079&lt;/td&gt;
&lt;td&gt;54.8% of 301&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;0.4% of 571&lt;/td&gt;
&lt;td&gt;72.4% of 909&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;0.9% of 229&lt;/td&gt;
&lt;td&gt;85.3% of 1153&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;1.3% of 77&lt;/td&gt;
&lt;td&gt;89.9% of 936&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The effect survives intact. This is also the only reason a 9×9 bank exists in&lt;br&gt;
this repository at all: before the sampler enforced tautness, four thousand&lt;br&gt;
draws produced zero unique boards.&lt;/p&gt;
&lt;h2&gt;
  
  
  Four rungs, and one of them never fires
&lt;/h2&gt;

&lt;p&gt;The solver does not think in paths. It assigns ON / OFF / undecided to the&lt;br&gt;
&lt;code&gt;h(w−1) + (h−1)w&lt;/code&gt; &lt;strong&gt;segments between cells&lt;/strong&gt;, which splits the puzzle into two&lt;br&gt;
constraints that look nothing alike:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;degree&lt;/strong&gt; — a numbered cell has exactly one ON segment, every other cell
exactly two.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;shape&lt;/strong&gt; — the ON subgraph is a forest of paths, and each path's two ends
carry the same number.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Rule 3 — "every cell is used" — disappears entirely into the degree line. A cell&lt;br&gt;
with degree two is on somebody's path by construction. Collapsing the rule that&lt;br&gt;
defines the puzzle into one clause was the nicest part of the build.&lt;/p&gt;

&lt;p&gt;The rungs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;deg&lt;/code&gt;&lt;/strong&gt; — degree counting only.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;chain&lt;/code&gt;&lt;/strong&gt; — union-find over the ON components; turn off any segment that
would close a loop or weld two different numbers onto one path.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;reach&lt;/code&gt;&lt;/strong&gt; — connectivity: both ends of every number must still be able to
meet, and no region may be sealed off with no complete pair inside it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;probe&lt;/code&gt;&lt;/strong&gt; — try each undecided segment both ways, keep whichever survives.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Decided from a blank slate:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;board&lt;/th&gt;
&lt;th&gt;&lt;code&gt;deg&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;chain&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;reach&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;probe&lt;/code&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;7×7&lt;/td&gt;
&lt;td&gt;8.4%&lt;/td&gt;
&lt;td&gt;76.7%&lt;/td&gt;
&lt;td&gt;76.7%&lt;/td&gt;
&lt;td&gt;100%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;9×9&lt;/td&gt;
&lt;td&gt;4.5%&lt;/td&gt;
&lt;td&gt;53.6%&lt;/td&gt;
&lt;td&gt;53.6%&lt;/td&gt;
&lt;td&gt;100%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Branch points to prove uniqueness, summed over the bank:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;board&lt;/th&gt;
&lt;th&gt;&lt;code&gt;deg&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;chain&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;reach&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;probe&lt;/code&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;7×7, 40 boards&lt;/td&gt;
&lt;td&gt;3,306,784 *&lt;/td&gt;
&lt;td&gt;172&lt;/td&gt;
&lt;td&gt;172&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;9×9, 36 boards&lt;/td&gt;
&lt;td&gt;10,800,036 *&lt;/td&gt;
&lt;td&gt;2,827&lt;/td&gt;
&lt;td&gt;2,827&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;* one 7×7 board and all 36 9×9 boards hit a 300,000-branch cap, so the &lt;code&gt;deg&lt;/code&gt;&lt;br&gt;
row is a lower bound.&lt;/p&gt;

&lt;p&gt;Look at the &lt;code&gt;reach&lt;/code&gt; column. It is &lt;strong&gt;identical&lt;/strong&gt; to &lt;code&gt;chain&lt;/code&gt; — same decided&lt;br&gt;
fraction, same branch count, digit for digit. Across &lt;strong&gt;2,488 comparisons&lt;/strong&gt;&lt;br&gt;
(blank slates, partly-drawn boards, shipped boards, random boards) &lt;code&gt;reach&lt;/code&gt; has&lt;br&gt;
never once reached a different conclusion than &lt;code&gt;chain&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I added &lt;code&gt;reach&lt;/code&gt; because it looked obviously useful. It is not. I have no proof&lt;br&gt;
that degree counting plus loop avoidance implies connectivity here, so this goes&lt;br&gt;
in as a measurement rather than a theorem — and the rung stays in the ladder and&lt;br&gt;
in the demo's dropdown, because a rung that never fires is part of the result.&lt;/p&gt;
&lt;h2&gt;
  
  
  Dropping "every cell is used" changes almost nothing
&lt;/h2&gt;

&lt;p&gt;Rule 3 is what makes Numberlink a puzzle rather than a maze, so removing it&lt;br&gt;
ought to blow the answer count up. It does not:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;board&lt;/th&gt;
&lt;th&gt;still unique without rule 3&lt;/th&gt;
&lt;th&gt;median routings&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;7×7&lt;/td&gt;
&lt;td&gt;36 / 40&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;9×9&lt;/td&gt;
&lt;td&gt;31 / 36&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Nine boards in ten are already unique when read as "just join the pairs, empty&lt;br&gt;
cells are fine". The rule that defines the puzzle is nearly redundant by the&lt;br&gt;
time these particular boards reach you.&lt;/p&gt;

&lt;p&gt;That is a fact about the generator, not about Numberlink. Boards grown from taut&lt;br&gt;
partitions are heavily over-determined; they are nowhere near the edge of&lt;br&gt;
uniqueness. It is the 0%-versus-72.8% result seen from the other side. A board&lt;br&gt;
that only just manages to be unique under the full rules would fall apart the&lt;br&gt;
moment you dropped rule 3.&lt;/p&gt;
&lt;h2&gt;
  
  
  Generation: answer first, then repair
&lt;/h2&gt;

&lt;p&gt;Cutting the grid into taut paths first means an illegal board is unreachable —&lt;br&gt;
"every cell is used" is precisely what a partition &lt;em&gt;is&lt;/em&gt;. No rule ever needs&lt;br&gt;
checking afterwards. Only uniqueness needs a search.&lt;/p&gt;

&lt;p&gt;And Numberlink has no "add a hint" move. The clues &lt;strong&gt;are&lt;/strong&gt; the path ends, so&lt;br&gt;
adding a number means changing the shape of the answer. When a board comes out&lt;br&gt;
ambiguous the generator therefore does not resample. It repairs:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;take two answers;&lt;/li&gt;
&lt;li&gt;list the cells where they disagree;&lt;/li&gt;
&lt;li&gt;cut the path running through one of them in two — which adds exactly one pair;&lt;/li&gt;
&lt;li&gt;repeat until unique.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Aiming the cut at the disagreement kills the intruder without scattering extra&lt;br&gt;
numbers across the board.&lt;/p&gt;
&lt;h2&gt;
  
  
  Counting the grids themselves
&lt;/h2&gt;

&lt;p&gt;Forget the numbers: how many ways does an &lt;code&gt;h × w&lt;/code&gt; grid fall apart into paths of&lt;br&gt;
two or more cells?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2xn: 1, 6, 26, 118, 528, 2364, 10580, 47352, 211928, 948504, 4245120, 18999440
3xn: 1, 26, 242, 3113, 34772, 412016, 4758383
4xn: 2, 118, 3113, 99636, 2993923
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;None of the three is in OEIS (searched 2026-09-04). The 2×n row satisfies&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;a(n) = 5a(n−1) − 2a(n−2) − 2a(n−3) + 2a(n−4)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;for every term computed. It was fitted on four terms, so four of the eight&lt;br&gt;
checks are genuine predictions — but there is no proof here, only the fit.&lt;/p&gt;
&lt;h2&gt;
  
  
  The bug that inverted a conclusion
&lt;/h2&gt;

&lt;p&gt;The scariest bug in the build was in the routine that counts routings with rule&lt;br&gt;
3 switched off. It pulled its four-element neighbour buffer from a pool indexed&lt;br&gt;
by path length:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;   &lt;span class="c1"&gt;// ← here&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;neighbors&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cur&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When one pair finishes, the next pair restarts &lt;strong&gt;at length 1&lt;/strong&gt; — and overwrites&lt;br&gt;
&lt;code&gt;buf[1]&lt;/code&gt; while an ancestor frame (the first pair, back when &lt;em&gt;it&lt;/em&gt; was at length 1)&lt;br&gt;
is still iterating over it. Routings get skipped.&lt;/p&gt;

&lt;p&gt;Measured with that bug in place, the first numbers said 6 of 40 boards were&lt;br&gt;
unique without rule 3, with a median of 14.5 routings. That is the exact&lt;br&gt;
&lt;em&gt;opposite&lt;/em&gt; of the section above: it said the fill rule was carrying the&lt;br&gt;
uniqueness. A whole section of this article was written backwards and had to be&lt;br&gt;
thrown away.&lt;/p&gt;

&lt;p&gt;No puzzle-level test catches this. Does the board solve? Yes. Is the answer&lt;br&gt;
unique? Yes. What caught it was the most boring assertion in the suite, the one&lt;br&gt;
I nearly did not bother writing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;is at least as generous as the full puzzle&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// every answer with the fill rule is also an answer without it&lt;/span&gt;
  &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;without&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBeGreaterThanOrEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;withFill&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Removing a constraint reduced the number of solutions. Allocating a fresh&lt;br&gt;
four-element array per frame fixed it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two engines
&lt;/h2&gt;

&lt;p&gt;Everything above is cross-checked by two solvers that share no code. One assigns&lt;br&gt;
ON/OFF to segments and propagates degrees and connectivity. The other never&lt;br&gt;
mentions a segment: it cuts the grid into paths directly, anchoring on the&lt;br&gt;
lowest free cell, and keeps the cuts whose pieces happen to be numbered&lt;br&gt;
correctly. They agree on the answer count for 400 random boards on 3×3 through&lt;br&gt;
4×4, and on which parity-impossible placements have no answer at all.&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The checkerboard argument gives an identity that &lt;strong&gt;closes on the clue
placement alone&lt;/strong&gt; — board feasibility without any search.&lt;/li&gt;
&lt;li&gt;Necessary, not sufficient; the witness is &lt;strong&gt;2×3&lt;/strong&gt;, and a one-pair board is
exactly a Hamiltonian path problem.&lt;/li&gt;
&lt;li&gt;The "no path runs alongside itself" convention decides &lt;strong&gt;almost all&lt;/strong&gt; of the
uniqueness — 0% against 72.8%, and it survives fixing the pair count.&lt;/li&gt;
&lt;li&gt;The connectivity rung &lt;strong&gt;never fired&lt;/strong&gt; in 2,488 comparisons. No proof, so it
ships as a measurement.&lt;/li&gt;
&lt;li&gt;"Every cell is used" is nearly redundant on these boards — which says more
about the generator than about the puzzle.&lt;/li&gt;
&lt;li&gt;74 tests, and the boring inequality test is the one that earned its keep.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Demo: &lt;a href="https://sen.ltd/portfolio/numberlink/" rel="noopener noreferrer"&gt;https://sen.ltd/portfolio/numberlink/&lt;/a&gt;&lt;br&gt;
Repo: &lt;a href="https://github.com/sen-ltd/numberlink" rel="noopener noreferrer"&gt;https://github.com/sen-ltd/numberlink&lt;/a&gt;&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>algorithms</category>
      <category>gamedev</category>
      <category>puzzle</category>
    </item>
    <item>
      <title>Stostone: the rule says drop the stones — and nothing ever has to move</title>
      <dc:creator>SEN LLC</dc:creator>
      <pubDate>Thu, 03 Sep 2026 00:16:47 +0000</pubDate>
      <link>https://dev.to/sendotltd/stostone-the-rule-says-drop-the-stones-and-nothing-ever-has-to-move-4326</link>
      <guid>https://dev.to/sendotltd/stostone-the-rule-says-drop-the-stones-and-nothing-ever-has-to-move-4326</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Stostone&lt;/strong&gt; in the browser with a &lt;strong&gt;five-rung solver&lt;/strong&gt;. The headline rule is&lt;br&gt;
written as physics — drop the stones, they must fill the bottom half — and it&lt;br&gt;
is not physics at all. It is a per-column count plus one invariant, and both&lt;br&gt;
can be checked without moving anything. Puzzle #53 in the solver series.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Demo: &lt;a href="https://sen.ltd/portfolio/stostone/" rel="noopener noreferrer"&gt;https://sen.ltd/portfolio/stostone/&lt;/a&gt;&lt;br&gt;
Repo: &lt;a href="https://github.com/sen-ltd/stostone" rel="noopener noreferrer"&gt;https://github.com/sen-ltd/stostone&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsen.ltd%2Fportfolio%2Fstostone%2Fassets%2Fscreenshot.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsen.ltd%2Fportfolio%2Fstostone%2Fassets%2Fscreenshot.png" alt="Stostone" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Rules
&lt;/h2&gt;

&lt;p&gt;The board is &lt;code&gt;H×W&lt;/code&gt; with &lt;code&gt;H&lt;/code&gt; even, and it is cut into regions.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Shade some cells. The shaded cells of each region form exactly one connected
group — a &lt;strong&gt;stone&lt;/strong&gt; — and every region has one.&lt;/li&gt;
&lt;li&gt;Two stones may not touch.&lt;/li&gt;
&lt;li&gt;A number in a region gives the size of that region's stone.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Drop the stones straight down, each one rigid. They must come to rest
exactly filling the bottom half of the board.&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Rule 4 is the reason the puzzle exists. It is also the only rule in this whole&lt;br&gt;
series of genre implementations that is stated as a &lt;em&gt;process&lt;/em&gt;: do a thing, then&lt;br&gt;
look at the result. Every other pencil puzzle states a property of the grid in&lt;br&gt;
front of you. So the first question is whether the process is really necessary.&lt;/p&gt;

&lt;p&gt;It is not.&lt;/p&gt;
&lt;h2&gt;
  
  
  The counting half
&lt;/h2&gt;

&lt;p&gt;Falling moves cells vertically. It cannot change how many shaded cells a column&lt;br&gt;
holds. And "the bottom half is exactly full" says every column &lt;em&gt;ends&lt;/em&gt; with&lt;br&gt;
&lt;code&gt;H/2&lt;/code&gt; shaded cells. Therefore:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Every column starts with exactly &lt;code&gt;H/2&lt;/code&gt; shaded cells.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A statement about a configuration nobody has computed yet is really a local&lt;br&gt;
count on the one in front of you. That is one line of code and it is the whole&lt;br&gt;
&lt;code&gt;col&lt;/code&gt; rung of the solver.&lt;/p&gt;
&lt;h2&gt;
  
  
  The rest of it
&lt;/h2&gt;

&lt;p&gt;Number the shaded cells of a column from the bottom. The one with &lt;code&gt;b&lt;/code&gt; blanks&lt;br&gt;
under it has to land on row &lt;code&gt;H−1−b&lt;/code&gt;, so it wants to travel &lt;code&gt;H−1−b−r&lt;/code&gt;. A stone&lt;br&gt;
is rigid — every one of its cells travels the same distance — so:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;blankBelow(r, c)&lt;/code&gt; is the same for every cell of a stone, and that common&lt;br&gt;
value is exactly how far the stone falls.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is the entirety of rule 4, with no simulation in it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;packsByRank&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;h&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cells&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Int8Array&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nf"&gt;columnsBalanced&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;h&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cells&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;below&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Int32Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;h&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;seen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;h&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;below&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;w&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;seen&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cells&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;w&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;BLACK&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;seen&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;comp&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nf"&gt;blackComponents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;h&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cells&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;k&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;comp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;below&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There is a second thing hiding here, which is that "drop the stones" is not&lt;br&gt;
obviously well defined at all. Which stone falls first? Does the answer depend&lt;br&gt;
on the order? It does not, and the reason is worth stating: two stones sharing a&lt;br&gt;
column impose &lt;code&gt;d_i − d_j ≤ gap&lt;/code&gt; on their displacements, a system of difference&lt;br&gt;
constraints is closed under componentwise maximum, so a unique maximal solution&lt;br&gt;
exists and any greedy schedule reaches it. The repository simulates the fall&lt;br&gt;
twice on two different schedules — one row at a time for everything at once, one&lt;br&gt;
stone at a time all the way down — and checks both against the invariant that&lt;br&gt;
does not simulate it. On every grid the tests can enumerate exhaustively, all&lt;br&gt;
three agree.&lt;/p&gt;
&lt;h2&gt;
  
  
  The corollary you can see
&lt;/h2&gt;

&lt;p&gt;Apply the invariant to two cells of one stone in the same column, &lt;code&gt;r &amp;lt; r'&lt;/code&gt;. With&lt;br&gt;
&lt;code&gt;B&lt;/code&gt; shaded cells strictly between them, &lt;code&gt;blankBelow(r,c) = blankBelow(r',c) +&lt;br&gt;
(r' − r − 1 − B)&lt;/code&gt;, and the invariant forces &lt;code&gt;B = r' − r − 1&lt;/code&gt; — all of them. So:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;A stone never has a vertical hole.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That gives three nested readings of rule 4:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;count&lt;/code&gt;: every column carries &lt;code&gt;H/2&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;convex&lt;/code&gt;: that, plus no stone has a vertical hole.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;exact&lt;/code&gt;: the real thing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All three ship as switchable rule sets, which is what makes the next section&lt;br&gt;
possible.&lt;/p&gt;
&lt;h2&gt;
  
  
  Counting is necessary and is not sufficient
&lt;/h2&gt;

&lt;p&gt;The smallest witness is 4×3. Every column carries 2 of 4, neither stone has a&lt;br&gt;
vertical hole, and the arch still comes to rest one row high, because its middle&lt;br&gt;
prong lands on the cell underneath:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# . #        . . .
# # #   ↓    # . #
. . .        # # #
. # .        . # .
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Counting the region-free grids — no regions, no numbers, just the shadings an&lt;br&gt;
&lt;code&gt;H×W&lt;/code&gt; board admits — puts numbers on the gap. &lt;code&gt;count&lt;/code&gt; has the closed form&lt;br&gt;
&lt;code&gt;C(H, H/2)^W&lt;/code&gt;; the other two were enumerated by walking only the balanced grids.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;board&lt;/th&gt;
&lt;th&gt;&lt;code&gt;exact&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;convex&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;count&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;exact/count&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;2×n&lt;/td&gt;
&lt;td&gt;2ⁿ&lt;/td&gt;
&lt;td&gt;2ⁿ&lt;/td&gt;
&lt;td&gt;2ⁿ&lt;/td&gt;
&lt;td&gt;100.0%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4×2&lt;/td&gt;
&lt;td&gt;28&lt;/td&gt;
&lt;td&gt;36&lt;/td&gt;
&lt;td&gt;36&lt;/td&gt;
&lt;td&gt;77.8%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4×4&lt;/td&gt;
&lt;td&gt;640&lt;/td&gt;
&lt;td&gt;1,296&lt;/td&gt;
&lt;td&gt;1,296&lt;/td&gt;
&lt;td&gt;49.4%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4×10&lt;/td&gt;
&lt;td&gt;7,618,204&lt;/td&gt;
&lt;td&gt;60,466,176&lt;/td&gt;
&lt;td&gt;60,466,176&lt;/td&gt;
&lt;td&gt;12.6%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6×2&lt;/td&gt;
&lt;td&gt;226&lt;/td&gt;
&lt;td&gt;376&lt;/td&gt;
&lt;td&gt;400&lt;/td&gt;
&lt;td&gt;56.5%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6×4&lt;/td&gt;
&lt;td&gt;31,820&lt;/td&gt;
&lt;td&gt;133,760&lt;/td&gt;
&lt;td&gt;160,000&lt;/td&gt;
&lt;td&gt;19.9%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6×6&lt;/td&gt;
&lt;td&gt;4,482,592&lt;/td&gt;
&lt;td&gt;47,582,864&lt;/td&gt;
&lt;td&gt;64,000,000&lt;/td&gt;
&lt;td&gt;7.0%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8×2&lt;/td&gt;
&lt;td&gt;1,940&lt;/td&gt;
&lt;td&gt;4,248&lt;/td&gt;
&lt;td&gt;4,900&lt;/td&gt;
&lt;td&gt;39.6%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8×4&lt;/td&gt;
&lt;td&gt;1,717,396&lt;/td&gt;
&lt;td&gt;15,963,452&lt;/td&gt;
&lt;td&gt;24,010,000&lt;/td&gt;
&lt;td&gt;7.2%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Two edges of that table are provable and both come out right. On a &lt;strong&gt;two-row&lt;/strong&gt;&lt;br&gt;
board the three readings coincide: a stone straddling a gap would need three&lt;br&gt;
shaded cells in a column and there are only two, so &lt;code&gt;exact = 2^W&lt;/code&gt; exactly. A&lt;br&gt;
&lt;strong&gt;single column&lt;/strong&gt; packs whenever it is balanced, so &lt;code&gt;exact = C(H, H/2)&lt;/code&gt;. Column&lt;br&gt;
convexity is likewise vacuous at four rows — the &lt;code&gt;convex&lt;/code&gt; and &lt;code&gt;count&lt;/code&gt; columns&lt;br&gt;
are identical for every 4×n — and only starts costing anything at six rows.&lt;/p&gt;

&lt;p&gt;The 4×n counts are 6, 28, 134, 640, 3058, 14612, 69822, 333640, 1594282,&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;They are not in OEIS. They do satisfy
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;a(n) = 6·a(n−1) − 5·a(n−2) − 4·a(n−3)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;for every term computed — fitted from the first three and confirmed by the next&lt;br&gt;
seven. A transfer matrix of that width would be the proof; this repository does&lt;br&gt;
not have one, and the README says so.&lt;/p&gt;

&lt;h2&gt;
  
  
  The half that cannot open a board is the half you cannot do without
&lt;/h2&gt;

&lt;p&gt;The solver is a five-rung ladder: &lt;code&gt;col&lt;/code&gt; (the counting half of rule 4), &lt;code&gt;clue&lt;/code&gt;&lt;br&gt;
(the numbers, one stone per region, stones apart, reachability), &lt;code&gt;fit&lt;/code&gt; (list&lt;br&gt;
every way a region's stone could still be drawn and keep what they agree on),&lt;br&gt;
&lt;code&gt;drop&lt;/code&gt; (the invariant and its corollary), &lt;code&gt;probe&lt;/code&gt; (singleton consistency).&lt;/p&gt;

&lt;p&gt;Run each rung on its own, cumulatively, from an empty grid, over the 77 shipped&lt;br&gt;
boards:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;size&lt;/th&gt;
&lt;th&gt;&lt;code&gt;col&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;clue&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;fit&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;drop&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;probe&lt;/code&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;6×6&lt;/td&gt;
&lt;td&gt;0.0%&lt;/td&gt;
&lt;td&gt;37.9%&lt;/td&gt;
&lt;td&gt;75.4%&lt;/td&gt;
&lt;td&gt;78.5%&lt;/td&gt;
&lt;td&gt;100.0%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8×8&lt;/td&gt;
&lt;td&gt;0.0%&lt;/td&gt;
&lt;td&gt;11.7%&lt;/td&gt;
&lt;td&gt;26.2%&lt;/td&gt;
&lt;td&gt;28.5%&lt;/td&gt;
&lt;td&gt;100.0%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;col&lt;/code&gt; settles &lt;strong&gt;nothing&lt;/strong&gt;. It is pure saturation — it can finish a column, and&lt;br&gt;
at the start no column is finished either way. It cannot open a board. But&lt;br&gt;
attribute every cell the full stack writes to the rung that wrote it:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;size&lt;/th&gt;
&lt;th&gt;boards&lt;/th&gt;
&lt;th&gt;&lt;code&gt;col&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;clue&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;fit&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;drop&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;probe&lt;/code&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;6×6&lt;/td&gt;
&lt;td&gt;44&lt;/td&gt;
&lt;td&gt;19.5%&lt;/td&gt;
&lt;td&gt;37.8%&lt;/td&gt;
&lt;td&gt;31.1%&lt;/td&gt;
&lt;td&gt;5.5%&lt;/td&gt;
&lt;td&gt;6.1%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8×8&lt;/td&gt;
&lt;td&gt;33&lt;/td&gt;
&lt;td&gt;14.6%&lt;/td&gt;
&lt;td&gt;29.2%&lt;/td&gt;
&lt;td&gt;22.1%&lt;/td&gt;
&lt;td&gt;7.9%&lt;/td&gt;
&lt;td&gt;26.2%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Give it one cell from anywhere else and it writes about a sixth of the board.&lt;br&gt;
And take each rung out of the full stack:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;variant&lt;/th&gt;
&lt;th&gt;settled&lt;/th&gt;
&lt;th&gt;finish without guessing&lt;/th&gt;
&lt;th&gt;assumptions&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;all rungs&lt;/td&gt;
&lt;td&gt;100.0%&lt;/td&gt;
&lt;td&gt;77/77&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;− &lt;code&gt;col&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;48.8%&lt;/td&gt;
&lt;td&gt;1/77&lt;/td&gt;
&lt;td&gt;350,027&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;− &lt;code&gt;clue&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;98.6%&lt;/td&gt;
&lt;td&gt;75/77&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;− &lt;code&gt;fit&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;90.1%&lt;/td&gt;
&lt;td&gt;67/77&lt;/td&gt;
&lt;td&gt;47&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;− &lt;code&gt;drop&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;76.1%&lt;/td&gt;
&lt;td&gt;36/77&lt;/td&gt;
&lt;td&gt;4,917&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Without probing on top the same order holds: 593,084 assumptions without &lt;code&gt;col&lt;/code&gt;,&lt;br&gt;
14,306 without &lt;code&gt;drop&lt;/code&gt;. &lt;strong&gt;The half of rule 4 that cannot open a board is 71 times&lt;br&gt;
the more expensive half to do without.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Now ablate rule 4 as a &lt;em&gt;rule of the puzzle&lt;/em&gt; instead of as an inference, and the&lt;br&gt;
picture turns over. Here the arithmetic half is the one that is not enough:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;size&lt;/th&gt;
&lt;th&gt;&lt;code&gt;exact&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;convex&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;count&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;none&lt;/code&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;6×6&lt;/td&gt;
&lt;td&gt;44/44&lt;/td&gt;
&lt;td&gt;34/44&lt;/td&gt;
&lt;td&gt;34/44&lt;/td&gt;
&lt;td&gt;0/44&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8×8&lt;/td&gt;
&lt;td&gt;33/33&lt;/td&gt;
&lt;td&gt;2/33&lt;/td&gt;
&lt;td&gt;2/33&lt;/td&gt;
&lt;td&gt;0/33&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;At 6×6, weakening the real rule to counting costs 10 of the 44 boards their&lt;br&gt;
unique answer — and adding convexity back buys none of them; exactly the same 10&lt;br&gt;
fall either way. At 8×8, 31 of the 33 lose uniqueness under both, with a median&lt;br&gt;
of 37 answers where there had been one. On the shipped 6×6 region maps, counting&lt;br&gt;
alone admits 8,081 answers where the real rule admits 2,870: &lt;strong&gt;35.5%&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;So the two halves are not two smaller versions of the same rule. One does almost&lt;br&gt;
all of the deducing and none of the disambiguating; the other does almost none&lt;br&gt;
of the deducing and all of the disambiguating.&lt;/p&gt;

&lt;h2&gt;
  
  
  The clue language, and what it cannot say
&lt;/h2&gt;

&lt;p&gt;A number lives in a region and gives that region's stone size, so the entire&lt;br&gt;
clue language is the vector &lt;em&gt;region ↦ size&lt;/em&gt;. The strongest clue set that exists&lt;br&gt;
is a number in every region. So an answer can be pinned down &lt;strong&gt;iff&lt;/strong&gt; it is the&lt;br&gt;
only legal grid with its size vector — and that fails a lot:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;board&lt;/th&gt;
&lt;th&gt;stones aimed at&lt;/th&gt;
&lt;th&gt;pinned by every number&lt;/th&gt;
&lt;th&gt;median answers&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;6×6&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;57.1%&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6×6&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;32.7%&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6×6&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;20.6%&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8×8&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;50.0%&lt;/td&gt;
&lt;td&gt;1.5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8×8&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;33.3%&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Fewer, larger stones means fewer regions means a shorter vector, and the vector&lt;br&gt;
runs out of things to say. This is the one measurement here that the shipped&lt;br&gt;
boards &lt;em&gt;cannot&lt;/em&gt; provide, because the generator draws the stones first and the&lt;br&gt;
region map second, and simply redraws the map until the full number set does pin&lt;br&gt;
the answer. Measuring the rate on the boards it kept would be measuring its own&lt;br&gt;
filter. So it is measured separately with the filter switched off, and the&lt;br&gt;
README says which is which.&lt;/p&gt;

&lt;p&gt;Once a board is pinnable, very few numbers are needed: 2.6 of 9.5 regions at&lt;br&gt;
6×6, 5.3 of 11.5 at 8×8.&lt;/p&gt;

&lt;h2&gt;
  
  
  Generation runs backwards
&lt;/h2&gt;

&lt;p&gt;Every legal position is a bottom half packed solid, cut into connected pieces,&lt;br&gt;
and lifted. That is the invariant read right to left, so the generator never has&lt;br&gt;
to reject an answer for failing rule 4:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Fill the bottom &lt;code&gt;H/2&lt;/code&gt; rows — what the stones must look like once they have
landed.&lt;/li&gt;
&lt;li&gt;Cut that block into connected pieces.&lt;/li&gt;
&lt;li&gt;Lift each piece. Two pieces sharing a column must keep their order, so the
upper lifts at least as far as the lower; those constraints form a DAG, and
the occasional cycle just means the two pieces would have to interleave and
the draw is thrown away.&lt;/li&gt;
&lt;li&gt;Refuse a lift that leaves two pieces touching — that fuses them into one
stone whose cells disagree about how far they want to fall.&lt;/li&gt;
&lt;li&gt;Grow the regions outwards from the stones, then buy numbers adversarially.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The one thing that is a search rather than a formula is step 4. The packed block&lt;br&gt;
is solid, so every pair of neighbouring pieces starts out touching and only the&lt;br&gt;
lift can separate them, and on a crowded 8×8 board most random lifts fail. So&lt;br&gt;
step 3 backtracks over lift values.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the answers look like
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;size&lt;/th&gt;
&lt;th&gt;stones&lt;/th&gt;
&lt;th&gt;mean stone&lt;/th&gt;
&lt;th&gt;mean fall&lt;/th&gt;
&lt;th&gt;stones that never move&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;6×6&lt;/td&gt;
&lt;td&gt;418&lt;/td&gt;
&lt;td&gt;1.89&lt;/td&gt;
&lt;td&gt;1.50&lt;/td&gt;
&lt;td&gt;21.5%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8×8&lt;/td&gt;
&lt;td&gt;381&lt;/td&gt;
&lt;td&gt;2.77&lt;/td&gt;
&lt;td&gt;2.03&lt;/td&gt;
&lt;td&gt;17.1%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;About a fifth of all stones are already resting where they will end up. Those&lt;br&gt;
are free information: a stone with a blank under it in any column has a nonzero&lt;br&gt;
fall distance, and one that touches the floor pins its entire column below every&lt;br&gt;
one of its cells.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cross-checks
&lt;/h2&gt;

&lt;p&gt;Three engines that share no code have to agree: the propagating search, an&lt;br&gt;
enumerator that treats a grid as an integer and tries all of them, and one that&lt;br&gt;
picks each region's stone out of that region's connected subsets. Over 60 random&lt;br&gt;
4×4 region maps they agree on all 503 answers, and under every one of the four&lt;br&gt;
settings of rule 4.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;probe&lt;/code&gt; is sound but not complete. Over 876 clue prefixes it never once claimed&lt;br&gt;
to finish a board with more than one answer; three times a board had exactly one&lt;br&gt;
answer and it still needed a guess. The gap only ever points one way, as it has&lt;br&gt;
in every genre in this series.&lt;/p&gt;

&lt;h2&gt;
  
  
  The bug the cross-check caught
&lt;/h2&gt;

&lt;p&gt;The interesting failure was not in the puzzle logic. It was in the second&lt;br&gt;
simulation of the fall — the one that drops one stone all the way before moving&lt;br&gt;
to the next. It mixed two coordinate systems: the stone's cells were being&lt;br&gt;
updated in place as it fell, while the collision test still added the cumulative&lt;br&gt;
drop offset on top of them. On a board with one stone it is invisible. It only&lt;br&gt;
diverges when a stone lands on another stone, which is exactly the case the&lt;br&gt;
whole puzzle is about.&lt;/p&gt;

&lt;p&gt;Nothing in the puzzle-side tests would have caught it, because the puzzle side&lt;br&gt;
never calls it. It was caught by the property test that asserts the two&lt;br&gt;
schedules reach the same fixpoint — which exists because "the fall is&lt;br&gt;
order-independent" is a claim this repository makes, and a claim like that is&lt;br&gt;
worth a test whether or not you expect it to fail.&lt;/p&gt;

&lt;h2&gt;
  
  
  Running it
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install
&lt;/span&gt;npm run dev      &lt;span class="c"&gt;# the demo on localhost&lt;/span&gt;
npm &lt;span class="nb"&gt;test&lt;/span&gt;         &lt;span class="c"&gt;# 70 tests&lt;/span&gt;
npm run build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;MIT.&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>algorithms</category>
      <category>gamedev</category>
      <category>puzzle</category>
    </item>
    <item>
      <title>Choco Banana: the half of the rule that can only say no is six times the more expensive half</title>
      <dc:creator>SEN LLC</dc:creator>
      <pubDate>Wed, 02 Sep 2026 00:18:54 +0000</pubDate>
      <link>https://dev.to/sendotltd/choco-banana-the-half-of-the-rule-that-can-only-say-no-is-six-times-the-more-expensive-half-4j1j</link>
      <guid>https://dev.to/sendotltd/choco-banana-the-half-of-the-rule-that-can-only-say-no-is-six-times-the-more-expensive-half-4j1j</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Choco Banana&lt;/strong&gt; in the browser with &lt;strong&gt;five rule sets&lt;/strong&gt; inside. Every group of&lt;br&gt;
shaded cells must be a rectangle; every group of unshaded cells must not be.&lt;br&gt;
The same predicate, affirmed once and denied once — and the denied half turns&lt;br&gt;
out to be the one you cannot afford to lose. Puzzle #52 in the solver series.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Demo: &lt;a href="https://sen.ltd/portfolio/choco-banana/" rel="noopener noreferrer"&gt;https://sen.ltd/portfolio/choco-banana/&lt;/a&gt;&lt;br&gt;
Repo: &lt;a href="https://github.com/sen-ltd/choco-banana" rel="noopener noreferrer"&gt;https://github.com/sen-ltd/choco-banana&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1283m01jfx1wii57vu7n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1283m01jfx1wii57vu7n.png" alt="Choco Banana" width="800" height="538"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Rules
&lt;/h2&gt;

&lt;p&gt;Shade some cells of an &lt;code&gt;H×W&lt;/code&gt; grid.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Every orthogonally connected group of shaded cells &lt;strong&gt;is a rectangle&lt;/strong&gt; — a
chocolate bar.&lt;/li&gt;
&lt;li&gt;Every orthogonally connected group of unshaded cells &lt;strong&gt;is not a rectangle&lt;/strong&gt; —
a banana.&lt;/li&gt;
&lt;li&gt;A number in a cell gives the &lt;strong&gt;size of the group that cell belongs to&lt;/strong&gt;, and
says nothing at all about which colour that group is.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Rules 1 and 2 are the same predicate, affirmed once and denied once. Rule 3 hands&lt;br&gt;
you an area and withholds the colour. Those two asymmetries are the whole puzzle,&lt;br&gt;
and they are what this repository measures.&lt;/p&gt;
&lt;h2&gt;
  
  
  The two directions are not equivalent as inference
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;"Is a rectangle" is closed under bounding boxes.&lt;/strong&gt; Any set of shaded cells&lt;br&gt;
known to be in one group drags its entire bounding box in with it, so two shaded&lt;br&gt;
cells can fill a block. It &lt;em&gt;pushes&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"Is not a rectangle" is closed under nothing.&lt;/strong&gt; A banana that happens to be a&lt;br&gt;
rectangle right now is not yet illegal. It only becomes illegal once it is sealed&lt;br&gt;
shut and can no longer grow. So the rule cannot advance a position — it can only&lt;br&gt;
reject one, and only at the very last moment.&lt;/p&gt;

&lt;p&gt;Which makes the denied half look like the cheap half.&lt;/p&gt;

&lt;p&gt;It is not.&lt;/p&gt;

&lt;p&gt;Attribute every cell the solver writes to the rung that wrote it, over the 68&lt;br&gt;
shipped boards:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;size&lt;/th&gt;
&lt;th&gt;boards&lt;/th&gt;
&lt;th&gt;&lt;code&gt;value&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;rect&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;size&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;anti&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;probe&lt;/code&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;6×6&lt;/td&gt;
&lt;td&gt;38&lt;/td&gt;
&lt;td&gt;19.8%&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;5.5%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;62.6%&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;4.2%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;7.9%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8×8&lt;/td&gt;
&lt;td&gt;30&lt;/td&gt;
&lt;td&gt;15.3%&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;3.5%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;67.4%&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;4.5%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;9.2%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The two halves of the rectangle predicate write about the same number of cells,&lt;br&gt;
and both are dwarfed by the group-size arithmetic. But now drop one rung at a&lt;br&gt;
time out of the full stack:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;variant&lt;/th&gt;
&lt;th&gt;settled&lt;/th&gt;
&lt;th&gt;finishes with no guessing&lt;/th&gt;
&lt;th&gt;assumptions&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;all rungs&lt;/td&gt;
&lt;td&gt;100.0%&lt;/td&gt;
&lt;td&gt;68/68&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;− &lt;code&gt;value&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;86.7%&lt;/td&gt;
&lt;td&gt;50/68&lt;/td&gt;
&lt;td&gt;332&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;− &lt;code&gt;rect&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;97.2%&lt;/td&gt;
&lt;td&gt;54/68&lt;/td&gt;
&lt;td&gt;498&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;− &lt;code&gt;anti&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;89.8%&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;36/68&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;11,686&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;− &lt;code&gt;size&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;23.5%&lt;/td&gt;
&lt;td&gt;8/68&lt;/td&gt;
&lt;td&gt;3,623,318&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Without probing sitting on top, &lt;code&gt;− rect&lt;/code&gt; costs 17,452 assumptions across the set&lt;br&gt;
and &lt;code&gt;− anti&lt;/code&gt; costs &lt;strong&gt;103,958&lt;/strong&gt;. The rule that can only say &lt;em&gt;no&lt;/em&gt; is six times more&lt;br&gt;
expensive to do without than the rule that can say &lt;em&gt;yes&lt;/em&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Why
&lt;/h3&gt;

&lt;p&gt;The affirmed half has already moved house.&lt;/p&gt;

&lt;p&gt;Its real work is happening inside the &lt;code&gt;size&lt;/code&gt; rung. A clued chocolate bar of area&lt;br&gt;
&lt;code&gt;v&lt;/code&gt; gets matched against the set of area-&lt;code&gt;v&lt;/code&gt; rectangles that still fit around the&lt;br&gt;
cell without swallowing a known banana; cells common to every survivor are shaded,&lt;br&gt;
and cells touching the group but inside no survivor are banana. That &lt;em&gt;is&lt;/em&gt; "is a&lt;br&gt;
rectangle" — with a number attached. By the time you get to &lt;code&gt;rect&lt;/code&gt; standing on&lt;br&gt;
its own, there is almost nothing left for it to do.&lt;/p&gt;

&lt;p&gt;The denied half has no second home. Nothing else in the solver knows that a&lt;br&gt;
sealed rectangle of unshaded cells is illegal, so when you delete it, that&lt;br&gt;
knowledge is simply gone and the search pays for it.&lt;/p&gt;

&lt;p&gt;(The &lt;code&gt;unique&lt;/code&gt; column is worth a footnote: with &lt;code&gt;size&lt;/code&gt; removed the search blows&lt;br&gt;
past its 60,000-node ablation budget on 58 of the 68 boards, so it can only&lt;br&gt;
&lt;em&gt;confirm&lt;/em&gt; uniqueness on 10 of them. The answer counts did not change — the&lt;br&gt;
budget did. That is itself a measurement of the cost.)&lt;/p&gt;
&lt;h3&gt;
  
  
  As rules rather than as inferences, both halves are load-bearing
&lt;/h3&gt;

&lt;p&gt;Uniqueness is a property of the rule set, not of the solver. So ablate the two&lt;br&gt;
halves as &lt;em&gt;rules of the puzzle&lt;/em&gt; and re-count the answers:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;size&lt;/th&gt;
&lt;th&gt;boards&lt;/th&gt;
&lt;th&gt;full rules&lt;/th&gt;
&lt;th&gt;without "banana ≠ rectangle"&lt;/th&gt;
&lt;th&gt;without "chocolate = rectangle"&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;6×6&lt;/td&gt;
&lt;td&gt;38&lt;/td&gt;
&lt;td&gt;38/38&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;12/38&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;21/38&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8×8&lt;/td&gt;
&lt;td&gt;30&lt;/td&gt;
&lt;td&gt;30/30&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;12/30&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;9/30&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Delete "a banana is not a rectangle" and 26 of the 38 6×6 boards and 18 of the 30&lt;br&gt;
8×8 boards stop having a unique answer, the median board picking up 2 and 4.5&lt;br&gt;
answers respectively. Delete the other half and at 8×8 it is &lt;em&gt;worse&lt;/em&gt; — only 9 of&lt;br&gt;
30 survive.&lt;/p&gt;

&lt;p&gt;So as constraints the two halves are comparable; the asymmetry lives entirely on&lt;br&gt;
the inference side, and it points the opposite way from the intuition.&lt;/p&gt;
&lt;h2&gt;
  
  
  A number is a factorisation, not a quantity
&lt;/h2&gt;

&lt;p&gt;The clue gives a size and withholds the colour, so reading it is an arithmetic&lt;br&gt;
question.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A connected set of &lt;strong&gt;1 or 2&lt;/strong&gt; cells is a rectangle however you draw it. So &lt;code&gt;1&lt;/code&gt;
and &lt;code&gt;2&lt;/code&gt; are always chocolate.&lt;/li&gt;
&lt;li&gt;A chocolate bar of area &lt;code&gt;v&lt;/code&gt; exists on an &lt;code&gt;H×W&lt;/code&gt; board only if &lt;code&gt;v = a·b&lt;/code&gt; with
&lt;code&gt;a ≤ H&lt;/code&gt; and &lt;code&gt;b ≤ W&lt;/code&gt;. &lt;strong&gt;A number outside that multiplication table is always
banana&lt;/strong&gt; — on a 6×6 board that is &lt;code&gt;7, 11, 13, 14, 17, 19, 21, 22, 23, 26…&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And a banana of area &lt;code&gt;v&lt;/code&gt; exists exactly when &lt;code&gt;3 ≤ v ≤ H·W − 1&lt;/code&gt; (with &lt;code&gt;H, W ≥ 2&lt;/code&gt;).&lt;br&gt;
The two ends are precisely the cases that force a rectangle, and everything&lt;br&gt;
strictly between is constructible: take &lt;code&gt;⌊v/W⌋&lt;/code&gt; full rows plus the remainder, and&lt;br&gt;
when the remainder is zero, shave one cell off the last full row and hang it&lt;br&gt;
below instead.&lt;/p&gt;

&lt;p&gt;So the &lt;code&gt;value&lt;/code&gt; rung never looks at the grid at all. The number and the board&lt;br&gt;
dimensions are enough.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;v&lt;/th&gt;
&lt;th&gt;6×6&lt;/th&gt;
&lt;th&gt;8×8&lt;/th&gt;
&lt;th&gt;10×10&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1, 2&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;chocolate&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;chocolate&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;chocolate&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;banana&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;either&lt;/td&gt;
&lt;td&gt;either&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;11, 13&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;banana&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;banana&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;banana&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;14&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;banana&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;either&lt;/td&gt;
&lt;td&gt;either&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;More than half of all possible group sizes name their own colour on sight: 21 of&lt;br&gt;
36 on a 6×6 board (58.3%), 37 of 64 on an 8×8 (57.8%), 61 of 100 on a 10×10&lt;br&gt;
(61.0%). On the shipped 6×6 boards, 271 of the 388 clues (69.8%) are of that&lt;br&gt;
kind — 195 of them because they are a &lt;code&gt;1&lt;/code&gt; or a &lt;code&gt;2&lt;/code&gt;, 76 because they are off the&lt;br&gt;
times table.&lt;/p&gt;

&lt;p&gt;The number of areas a bar may have on an &lt;code&gt;n×n&lt;/code&gt; board is exactly&lt;br&gt;
&lt;a href="https://oeis.org/A027424" rel="noopener noreferrer"&gt;OEIS A027424&lt;/a&gt;: 1, 3, 6, 9, 14, 18, 25, 30, 36, 42.&lt;/p&gt;
&lt;h2&gt;
  
  
  Some answers no clue set can pin down
&lt;/h2&gt;

&lt;p&gt;The clue language of Choco Banana is precisely the map &lt;em&gt;cell → size of its&lt;br&gt;
group&lt;/em&gt;. So the strongest clue set that can exist is a number in every cell, and a&lt;br&gt;
one-line theorem falls out:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;An answer can be made unique if and only if it is the only legal grid with&lt;br&gt;
its size map.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;(⇐) If it is the only one, write every size and it is pinned. (⇒) If another&lt;br&gt;
answer &lt;code&gt;B&lt;/code&gt; has the same size map, then &lt;code&gt;B&lt;/code&gt; satisfies every clue &lt;code&gt;A&lt;/code&gt; satisfies, so&lt;br&gt;
no clue set on earth can exclude it.&lt;/p&gt;

&lt;p&gt;And the right-hand side is not always true. On a 3×4 board, a 2×3 chocolate bar&lt;br&gt;
in any of the four corners leaves six banana cells in an L — and &lt;strong&gt;all four grids&lt;br&gt;
read 6 in every single cell.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;###.     .###     ....     ....
###.     .###     ###.     .###
....     ....     ###.     .###
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Write all twelve numbers and four answers still stand.&lt;/p&gt;

&lt;p&gt;Exhaustively, over every legal grid on small boards:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;board&lt;/th&gt;
&lt;th&gt;answers&lt;/th&gt;
&lt;th&gt;distinct size maps&lt;/th&gt;
&lt;th&gt;answers in a tied group&lt;/th&gt;
&lt;th&gt;biggest tie&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;2×2 … 3×3&lt;/td&gt;
&lt;td&gt;5 … 121&lt;/td&gt;
&lt;td&gt;all distinct&lt;/td&gt;
&lt;td&gt;0 (0.0%)&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3×4&lt;/td&gt;
&lt;td&gt;599&lt;/td&gt;
&lt;td&gt;596&lt;/td&gt;
&lt;td&gt;4 (0.7%)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;4&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3×5&lt;/td&gt;
&lt;td&gt;3057&lt;/td&gt;
&lt;td&gt;3055&lt;/td&gt;
&lt;td&gt;4 (0.1%)&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4×4&lt;/td&gt;
&lt;td&gt;4835&lt;/td&gt;
&lt;td&gt;4831&lt;/td&gt;
&lt;td&gt;8 (0.2%)&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4×5&lt;/td&gt;
&lt;td&gt;40899&lt;/td&gt;
&lt;td&gt;40875&lt;/td&gt;
&lt;td&gt;48 (0.1%)&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Not one pair exists up to 3×3; they appear at 3×4 and then sit at around 0.1%.&lt;br&gt;
The generator has to detect them and walk away — its adversarial clue-buying loop&lt;br&gt;
returns &lt;code&gt;null&lt;/code&gt; the moment it cannot find a single cell where the two answers&lt;br&gt;
disagree about a size.&lt;/p&gt;

&lt;h2&gt;
  
  
  Both clue dialects are incomplete
&lt;/h2&gt;

&lt;p&gt;Restrict clue buying to numbers that name their own colour, then to numbers that&lt;br&gt;
do not:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;size&lt;/th&gt;
&lt;th&gt;boards&lt;/th&gt;
&lt;th&gt;unrestricted&lt;/th&gt;
&lt;th&gt;forcing only&lt;/th&gt;
&lt;th&gt;silent only&lt;/th&gt;
&lt;th&gt;price (median)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;6×6&lt;/td&gt;
&lt;td&gt;38&lt;/td&gt;
&lt;td&gt;38&lt;/td&gt;
&lt;td&gt;19&lt;/td&gt;
&lt;td&gt;15&lt;/td&gt;
&lt;td&gt;6.0 / 7.0 / 8.0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Unrestricted, all 38 answers can be pinned. With only self-naming numbers, 19.&lt;br&gt;
With only silent ones, 15. The price — the median size of the minimal clue set —&lt;br&gt;
barely moves (6 / 7 / 8), so what each dialect loses is not cost but &lt;em&gt;reach&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;probe&lt;/code&gt; is sound here, but not complete
&lt;/h2&gt;

&lt;p&gt;In the previous puzzle in this series, "singleton consistency finishes the grid"&lt;br&gt;
and "the board has exactly one answer" agreed on all 718 clue prefixes tested.&lt;br&gt;
Not here.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;clue prefixes tested: &lt;strong&gt;581&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;agreement: 525 (&lt;strong&gt;90.4%&lt;/strong&gt;)&lt;/li&gt;
&lt;li&gt;unique but &lt;code&gt;probe&lt;/code&gt; stalls: &lt;strong&gt;56&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;probe&lt;/code&gt; finishes but the board is not unique: &lt;strong&gt;0&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The gap only points one way.&lt;/strong&gt; Not once did &lt;code&gt;probe&lt;/code&gt; claim to have finished a&lt;br&gt;
board that turned out to have a second answer — if it had, that would be a&lt;br&gt;
soundness bug, not a statistic. But 56 times a board had exactly one answer and&lt;br&gt;
&lt;code&gt;probe&lt;/code&gt; still needed a guess to find it. Difficulty and search strength come&lt;br&gt;
apart here in a way they did not last time.&lt;/p&gt;

&lt;p&gt;Every shipped clue set is minimal in the strict sense: removing any one of the&lt;br&gt;
518 uniqueness clues, one at a time, left &lt;strong&gt;0&lt;/strong&gt; of them still unique, and the&lt;br&gt;
median board grew to 26 answers.&lt;/p&gt;

&lt;h2&gt;
  
  
  External ledgers
&lt;/h2&gt;

&lt;p&gt;Answers on a board with no clues at all, agreed by all engines:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;grid&lt;/th&gt;
&lt;th&gt;legal grids&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;n×n&lt;/code&gt;, n = 1…5&lt;/td&gt;
&lt;td&gt;1, 5, 121, 4835, 584931&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;1×n&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1, 1, 1, 1, 1, 1, 1, 1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;2×n&lt;/code&gt;, n = 1…10&lt;/td&gt;
&lt;td&gt;1, 5, 19, 57, 171, 509, 1505, 4441, 13105, 38689&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;3×n&lt;/code&gt;, n = 1…8&lt;/td&gt;
&lt;td&gt;1, 19, 121, 599, 3057, 15525, 78781, 399575&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;None of those is in OEIS as of 2026-09. The &lt;code&gt;1×n&lt;/code&gt; row is not a coincidence and&lt;br&gt;
not a bug: every connected piece of a strip is a rectangle, so no banana can live&lt;br&gt;
on one at all, and the only legal grid is all-chocolate for every &lt;code&gt;n&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The one number that &lt;em&gt;does&lt;/em&gt; reach outside the repository is the multiplication&lt;br&gt;
table, A027424 above.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three engines
&lt;/h2&gt;

&lt;p&gt;Three implementations that share no code have to agree on every board:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;solveCtx&lt;/code&gt; — the propagating search&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;bruteByMask&lt;/code&gt; — treats the grid as an integer and tries all of them&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;bruteByCells&lt;/code&gt; — walks cells in raster order and &lt;strong&gt;closes each group the moment
its last neighbour is coloured&lt;/strong&gt;, checking rectangularity and clue sizes there
and then&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;67/67 on the shipped boards for solver vs cell enumerator, 100/100 on random&lt;br&gt;
clued boards small enough for all three. 72 tests.&lt;/p&gt;

&lt;p&gt;That cross-check earned its keep during development. The &lt;code&gt;anti&lt;/code&gt; rung was built&lt;br&gt;
the obvious way: collect the list of unshaded components, then loop over it. But&lt;br&gt;
a write inside that loop can &lt;strong&gt;merge two bananas&lt;/strong&gt;, which makes every later entry&lt;br&gt;
in the list stale — and a stale component is a subset of the real one, so it can&lt;br&gt;
look like it has no way out, i.e. like a sealed rectangle. The solver was&lt;br&gt;
rejecting correct answers as contradictions. The cell enumerator caught it on one&lt;br&gt;
4×4 board with &lt;code&gt;solver=0, brute=1&lt;/code&gt;. The fix is one line — return &lt;code&gt;'changed'&lt;/code&gt; the&lt;br&gt;
instant you write, and let the outer loop rebuild the list — and there is a&lt;br&gt;
regression test with the minimal 4×4 case that reproduces it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The five rungs
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;rung&lt;/th&gt;
&lt;th&gt;what it is&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;value&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;the number alone names the colour: &lt;code&gt;1&lt;/code&gt;/&lt;code&gt;2&lt;/code&gt; are chocolate, an area off the &lt;code&gt;H×W&lt;/code&gt; times table is banana&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;rect&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;every chocolate bar fills its bounding box&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;size&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;a clued group is exactly that big: lower bound (what it holds) and upper bound (what it can reach), both saturating, plus the intersection of the surviving rectangle placements&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;anti&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;a banana may not be a rectangle: a sealed rectangular banana is a contradiction, one with a single way out must take it, and a cell walled in on four sides is chocolate&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;probe&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;singleton consistency on top&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Cumulatively on 6×6 they settle 19.8% → 34.4% → 69.7% → 79.8% → 100%.&lt;/p&gt;

&lt;h2&gt;
  
  
  Generation
&lt;/h2&gt;

&lt;p&gt;Answer first. Step one finds a legal grid by running the solver on a board with&lt;br&gt;
no clues, with the branching order shuffled and the colour order biased, so every&lt;br&gt;
answer is legal by construction. Step two buys clues adversarially: while a second&lt;br&gt;
answer exists, find a cell where the two grids put a differently sized group and&lt;br&gt;
write that size there. It stops when uniqueness is reached, or gives up when no&lt;br&gt;
such cell exists — which, as above, genuinely happens.&lt;/p&gt;

&lt;p&gt;Then the clue set is minimised twice: once down to a uniqueness-minimal set, and&lt;br&gt;
once down to a set that also lets the target rung finish without guessing. The&lt;br&gt;
median 6×6 board needs 6 clues to be unique and 11 to be guess-free; at 8×8 it is&lt;br&gt;
10 and 16.5.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/sen-ltd/choco-banana
&lt;span class="nb"&gt;cd &lt;/span&gt;choco-banana &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; npm &lt;span class="nb"&gt;install
&lt;/span&gt;npm run dev
npm &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;?board=8-3&amp;amp;fill=size&lt;/code&gt; opens a specific board with one rung already run, so a&lt;br&gt;
link can point at exactly the position being discussed.&lt;/p&gt;

&lt;p&gt;Demo: &lt;a href="https://sen.ltd/portfolio/choco-banana/" rel="noopener noreferrer"&gt;https://sen.ltd/portfolio/choco-banana/&lt;/a&gt;&lt;br&gt;
Repo: &lt;a href="https://github.com/sen-ltd/choco-banana" rel="noopener noreferrer"&gt;https://github.com/sen-ltd/choco-banana&lt;/a&gt;&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>algorithms</category>
      <category>gamedev</category>
      <category>puzzle</category>
    </item>
    <item>
      <title>Yajisan-Kazusan: everything the solver learns first, it learns from a liar</title>
      <dc:creator>SEN LLC</dc:creator>
      <pubDate>Sun, 30 Aug 2026 23:52:56 +0000</pubDate>
      <link>https://dev.to/sendotltd/yajisan-kazusan-everything-the-solver-learns-first-it-learns-from-a-liar-2n2m</link>
      <guid>https://dev.to/sendotltd/yajisan-kazusan-everything-the-solver-learns-first-it-learns-from-a-liar-2n2m</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Yajisan-Kazusan&lt;/strong&gt; in the browser with &lt;strong&gt;five rule sets&lt;/strong&gt; inside. An arrow&lt;br&gt;
clue only has to be true when its own cell is unshaded. Shade the clue's cell&lt;br&gt;
and the number may say anything at all — a clue is allowed to lie. Puzzle #51&lt;br&gt;
in the solver series.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Demo: &lt;a href="https://sen.ltd/portfolio/yajisan-kazusan/" rel="noopener noreferrer"&gt;https://sen.ltd/portfolio/yajisan-kazusan/&lt;/a&gt;&lt;br&gt;
Repo: &lt;a href="https://github.com/sen-ltd/yajisan-kazusan" rel="noopener noreferrer"&gt;https://github.com/sen-ltd/yajisan-kazusan&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fo2bs4uusmyto8dxlj4jf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fo2bs4uusmyto8dxlj4jf.png" alt="Yajisan-Kazusan" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Rules
&lt;/h2&gt;

&lt;p&gt;Shade some cells of an &lt;code&gt;H×W&lt;/code&gt; grid.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;No two shaded cells are orthogonally adjacent.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;The unshaded cells form &lt;strong&gt;one&lt;/strong&gt; connected region.&lt;/li&gt;
&lt;li&gt;Every clue is an arrow and a number written &lt;em&gt;inside&lt;/em&gt; a cell. &lt;strong&gt;If that cell is
unshaded&lt;/strong&gt;, the number must equal how many shaded cells lie beyond it in the
arrow's direction, out to the edge. &lt;strong&gt;If the cell is shaded, the clue is
exempt&lt;/strong&gt; — it may say anything.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Rule 3 is the whole puzzle. A clue is not an assertion about the grid; it is an&lt;br&gt;
assertion &lt;em&gt;conditional on one of the unknowns&lt;/em&gt;, namely its own cell. So a clue&lt;br&gt;
can lie, provided it pays for the privilege by standing on a shaded cell.&lt;/p&gt;

&lt;p&gt;Put differently, a Yajisan-Kazusan clue is a disjunction:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I am shaded, &lt;strong&gt;or&lt;/strong&gt; my number is right.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  The contrapositive is the engine
&lt;/h2&gt;

&lt;p&gt;The useful half of a disjunction is what happens when the right-hand side dies.&lt;/p&gt;

&lt;p&gt;A line of &lt;code&gt;L&lt;/code&gt; cells can hold at most &lt;code&gt;⌈L/2⌉&lt;/code&gt; shaded cells, because they may not&lt;br&gt;
touch. So a clue whose number is bigger than that can &lt;strong&gt;never&lt;/strong&gt; be true, and:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;A clue carrying an unsayable number has confessed that its own cell is&lt;br&gt;
shaded.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is not a lemma, it is the solver's second rung. Measured on the shipped&lt;br&gt;
boards — what fraction of the grid each rung's fixpoint settles:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;size&lt;/th&gt;
&lt;th&gt;boards&lt;/th&gt;
&lt;th&gt;&lt;code&gt;adj&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;cap&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;ray&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;white&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;probe&lt;/code&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;6×6&lt;/td&gt;
&lt;td&gt;40&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.0%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;32.4%&lt;/td&gt;
&lt;td&gt;52.9%&lt;/td&gt;
&lt;td&gt;59.6%&lt;/td&gt;
&lt;td&gt;100.0%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8×8&lt;/td&gt;
&lt;td&gt;40&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.0%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;37.7%&lt;/td&gt;
&lt;td&gt;58.0%&lt;/td&gt;
&lt;td&gt;67.1%&lt;/td&gt;
&lt;td&gt;100.0%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10×10&lt;/td&gt;
&lt;td&gt;30&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.0%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;34.2%&lt;/td&gt;
&lt;td&gt;59.7%&lt;/td&gt;
&lt;td&gt;64.3%&lt;/td&gt;
&lt;td&gt;100.0%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;adj&lt;/code&gt; — "shaded cells never touch" — settles &lt;strong&gt;0.0%&lt;/strong&gt;, and of course it does:&lt;br&gt;
nothing is shaded yet, so the adjacency rule has nothing to work from. The very&lt;br&gt;
next rung, which does nothing whatsoever except catch clues lying, goes straight&lt;br&gt;
to a third of the board.&lt;/p&gt;

&lt;p&gt;So in this puzzle, &lt;strong&gt;everything the solver learns first, it learns from a&lt;br&gt;
liar.&lt;/strong&gt; The honest clues cannot start work until a liar has shaded a cell for&lt;br&gt;
them.&lt;/p&gt;
&lt;h2&gt;
  
  
  A clue set always exists
&lt;/h2&gt;

&lt;p&gt;The foundation first. For any legal answer there is always a clue set that pins&lt;br&gt;
it down, and the proof is a two-case split that is literally the generator's&lt;br&gt;
code.&lt;/p&gt;

&lt;p&gt;Let &lt;code&gt;A&lt;/code&gt; be the intended answer and &lt;code&gt;B&lt;/code&gt; a rival answer we want to kill.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Case 1: some cell &lt;code&gt;c&lt;/code&gt; is shaded in &lt;code&gt;A&lt;/code&gt; and unshaded in &lt;code&gt;B&lt;/code&gt;.&lt;/strong&gt;&lt;br&gt;
Put a clue in &lt;code&gt;c&lt;/code&gt;. In &lt;code&gt;A&lt;/code&gt; it is exempt, so its number is free. In &lt;code&gt;B&lt;/code&gt; it is&lt;br&gt;
binding, so any number other than &lt;code&gt;B&lt;/code&gt;'s actual count kills &lt;code&gt;B&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Case 2: no such cell&lt;/strong&gt; — i.e. &lt;code&gt;A&lt;/code&gt;'s shaded set is a proper subset of &lt;code&gt;B&lt;/code&gt;'s.&lt;br&gt;
Take &lt;code&gt;d&lt;/code&gt;, the &lt;em&gt;last&lt;/em&gt; cell in raster order where the two disagree; it is shaded in&lt;br&gt;
&lt;code&gt;B&lt;/code&gt;, unshaded in &lt;code&gt;A&lt;/code&gt;. Its right neighbour (or, at the row's end, its neighbour&lt;br&gt;
below) is unshaded in &lt;code&gt;B&lt;/code&gt; by rule 1, and it comes after &lt;code&gt;d&lt;/code&gt;, so &lt;code&gt;A&lt;/code&gt; and &lt;code&gt;B&lt;/code&gt; agree&lt;br&gt;
there — it is unshaded in both. Point an arrow from it back through &lt;code&gt;d&lt;/code&gt;. Every&lt;br&gt;
cell on that line other than &lt;code&gt;d&lt;/code&gt; is a cell the two answers agree on, so the two&lt;br&gt;
counts differ by exactly one. Write &lt;code&gt;A&lt;/code&gt;'s honest number and &lt;code&gt;B&lt;/code&gt; dies.&lt;/p&gt;

&lt;p&gt;Case 2 &lt;strong&gt;depends on rule 1&lt;/strong&gt;, which is the interesting part. Without "shaded&lt;br&gt;
cells never touch", there is no guarantee of a cell next to the disagreement that&lt;br&gt;
is unshaded in both answers.&lt;/p&gt;
&lt;h2&gt;
  
  
  An all-liar clue set works exactly on maximal answers
&lt;/h2&gt;

&lt;p&gt;Existence settled, now restrict the alphabet.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Liar dialect&lt;/strong&gt;: clues only on cells that end up shaded. Every clue is exempt.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Honest dialect&lt;/strong&gt;: clues only on cells that end up unshaded. Every clue is
binding.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The liar dialect has a clean, exact answer.&lt;/p&gt;

&lt;p&gt;Write an unsayable number on every shaded cell of the answer. Each one confesses,&lt;br&gt;
so all those cells are forced shaded; nothing else is said at all. The answers to&lt;br&gt;
that puzzle are therefore precisely the legal shadings that &lt;strong&gt;contain&lt;/strong&gt; the&lt;br&gt;
intended one. So:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If no cell can be added to the answer while staying legal — the answer is
&lt;strong&gt;⊆-maximal&lt;/strong&gt; — nothing else contains it, and it is unique.&lt;/li&gt;
&lt;li&gt;If a cell &lt;em&gt;can&lt;/em&gt; be added, the bigger shading is a legal answer too, and every
clue sits on a cell that the bigger answer also shades, where every clue is
exempt. It survives. And this is not a fact about &lt;em&gt;that&lt;/em&gt; clue set: a liar-only
clue set can only ever live on the answer's shaded cells, so &lt;strong&gt;no&lt;/strong&gt; liar-only
clue set can work.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;A liar-only clue set exists if and only if the answer is ⊆-maximal.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Both directions, on 540 answers:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;size&lt;/th&gt;
&lt;th&gt;density&lt;/th&gt;
&lt;th&gt;answers&lt;/th&gt;
&lt;th&gt;maximal&lt;/th&gt;
&lt;th&gt;of those, unique&lt;/th&gt;
&lt;th&gt;non-maximal&lt;/th&gt;
&lt;th&gt;of those, unique&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;5×5&lt;/td&gt;
&lt;td&gt;0.18&lt;/td&gt;
&lt;td&gt;60&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;60&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5×5&lt;/td&gt;
&lt;td&gt;0.24&lt;/td&gt;
&lt;td&gt;60&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;7&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;53&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5×5&lt;/td&gt;
&lt;td&gt;packed&lt;/td&gt;
&lt;td&gt;60&lt;/td&gt;
&lt;td&gt;60&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;60&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6×6&lt;/td&gt;
&lt;td&gt;0.18&lt;/td&gt;
&lt;td&gt;60&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;60&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6×6&lt;/td&gt;
&lt;td&gt;0.24&lt;/td&gt;
&lt;td&gt;60&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;50&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6×6&lt;/td&gt;
&lt;td&gt;packed&lt;/td&gt;
&lt;td&gt;60&lt;/td&gt;
&lt;td&gt;60&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;60&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7×7&lt;/td&gt;
&lt;td&gt;0.18&lt;/td&gt;
&lt;td&gt;60&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;60&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7×7&lt;/td&gt;
&lt;td&gt;0.24&lt;/td&gt;
&lt;td&gt;60&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;4&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;56&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7×7&lt;/td&gt;
&lt;td&gt;packed&lt;/td&gt;
&lt;td&gt;60&lt;/td&gt;
&lt;td&gt;60&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;60&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;All 201 maximal answers unique, none of the 339 non-maximal ones. No exceptions.&lt;/p&gt;
&lt;h2&gt;
  
  
  The honest dialect is the weaker one
&lt;/h2&gt;

&lt;p&gt;Same greedy purchase, only the legal locations change.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sparse answers (~20% shaded; at this density essentially none are maximal)&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;size&lt;/th&gt;
&lt;th&gt;boards&lt;/th&gt;
&lt;th&gt;maximal&lt;/th&gt;
&lt;th&gt;free-choice clues&lt;/th&gt;
&lt;th&gt;liar-only works&lt;/th&gt;
&lt;th&gt;honest-only works&lt;/th&gt;
&lt;th&gt;honest-only clues&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;6×6&lt;/td&gt;
&lt;td&gt;40&lt;/td&gt;
&lt;td&gt;0.0%&lt;/td&gt;
&lt;td&gt;11.9&lt;/td&gt;
&lt;td&gt;0.0%&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;22.5%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;14.1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8×8&lt;/td&gt;
&lt;td&gt;40&lt;/td&gt;
&lt;td&gt;0.0%&lt;/td&gt;
&lt;td&gt;21.1&lt;/td&gt;
&lt;td&gt;0.0%&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;10.0%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;23.0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Packed answers (nothing more fits, so all maximal)&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;size&lt;/th&gt;
&lt;th&gt;boards&lt;/th&gt;
&lt;th&gt;maximal&lt;/th&gt;
&lt;th&gt;free choice&lt;/th&gt;
&lt;th&gt;liar-only works&lt;/th&gt;
&lt;th&gt;liar-only clues&lt;/th&gt;
&lt;th&gt;honest-only works&lt;/th&gt;
&lt;th&gt;honest-only clues&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;6×6&lt;/td&gt;
&lt;td&gt;40&lt;/td&gt;
&lt;td&gt;100%&lt;/td&gt;
&lt;td&gt;10.4&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;100%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;10.4&lt;/td&gt;
&lt;td&gt;57.5%&lt;/td&gt;
&lt;td&gt;11.1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8×8&lt;/td&gt;
&lt;td&gt;30&lt;/td&gt;
&lt;td&gt;100%&lt;/td&gt;
&lt;td&gt;17.5&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;100%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;18.3&lt;/td&gt;
&lt;td&gt;16.7%&lt;/td&gt;
&lt;td&gt;18.6&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Read it like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Where the liar dialect works at all, it costs &lt;strong&gt;the same as a free choice&lt;/strong&gt;
(10.4 vs 10.4 on 6×6, 18.3 vs 17.5 on 8×8). The restriction is nearly free.&lt;/li&gt;
&lt;li&gt;The honest dialect frequently &lt;strong&gt;does not work at all&lt;/strong&gt;. On packed 8×8 answers
it succeeds on 5 boards out of 30. That is not a price problem, it is an
existence problem.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Earlier puzzles in this series kept landing on "both clue colours always exist,&lt;br&gt;
the only question is the price". Yajisan-Kazusan breaks the pattern. &lt;strong&gt;The liars&lt;br&gt;
are the expressive half of this puzzle's vocabulary; the honest clues are an&lt;br&gt;
incomplete dialect.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Four clues in ten are liars, and not one of them is spare
&lt;/h2&gt;

&lt;p&gt;Back from existence to measurement. Build the &lt;strong&gt;minimal&lt;/strong&gt; clue set that buys&lt;br&gt;
uniqueness, then count how many of those clues end up exempt in the answer:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;size&lt;/th&gt;
&lt;th&gt;boards&lt;/th&gt;
&lt;th&gt;clues&lt;/th&gt;
&lt;th&gt;exempt&lt;/th&gt;
&lt;th&gt;exempt share&lt;/th&gt;
&lt;th&gt;unsayable&lt;/th&gt;
&lt;th&gt;share&lt;/th&gt;
&lt;th&gt;exempt but accidentally true&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;6×6&lt;/td&gt;
&lt;td&gt;40&lt;/td&gt;
&lt;td&gt;478&lt;/td&gt;
&lt;td&gt;217&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;45.4%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;90&lt;/td&gt;
&lt;td&gt;18.8%&lt;/td&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8×8&lt;/td&gt;
&lt;td&gt;40&lt;/td&gt;
&lt;td&gt;842&lt;/td&gt;
&lt;td&gt;366&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;43.5%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;184&lt;/td&gt;
&lt;td&gt;21.9%&lt;/td&gt;
&lt;td&gt;26&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10×10&lt;/td&gt;
&lt;td&gt;30&lt;/td&gt;
&lt;td&gt;931&lt;/td&gt;
&lt;td&gt;379&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;40.7%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;206&lt;/td&gt;
&lt;td&gt;22.1%&lt;/td&gt;
&lt;td&gt;25&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Just over four in ten are liars, and about half of &lt;em&gt;those&lt;/em&gt; carry a number the&lt;br&gt;
line could never show — the confessions &lt;code&gt;cap&lt;/code&gt; catches on pass one. The rest are&lt;br&gt;
"sayable, but wrong here". And 7–9% of the exempt clues are &lt;strong&gt;accidentally&lt;br&gt;
honest&lt;/strong&gt;: nobody checks them, but their number happens to be right anyway.&lt;/p&gt;

&lt;p&gt;Now minimality does the work. A minimal set means every clue is load-bearing, so&lt;br&gt;
pull the liars out one at a time:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;size&lt;/th&gt;
&lt;th&gt;exempt clues tried&lt;/th&gt;
&lt;th&gt;still unique&lt;/th&gt;
&lt;th&gt;answers after the drop (median)&lt;/th&gt;
&lt;th&gt;max&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;6×6&lt;/td&gt;
&lt;td&gt;217&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;200+&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8×8&lt;/td&gt;
&lt;td&gt;366&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;200+&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10×10&lt;/td&gt;
&lt;td&gt;378&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;11&lt;/td&gt;
&lt;td&gt;200+&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;961 liars removed one at a time, and &lt;strong&gt;not once&lt;/strong&gt; did the board stay unique; the&lt;br&gt;
median board sprouts 8–11 answers. A lying clue is not decoration. Removing one&lt;br&gt;
collapses the board.&lt;/p&gt;

&lt;p&gt;Look at it from the grid's side and the same thing shows up: only about a fifth&lt;br&gt;
of the cells are shaded, but four tenths of the clues are sitting on them. Left&lt;br&gt;
to itself, the adversarial buyer &lt;strong&gt;over-selects&lt;/strong&gt; liars.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;code&gt;probe&lt;/code&gt; and uniqueness agree exactly
&lt;/h2&gt;

&lt;p&gt;Two quantities this series measures every time:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;clues needed for &lt;strong&gt;uniqueness&lt;/strong&gt; (unique-min)&lt;/li&gt;
&lt;li&gt;clues needed to be &lt;strong&gt;solvable without search&lt;/strong&gt; (solve-min)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Previous entries showed a step of about 1.08×. Here:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;size&lt;/th&gt;
&lt;th&gt;boards&lt;/th&gt;
&lt;th&gt;unique-min&lt;/th&gt;
&lt;th&gt;solve-min&lt;/th&gt;
&lt;th&gt;ratio&lt;/th&gt;
&lt;th&gt;grade histogram of the unique-min board&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;6×6&lt;/td&gt;
&lt;td&gt;40&lt;/td&gt;
&lt;td&gt;11.9&lt;/td&gt;
&lt;td&gt;11.9&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1.00&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;probe:35 white:5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8×8&lt;/td&gt;
&lt;td&gt;40&lt;/td&gt;
&lt;td&gt;21.1&lt;/td&gt;
&lt;td&gt;21.1&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1.00&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;probe:32 white:8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10×10&lt;/td&gt;
&lt;td&gt;30&lt;/td&gt;
&lt;td&gt;31.0&lt;/td&gt;
&lt;td&gt;31.0&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1.00&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;probe:26 white:4&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;No step at all.&lt;/strong&gt; The moment a board becomes unique, singleton consistency can&lt;br&gt;
finish it without a single guess.&lt;/p&gt;

&lt;p&gt;The other direction, swept over 718 clue prefixes:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;size&lt;/th&gt;
&lt;th&gt;prefixes&lt;/th&gt;
&lt;th&gt;
&lt;code&gt;probe&lt;/code&gt; completes&lt;/th&gt;
&lt;th&gt;unique&lt;/th&gt;
&lt;th&gt;agree&lt;/th&gt;
&lt;th&gt;probe not unique&lt;/th&gt;
&lt;th&gt;unique not probe&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;6×6&lt;/td&gt;
&lt;td&gt;358&lt;/td&gt;
&lt;td&gt;40&lt;/td&gt;
&lt;td&gt;40&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;100.0%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8×8&lt;/td&gt;
&lt;td&gt;360&lt;/td&gt;
&lt;td&gt;40&lt;/td&gt;
&lt;td&gt;40&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;100.0%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Zero disagreements in either direction&lt;/strong&gt;, against 98.0% / 98.9% in the previous&lt;br&gt;
entry. My guess at why is that this puzzle's constraints all fire from a single&lt;br&gt;
cell — shade one cell and &lt;code&gt;cap&lt;/code&gt; immediately provokes a confession, while &lt;code&gt;adj&lt;/code&gt;&lt;br&gt;
and &lt;code&gt;white&lt;/code&gt; both propagate outward from one cell — but that is a guess, and I am&lt;br&gt;
only claiming the observation.&lt;/p&gt;
&lt;h2&gt;
  
  
  Ablation: the row that argues with the headline
&lt;/h2&gt;

&lt;p&gt;Take the full stack and drop exactly one rung.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;size&lt;/th&gt;
&lt;th&gt;variant&lt;/th&gt;
&lt;th&gt;fixpoint bits&lt;/th&gt;
&lt;th&gt;boards moved&lt;/th&gt;
&lt;th&gt;probes&lt;/th&gt;
&lt;th&gt;search assumptions&lt;/th&gt;
&lt;th&gt;over budget&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;6×6&lt;/td&gt;
&lt;td&gt;full&lt;/td&gt;
&lt;td&gt;1440&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;436&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6×6&lt;/td&gt;
&lt;td&gt;−adj&lt;/td&gt;
&lt;td&gt;127&lt;/td&gt;
&lt;td&gt;40&lt;/td&gt;
&lt;td&gt;3892&lt;/td&gt;
&lt;td&gt;2,387,173&lt;/td&gt;
&lt;td&gt;39&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6×6&lt;/td&gt;
&lt;td&gt;−cap&lt;/td&gt;
&lt;td&gt;1421&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;2040&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6×6&lt;/td&gt;
&lt;td&gt;−ray&lt;/td&gt;
&lt;td&gt;1339&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;2210&lt;/td&gt;
&lt;td&gt;28&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6×6&lt;/td&gt;
&lt;td&gt;−white&lt;/td&gt;
&lt;td&gt;1106&lt;/td&gt;
&lt;td&gt;37&lt;/td&gt;
&lt;td&gt;1652&lt;/td&gt;
&lt;td&gt;4854&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6×6&lt;/td&gt;
&lt;td&gt;−probe&lt;/td&gt;
&lt;td&gt;858&lt;/td&gt;
&lt;td&gt;35&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;426&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8×8&lt;/td&gt;
&lt;td&gt;full&lt;/td&gt;
&lt;td&gt;2560&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;800&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8×8&lt;/td&gt;
&lt;td&gt;−adj&lt;/td&gt;
&lt;td&gt;244&lt;/td&gt;
&lt;td&gt;40&lt;/td&gt;
&lt;td&gt;7358&lt;/td&gt;
&lt;td&gt;2,400,558&lt;/td&gt;
&lt;td&gt;40&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8×8&lt;/td&gt;
&lt;td&gt;−cap&lt;/td&gt;
&lt;td&gt;2492&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;3828&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8×8&lt;/td&gt;
&lt;td&gt;−ray&lt;/td&gt;
&lt;td&gt;2324&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;4110&lt;/td&gt;
&lt;td&gt;208&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8×8&lt;/td&gt;
&lt;td&gt;−white&lt;/td&gt;
&lt;td&gt;2072&lt;/td&gt;
&lt;td&gt;38&lt;/td&gt;
&lt;td&gt;2512&lt;/td&gt;
&lt;td&gt;23,674&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8×8&lt;/td&gt;
&lt;td&gt;−probe&lt;/td&gt;
&lt;td&gt;1717&lt;/td&gt;
&lt;td&gt;32&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;2244&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10×10&lt;/td&gt;
&lt;td&gt;full&lt;/td&gt;
&lt;td&gt;3000&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;840&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10×10&lt;/td&gt;
&lt;td&gt;−adj&lt;/td&gt;
&lt;td&gt;252&lt;/td&gt;
&lt;td&gt;30&lt;/td&gt;
&lt;td&gt;8476&lt;/td&gt;
&lt;td&gt;1,800,166&lt;/td&gt;
&lt;td&gt;30&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10×10&lt;/td&gt;
&lt;td&gt;−cap&lt;/td&gt;
&lt;td&gt;2957&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;4642&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10×10&lt;/td&gt;
&lt;td&gt;−ray&lt;/td&gt;
&lt;td&gt;2474&lt;/td&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;td&gt;6510&lt;/td&gt;
&lt;td&gt;790&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10×10&lt;/td&gt;
&lt;td&gt;−white&lt;/td&gt;
&lt;td&gt;2661&lt;/td&gt;
&lt;td&gt;25&lt;/td&gt;
&lt;td&gt;2328&lt;/td&gt;
&lt;td&gt;22,448&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10×10&lt;/td&gt;
&lt;td&gt;−probe&lt;/td&gt;
&lt;td&gt;1928&lt;/td&gt;
&lt;td&gt;26&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;7478&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;(The &lt;code&gt;−adj&lt;/code&gt; rows exhaust the 60,000-node search budget on almost every board —&lt;br&gt;
39 of 40 on 6×6, all of them on 8×8 and 10×10 — so those counts only mean "at&lt;br&gt;
least this much".)&lt;/p&gt;

&lt;p&gt;There is a row here that points the opposite way from this article's headline.&lt;br&gt;
&lt;strong&gt;Dropping &lt;code&gt;cap&lt;/code&gt; breaks almost nothing.&lt;/strong&gt; On 6×6 the fixpoint goes from 1440 bits&lt;br&gt;
to 1421, exactly one board out of forty moves, and search assumptions go from 0&lt;br&gt;
to 4. On 10×10, one board.&lt;/p&gt;

&lt;p&gt;It is not a contradiction. The ladder table measures each rung stacked &lt;strong&gt;from the&lt;br&gt;
bottom&lt;/strong&gt;, where &lt;code&gt;cap&lt;/code&gt; is the only source of information there is. The ablation&lt;br&gt;
measures dropping a rung &lt;strong&gt;from the top&lt;/strong&gt;, with &lt;code&gt;probe&lt;/code&gt; still switched on — and&lt;br&gt;
singleton consistency rediscovers &lt;code&gt;cap&lt;/code&gt; by itself, because "assume this cell is&lt;br&gt;
unshaded → its arrow must be true → contradiction" &lt;em&gt;is&lt;/em&gt; a single-cell probe.&lt;/p&gt;

&lt;p&gt;So &lt;code&gt;cap&lt;/code&gt; is a &lt;strong&gt;cheap shortcut, not a necessary axiom&lt;/strong&gt; — and the cost shows up&lt;br&gt;
in the probe counter rather than in the answer: dropping &lt;code&gt;cap&lt;/code&gt; sends probe&lt;br&gt;
invocations from 436 to 2040 on 6×6 and from 800 to 3828 on 8×8, about 4.7×. The&lt;br&gt;
same conclusion, bought back at five times the price.&lt;/p&gt;

&lt;p&gt;Dropping &lt;code&gt;adj&lt;/code&gt;, on the other hand, is a collapse, and it should be: &lt;code&gt;adj&lt;/code&gt; is what&lt;br&gt;
supports the &lt;code&gt;⌈L/2⌉&lt;/code&gt; bound &lt;code&gt;cap&lt;/code&gt; rests on and the in-line adjacency the &lt;code&gt;ray&lt;/code&gt; DP&lt;br&gt;
respects. Every deduction in this puzzle is built on rule 1.&lt;/p&gt;
&lt;h2&gt;
  
  
  How far away is the second answer
&lt;/h2&gt;

&lt;p&gt;Every entry in this series asks whether a second answer is explained by a small,&lt;br&gt;
search-free certificate. Drop one clue from a minimal board to make it ambiguous,&lt;br&gt;
then count how many cells the impostor moves:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;size&lt;/th&gt;
&lt;th&gt;ambiguous boards&lt;/th&gt;
&lt;th&gt;cells moved (avg)&lt;/th&gt;
&lt;th&gt;≤2&lt;/th&gt;
&lt;th&gt;3–4&lt;/th&gt;
&lt;th&gt;≥5&lt;/th&gt;
&lt;th&gt;of those cells, on a clue&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;6×6&lt;/td&gt;
&lt;td&gt;40&lt;/td&gt;
&lt;td&gt;3.13&lt;/td&gt;
&lt;td&gt;45.0%&lt;/td&gt;
&lt;td&gt;37.5%&lt;/td&gt;
&lt;td&gt;17.5%&lt;/td&gt;
&lt;td&gt;40.8%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8×8&lt;/td&gt;
&lt;td&gt;40&lt;/td&gt;
&lt;td&gt;5.53&lt;/td&gt;
&lt;td&gt;25.0%&lt;/td&gt;
&lt;td&gt;22.5%&lt;/td&gt;
&lt;td&gt;52.5%&lt;/td&gt;
&lt;td&gt;38.9%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10×10&lt;/td&gt;
&lt;td&gt;30&lt;/td&gt;
&lt;td&gt;4.17&lt;/td&gt;
&lt;td&gt;43.3%&lt;/td&gt;
&lt;td&gt;23.3%&lt;/td&gt;
&lt;td&gt;33.3%&lt;/td&gt;
&lt;td&gt;31.2%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;On 6×6, 45% of impostors move two cells or fewer; on 8×8, over half move five or&lt;br&gt;
more. &lt;strong&gt;The bigger the board, the less a second answer looks like a local&lt;br&gt;
swap.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;And a third to two fifths of the moved cells are clue cells themselves, which&lt;br&gt;
falls straight out of the exemption mechanic: flip a clue cell between shaded and&lt;br&gt;
unshaded and you flip whether that clue is checked at all. &lt;strong&gt;Second answers are&lt;br&gt;
usually built by switching clues on and off.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  External ledgers
&lt;/h2&gt;

&lt;p&gt;Internal consistency proves nothing, so the counts are nailed to numbers that&lt;br&gt;
exist outside the repository. Switch off rule 2 (connectivity) and drop every&lt;br&gt;
clue, and what is left is just "shade without touching" — the independent sets of&lt;br&gt;
the grid graph:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;grid&lt;/th&gt;
&lt;th&gt;counts&lt;/th&gt;
&lt;th&gt;OEIS&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;n×n, n=1..5&lt;/td&gt;
&lt;td&gt;2, 7, 63, 1234, 55447&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://oeis.org/A006506" rel="noopener noreferrer"&gt;A006506&lt;/a&gt;, non-attacking princes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2×n, n=1..8&lt;/td&gt;
&lt;td&gt;3, 7, 17, 41, 99, 239, 577, 1393&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://oeis.org/A001333" rel="noopener noreferrer"&gt;A001333&lt;/a&gt;, Pell–Lucas&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3×n, n=1..7&lt;/td&gt;
&lt;td&gt;5, 17, 63, 227, 827, 2999, 10897&lt;/td&gt;
&lt;td&gt;&lt;a href="https://oeis.org/A051736" rel="noopener noreferrer"&gt;A051736&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Three engines produce those numbers and they share no code. &lt;code&gt;bruteByRows&lt;/code&gt; stacks&lt;br&gt;
row bitmasks and never looks at a cell. &lt;code&gt;bruteByCells&lt;/code&gt; walks cells in raster&lt;br&gt;
order and never builds a mask. &lt;code&gt;independentSetCount&lt;/code&gt; does not enumerate at all —&lt;br&gt;
it is a transfer matrix, so it still answers for 7×7 (1,280,128,950) long after&lt;br&gt;
the enumerators have given up.&lt;/p&gt;

&lt;p&gt;Switch connectivity back on and the &lt;code&gt;n×n&lt;/code&gt; diagonal becomes &lt;strong&gt;1, 5, 39, 562,&lt;br&gt;
20297&lt;/strong&gt;, which is not in OEIS as of 2026-08. That absence is not a claim about&lt;br&gt;
anything, but the values are baked into the tests.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;1×n&lt;/code&gt; strip has a closed form you can do by hand: on a strip, "the unshaded&lt;br&gt;
cells are connected" means they are one run, so only the two ends can be shaded,&lt;br&gt;
and (for &lt;code&gt;n ≥ 3&lt;/code&gt;) the ends do not touch each other. That gives &lt;code&gt;{}&lt;/code&gt;, &lt;code&gt;{left}&lt;/code&gt;,&lt;br&gt;
&lt;code&gt;{right}&lt;/code&gt;, &lt;code&gt;{both}&lt;/code&gt; — &lt;strong&gt;4&lt;/strong&gt; for every &lt;code&gt;n ≥ 3&lt;/code&gt; (1 for n=1, 3 for n=2). Both&lt;br&gt;
enumerators and the solver agree at every &lt;code&gt;n&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  The five rungs
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;rung&lt;/th&gt;
&lt;th&gt;what it is&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;adj&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;the four neighbours of a shaded cell are unshaded&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;cap&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;a number the line could never show means the clue's own cell is shaded&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ray&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;once a clue cell is known unshaded its arrow is honest: a DP along the line&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;white&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;connectivity of the unshaded region — unreachable cells and cut cells&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;probe&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;singleton consistency&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Only &lt;code&gt;ray&lt;/code&gt; needs code shown. For a line &lt;code&gt;r_1..r_L&lt;/code&gt;, run a DP that keeps the set of&lt;br&gt;
reachable totals as a bitmask while respecting adjacency &lt;strong&gt;inside the line&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;rayTotals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cells&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;rr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;work&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;force&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;forceVal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;WHITE&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;d0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// reachable totals with the previous cell unshaded&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;d1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// ... with the previous cell shaded&lt;/span&gt;
  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;rr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;force&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;forceVal&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;cells&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;rr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]];&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;n0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;n1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;SHADED&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;n0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;d0&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;d1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;                 &lt;span class="c1"&gt;// leave it unshaded&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;WHITE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="nx"&gt;n1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;d0&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="mh"&gt;0x7fffffff&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// shade it: previous must be unshaded&lt;/span&gt;
    &lt;span class="nx"&gt;d0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;n0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;d1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;n1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;d0&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;d1&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;d0&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;d1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One function, three uses:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;cap&lt;/code&gt;&lt;/strong&gt; — assume the clue's cell is unshaded and run it. If the number is
not in the reachable set, the assumption is false: the cell is shaded.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;ray&lt;/code&gt;&lt;/strong&gt; — with the clue cell known unshaded, pin each undecided line cell
both ways with &lt;code&gt;force&lt;/code&gt;. If only one way can still reach the number, write it.&lt;/li&gt;
&lt;li&gt;It ignores adjacency &lt;em&gt;outside&lt;/em&gt; the line, which makes it a &lt;strong&gt;relaxation&lt;/strong&gt;: it
never rules out anything real, and it sharpens as the grid fills in.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The &lt;code&gt;⌈L/2⌉&lt;/code&gt; bound is not implemented as a separate constant anywhere. Run&lt;br&gt;
&lt;code&gt;rayTotals&lt;/code&gt; on an empty line and the largest reachable total &lt;em&gt;is&lt;/em&gt; &lt;code&gt;⌈L/2⌉&lt;/code&gt;; the&lt;br&gt;
tests check that for &lt;code&gt;L = 0..10&lt;/code&gt;. The bound is a corollary of the DP's first&lt;br&gt;
pass, not a rule of its own.&lt;/p&gt;

&lt;h2&gt;
  
  
  Generation
&lt;/h2&gt;

&lt;p&gt;Answer-first. Walk the cells in random order and shade one whenever that keeps&lt;br&gt;
both "no touching" and "the unshaded cells stay connected". No rejection, no&lt;br&gt;
retry — &lt;strong&gt;by the time you stop, you already have a legal answer.&lt;/strong&gt; Set the density&lt;br&gt;
parameter to 1 and it packs until nothing more fits (which needs a fixpoint, not&lt;br&gt;
one pass), and that gives the maximal answers the liar theorem needs.&lt;/p&gt;

&lt;p&gt;Clues are then bought adversarially by enumerating exactly the two cases from the&lt;br&gt;
existence proof, then minimised by shuffling and dropping one at a time. Every&lt;br&gt;
clue on a shipped board is load-bearing, and a test removes each one to prove it.&lt;/p&gt;

&lt;p&gt;Vary the density and the price runs the opposite way to intuition:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;size&lt;/th&gt;
&lt;th&gt;density&lt;/th&gt;
&lt;th&gt;avg shaded&lt;/th&gt;
&lt;th&gt;maximal&lt;/th&gt;
&lt;th&gt;answers with no clues&lt;/th&gt;
&lt;th&gt;clues for uniqueness&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;6×6&lt;/td&gt;
&lt;td&gt;0.14&lt;/td&gt;
&lt;td&gt;5.0&lt;/td&gt;
&lt;td&gt;0.0%&lt;/td&gt;
&lt;td&gt;1,646,096&lt;/td&gt;
&lt;td&gt;12.8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6×6&lt;/td&gt;
&lt;td&gt;0.18&lt;/td&gt;
&lt;td&gt;6.0&lt;/td&gt;
&lt;td&gt;0.0%&lt;/td&gt;
&lt;td&gt;1,646,096&lt;/td&gt;
&lt;td&gt;12.9&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6×6&lt;/td&gt;
&lt;td&gt;0.22&lt;/td&gt;
&lt;td&gt;8.0&lt;/td&gt;
&lt;td&gt;0.0%&lt;/td&gt;
&lt;td&gt;1,646,096&lt;/td&gt;
&lt;td&gt;11.8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6×6&lt;/td&gt;
&lt;td&gt;packed&lt;/td&gt;
&lt;td&gt;10.3&lt;/td&gt;
&lt;td&gt;100%&lt;/td&gt;
&lt;td&gt;1,646,096&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;10.3&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Twice as many shaded cells, fewer clues needed.&lt;/strong&gt; More shaded cells means more&lt;br&gt;
&lt;em&gt;exempt seats&lt;/em&gt; to write a clue into, and a clue in an exempt seat has a free&lt;br&gt;
choice of number — which is the maximum possible freedom to kill a rival. The&lt;br&gt;
more places an answer lets a clue lie, the cheaper it is to make unique.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tests
&lt;/h2&gt;

&lt;p&gt;61 of them: the line DP against brute force for every length 0–10; the asymmetry&lt;br&gt;
of rule 3 (rewrite an exempt clue's number to anything and the answer survives;&lt;br&gt;
move a binding clue's number by one and it dies); monotonicity in both senses&lt;br&gt;
(more clues never adds answers, a stronger rung never decides less); propagation&lt;br&gt;
never writing a cell the answer disagrees with; three engines agreeing on both&lt;br&gt;
counts and answer sets; the external ledgers; both directions of the liar&lt;br&gt;
theorem; and the shipped bank being unique, honestly graded and free of spare&lt;br&gt;
clues.&lt;/p&gt;

&lt;h2&gt;
  
  
  Layout
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;src/yajisan-kazusan.ts   model, five rule sets, propagation, search, referee
src/brute.ts             two enumerators sharing no code with the solver, plus a transfer matrix
src/generate.ts          answer-first generation and adversarial clue buying
tools/stats.mts          every table in this article
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;strong&gt;Demo&lt;/strong&gt;: &lt;a href="https://sen.ltd/portfolio/yajisan-kazusan/" rel="noopener noreferrer"&gt;https://sen.ltd/portfolio/yajisan-kazusan/&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Repo&lt;/strong&gt;: &lt;a href="https://github.com/sen-ltd/yajisan-kazusan" rel="noopener noreferrer"&gt;https://github.com/sen-ltd/yajisan-kazusan&lt;/a&gt;&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>algorithms</category>
      <category>gamedev</category>
      <category>puzzle</category>
    </item>
    <item>
      <title>Statue Park: the no-touching rule isn't a rule, and the circle that names nothing costs 60% more</title>
      <dc:creator>SEN LLC</dc:creator>
      <pubDate>Sun, 30 Aug 2026 00:55:06 +0000</pubDate>
      <link>https://dev.to/sendotltd/statue-park-the-no-touching-rule-isnt-a-rule-and-the-circle-that-names-nothing-costs-60-more-36f2</link>
      <guid>https://dev.to/sendotltd/statue-park-the-no-touching-rule-isnt-a-rule-and-the-circle-that-names-nothing-costs-60-more-36f2</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Statue Park&lt;/strong&gt; in the browser with &lt;strong&gt;five rule sets&lt;/strong&gt; inside. The clue is a&lt;br&gt;
bag of polyominoes: shade cells so the shaded groups are exactly that bag, and&lt;br&gt;
keep the unshaded cells — the &lt;strong&gt;park&lt;/strong&gt; — in one piece. Puzzle #50 in the solver&lt;br&gt;
series.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Demo: &lt;a href="https://sen.ltd/portfolio/statue-park/" rel="noopener noreferrer"&gt;https://sen.ltd/portfolio/statue-park/&lt;/a&gt;&lt;br&gt;
Repo: &lt;a href="https://github.com/sen-ltd/statue-park" rel="noopener noreferrer"&gt;https://github.com/sen-ltd/statue-park&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqo2t7cd4fofli6figimu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqo2t7cd4fofli6figimu.png" alt="Statue Park" width="800" height="616"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  The rules
&lt;/h2&gt;

&lt;p&gt;Shade some cells of an &lt;code&gt;H×W&lt;/code&gt; grid.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The shaded cells fall into orthogonally connected groups. The &lt;strong&gt;multiset of
their shapes&lt;/strong&gt;, up to rotation and reflection, must equal the given &lt;strong&gt;bank&lt;/strong&gt; —
every piece used exactly once.&lt;/li&gt;
&lt;li&gt;The unshaded cells — the &lt;strong&gt;park&lt;/strong&gt; — form one orthogonally connected region.&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;black circle&lt;/strong&gt; must be shaded. A &lt;strong&gt;white circle&lt;/strong&gt; must not be.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;There is not a single number anywhere. The clue is the bag, plus the circles.&lt;/p&gt;
&lt;h2&gt;
  
  
  The most famous rule is not a rule
&lt;/h2&gt;

&lt;p&gt;Every write-up of Statue Park lists &lt;strong&gt;"two pieces may not touch"&lt;/strong&gt; among the&lt;br&gt;
rules. It isn't one.&lt;/p&gt;

&lt;p&gt;A &lt;em&gt;maximal&lt;/em&gt; connected group of shaded cells is never orthogonally adjacent to&lt;br&gt;
another maximal group — that is what maximal means. So the moment you take the&lt;br&gt;
answer to be a &lt;strong&gt;shading&lt;/strong&gt; rather than an assignment of placements to pieces, the&lt;br&gt;
non-touching rule is free.&lt;/p&gt;

&lt;p&gt;What is left over is that the rulebook's model &lt;strong&gt;names&lt;/strong&gt; its pieces, and the name&lt;br&gt;
is unobservable. Therefore:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Two banks with the same shape multiset give the same shadings, and the&lt;br&gt;
&lt;strong&gt;labelled count = the shading count × ∏ mₜ!&lt;/strong&gt;, one factorial per repeated&lt;br&gt;
shape.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is not an interpretation, it is a measurable claim. The repo ships two brute&lt;br&gt;
force engines that share no code with the propagators. On 5×5:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;bank&lt;/th&gt;
&lt;th&gt;shadings&lt;/th&gt;
&lt;th&gt;labelled&lt;/th&gt;
&lt;th&gt;ratio&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;2 × the same tetromino&lt;/td&gt;
&lt;td&gt;48&lt;/td&gt;
&lt;td&gt;96&lt;/td&gt;
&lt;td&gt;2 = 2!&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3 × the same tetromino&lt;/td&gt;
&lt;td&gt;16&lt;/td&gt;
&lt;td&gt;96&lt;/td&gt;
&lt;td&gt;6 = 3!&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;one A + two B&lt;/td&gt;
&lt;td&gt;152&lt;/td&gt;
&lt;td&gt;304&lt;/td&gt;
&lt;td&gt;2 = 2!&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Two practical payoffs. &lt;strong&gt;No symmetry breaking anywhere&lt;/strong&gt; — the trick you would&lt;br&gt;
otherwise need to stop equal pieces permuting simply does not exist in the&lt;br&gt;
shading model. And &lt;strong&gt;two answers always differ as sets of cells&lt;/strong&gt;, which is what&lt;br&gt;
the next section stands on.&lt;/p&gt;
&lt;h2&gt;
  
  
  Theorem: black circles alone always suffice, and so do white circles alone
&lt;/h2&gt;

&lt;p&gt;Two answers to the same bank shade the &lt;strong&gt;same number of cells&lt;/strong&gt;, because the bank&lt;br&gt;
fixes the total area. So if two answers differ, then&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;there is a cell shaded in A and not in B, &lt;strong&gt;and&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;there is a cell shaded in B and not in A.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;(Equal totals, so it cannot be one-sided.)&lt;/p&gt;

&lt;p&gt;Print a black circle on the first and B dies. Print a white circle on the second&lt;br&gt;
and B dies. So a &lt;strong&gt;black-only clue set exists and a white-only clue set exists,&lt;br&gt;
for every puzzle&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Existence is settled. What is left is the price.&lt;/p&gt;
&lt;h2&gt;
  
  
  Measurement: white circles cost about 60% more
&lt;/h2&gt;

&lt;p&gt;Same greedy chooser (look at the second answer, pick a cell where it disagrees&lt;br&gt;
with the intended one, print a circle there), same minimisation afterwards. Only&lt;br&gt;
the alphabet changes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;size  n   mixed  black-only  white-only   black share of mixed   shaded share of board
6x6  40     6.0         5.1         8.1                  55.2%                   36.2%
8x8  23    13.0        11.3        18.6                  63.0%                   34.7%
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;White-only needs 18.6 circles at 8×8 where black-only needs 11.3. The explanation&lt;br&gt;
is available after the fact: a white circle only says "no statue here", which&lt;br&gt;
kills placements one at a time; a black circle says "a statue passes through&lt;br&gt;
here", which is a claim about &lt;strong&gt;a whole piece&lt;/strong&gt;, and it kills every placement of&lt;br&gt;
every piece that cannot cover that cell.&lt;/p&gt;

&lt;p&gt;The interesting column is the third one. &lt;strong&gt;Restricting the greedy chooser to black&lt;br&gt;
circles beats letting it choose freely&lt;/strong&gt; (11.3 vs 13.0 at 8×8). The chooser picks&lt;br&gt;
uniformly among the disagreeing cells, so left alone it keeps buying cheap white&lt;br&gt;
circles. Adding a constraint made it better — a clean example of that.&lt;/p&gt;

&lt;p&gt;Corroborating: in the freely-chosen sets, &lt;strong&gt;55–63% of the surviving circles are&lt;br&gt;
black&lt;/strong&gt;, while only &lt;strong&gt;35–36%&lt;/strong&gt; of the board is shaded. Minimisation keeps black&lt;br&gt;
circles at nearly twice their base rate.&lt;/p&gt;
&lt;h2&gt;
  
  
  Five rungs
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;rung&lt;/th&gt;
&lt;th&gt;what it may know&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;clue&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;the circles, plus the &lt;strong&gt;head count&lt;/strong&gt; — the bank fixes how many cells are shaded&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;place&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;the catalogue of legal placements; a placement dies when one of its cells is known park, or a cell touching it is known shaded&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;fit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;a shaded cell belongs to exactly one piece, so a neighbour that no surviving placement joins to it is park&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;white&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;the park stays connected, including the cut vertices that would strand part of it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;probe&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;singleton consistency over everything above&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Every rung is sound (its fixpoint never disagrees with the answer — asserted in&lt;br&gt;
the tests) and monotone (a stronger rung never decides fewer cells).&lt;/p&gt;
&lt;h3&gt;
  
  
  Incremental: nothing below &lt;code&gt;probe&lt;/code&gt; ever finishes a board
&lt;/h3&gt;

&lt;p&gt;Fixpoint on the board an editor would print — the minimal circle set that buys&lt;br&gt;
uniqueness:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;size  n      clue   place     fit   white   probe   completions
6x6  40    16.7%   18.8%   25.3%   29.1%   74.0%   clue:0 place:0 fit:0 white:0 probe:26
8x8  24    20.5%   22.6%   25.7%   29.2%   48.9%   clue:0 place:0 fit:0 white:0 probe:5
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The bottom four rungs all stall under 30% and &lt;code&gt;probe&lt;/code&gt; jumps. &lt;strong&gt;There are no&lt;br&gt;
&lt;code&gt;clue&lt;/code&gt;-, &lt;code&gt;place&lt;/code&gt;-, &lt;code&gt;fit&lt;/code&gt;- or &lt;code&gt;white&lt;/code&gt;-graded puzzles at all.&lt;/strong&gt; If you want a&lt;br&gt;
difficulty ladder in the shipped bank you have to buy it, by adding circles until&lt;br&gt;
a weaker rung can finish. That turns out to be nearly free:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;size  n   unique-min  solve-min   ratio
6x6  40         6.0        6.5    1.08
8x8  24        13.1       14.3    1.09
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Ten percent more circles than uniqueness needs, and the board no longer needs a&lt;br&gt;
search at all.&lt;/strong&gt; Uniqueness drags search-freeness along almost for nothing.&lt;/p&gt;
&lt;h3&gt;
  
  
  Ablation: all four rungs are load-bearing
&lt;/h3&gt;

&lt;p&gt;Same boards, full stack minus one rung:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;size  variant   fixpoint-bits  boards moved  probe assumptions  search assumptions
6x6  full              1440             0               3098                   0
6x6  −count            1426             1               3385                   2
6x6  −place             736            35               5461                2136
6x6  −fit               834            25               6368                 122
6x6  −white             629            36               4289                1002
8x8  full              1536             0               4274                   0
8x8  −count            1404             6               4543                  28
8x8  −place             845            24               6122               23790
8x8  −fit               807            21               7804                 254
8x8  −white             528            24               4741                5700
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The row worth staring at is &lt;code&gt;count&lt;/code&gt;. The head count is &lt;strong&gt;nearly free at the&lt;br&gt;
fixpoint&lt;/strong&gt; — it moves one board in forty at 6×6, fourteen bits across all forty —&lt;br&gt;
and it is &lt;strong&gt;not&lt;/strong&gt; free in the search (0 → 28 assumptions at 8×8). Incremental&lt;br&gt;
numbers alone would have called it dead weight. In the other direction, dropping&lt;br&gt;
&lt;code&gt;place&lt;/code&gt; at 8×8 makes the search buy 23,790 assumptions.&lt;/p&gt;
&lt;h2&gt;
  
  
  Ambiguity is not one piece sliding over
&lt;/h2&gt;

&lt;p&gt;Peel circles off until a board goes ambiguous, then compare the second answer to&lt;br&gt;
the intended one, component by component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;size  ambiguous  one piece moved  two    three or more   avg pieces moved
6x6         40            17.5% 42.5%           40.0%               2.23
8x8         24            16.7% 25.0%           58.3%               3.13
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In earlier entries of this series a cheap search-free certificate — a two-cell&lt;br&gt;
swap, a 2-opt reversal, a whole row sliding — explained 90%+ of second answers.&lt;br&gt;
Statue Park &lt;strong&gt;does not do that&lt;/strong&gt;. The second answer moves two or three pieces on&lt;br&gt;
average and only one board in six moves exactly one. There is no cheap local&lt;br&gt;
certificate here, and given that the bank is an inherently &lt;strong&gt;global&lt;/strong&gt; clue (where&lt;br&gt;
one piece can go depends on where all the others went), that is probably the&lt;br&gt;
honest picture rather than a gap in the analysis.&lt;/p&gt;
&lt;h2&gt;
  
  
  How much is the park rule actually worth?
&lt;/h2&gt;

&lt;p&gt;Count answers to the bank constraint alone, then again with the park rule on, no&lt;br&gt;
circles either way:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;config          boards  with park  without park   killed
6x6 2x size4/5      30        833          1399    40.4%
6x6 3x size4        30       5730         15149    62.2%
6x6 3x size5        30        704          4431    84.1%
7x7 3x size5        30      18744         57546    67.4%
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The bigger the pieces the bigger the connectivity rule's share — pentominoes cut&lt;br&gt;
the park more easily, so at three pentominoes on 6×6 it is throwing away 84% of&lt;br&gt;
the answer space on its own. Give the same three pentominoes more room (7×7) and&lt;br&gt;
its share drops to 67%: the rule bites hardest when the board is tight.&lt;/p&gt;
&lt;h2&gt;
  
  
  The generator never guesses at a bank
&lt;/h2&gt;

&lt;p&gt;No "draw a partition, print clues, pray a solution exists". &lt;strong&gt;Answer first&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Drop pieces one at a time at a random legal spot, never touching an existing
piece.&lt;/li&gt;
&lt;li&gt;After every drop, check the park is still connected, and refuse placements
that would cut it.&lt;/li&gt;
&lt;li&gt;When the last piece lands, that &lt;strong&gt;already is a legal answer&lt;/strong&gt; — so the bank is
read off it rather than guessed at.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Legality is structural, so only uniqueness has to be bought: look at the second&lt;br&gt;
answer, print a circle where it disagrees, then minimise the set.&lt;/p&gt;
&lt;h2&gt;
  
  
  Soundness
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Three engines agree.&lt;/strong&gt; The propagating search, a placement-first brute force,
and a cells-first brute force that never names a piece. Solution counts agree on
80 clue sets at 6×6, zero disagreements — and the count does not change across
the rungs of the ladder either.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;External ledger.&lt;/strong&gt; Give the bank &lt;code&gt;k&lt;/code&gt; monominoes and switch the park rule off,
and an answer is exactly a &lt;code&gt;k&lt;/code&gt;-element &lt;strong&gt;independent set in the grid graph&lt;/strong&gt;.
Summed over &lt;code&gt;k&lt;/code&gt; that has to be &lt;code&gt;2, 7, 63, 1234, 55447&lt;/code&gt; —
&lt;a href="https://oeis.org/A006506" rel="noopener noreferrer"&gt;OEIS A006506&lt;/a&gt;. The tests check it per &lt;code&gt;k&lt;/code&gt; against a
separate independent-set counter, and check the totals.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Closed form on a 1×m strip.&lt;/strong&gt; The park is connected only if the unshaded cells
are contiguous, so the shaded cells are a prefix plus a suffix; with monominoes
each end holds at most one, giving 1, 2, 1 (for m ≥ 3), 0 for k = 0,1,2,3. The
tests reproduce it for every m.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;probe&lt;/code&gt; ⇔ unique.&lt;/strong&gt; Sweeping 300 clue prefixes at 6×6 and 364 at 8×8: &lt;strong&gt;zero
boards where &lt;code&gt;probe&lt;/code&gt; finished but the answer was not unique.&lt;/strong&gt; The other
direction happens — six and four boards are unique without &lt;code&gt;probe&lt;/code&gt; seeing it —
for 98.0% and 98.9% agreement. &lt;code&gt;probe&lt;/code&gt; never lies; it just does not see
everything.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;69 tests.&lt;/p&gt;
&lt;h2&gt;
  
  
  The implementation lesson
&lt;/h2&gt;

&lt;p&gt;The thing that cost the most time was the brute force engine that does &lt;em&gt;not&lt;/em&gt; name&lt;br&gt;
its pieces. It walks the cells in reading order, shades or doesn't, and whenever&lt;br&gt;
a shaded group is &lt;strong&gt;sealed off&lt;/strong&gt; — every neighbour decided — it charges that&lt;br&gt;
shape against the bank.&lt;/p&gt;

&lt;p&gt;The bug: sealed groups were recomputed from scratch at every step. A group sealed&lt;br&gt;
at step &lt;code&gt;i&lt;/code&gt; is still sealed at step &lt;code&gt;i+1&lt;/code&gt;, so &lt;strong&gt;the same piece was charged to the&lt;br&gt;
bank twice&lt;/strong&gt;. It only misbehaves on banks with a repeated shape, and it only ever&lt;br&gt;
loses answers — the quiet kind of wrong.&lt;/p&gt;

&lt;p&gt;The fix was one array of "cells already charged", rolled back on backtrack. The&lt;br&gt;
lesson has the usual shape: &lt;strong&gt;you write the brute force engine to check that the&lt;br&gt;
fast implementation is right, and the brute force engine is the thing that breaks&lt;br&gt;
most quietly.&lt;/strong&gt; Which is why the soundness claim cannot rest on one engine — the&lt;br&gt;
placement-first engine cannot make this mistake structurally (each placement is&lt;br&gt;
handed to exactly one bank slot, so double-charging has nowhere to happen), so&lt;br&gt;
agreement between the two &lt;em&gt;is&lt;/em&gt; the detector.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;src/statue-park.ts   model, shapes, placement catalogue, five rungs, referee
src/brute.ts         two engines sharing no code with the propagators
src/generate.ts      answer-first layout and the circle-buying loop
tools/stats.mts      every table above
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;strong&gt;Demo&lt;/strong&gt;: &lt;a href="https://sen.ltd/portfolio/statue-park/" rel="noopener noreferrer"&gt;https://sen.ltd/portfolio/statue-park/&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Repo&lt;/strong&gt;: &lt;a href="https://github.com/sen-ltd/statue-park" rel="noopener noreferrer"&gt;https://github.com/sen-ltd/statue-park&lt;/a&gt;&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>algorithms</category>
      <category>gamedev</category>
      <category>puzzle</category>
    </item>
    <item>
      <title>Country Road: contract the countries and it is a Hamiltonian cycle — and that is the easy half</title>
      <dc:creator>SEN LLC</dc:creator>
      <pubDate>Sat, 29 Aug 2026 15:07:10 +0000</pubDate>
      <link>https://dev.to/sendotltd/country-road-contract-the-countries-and-it-is-a-hamiltonian-cycle-and-that-is-the-easy-half-3686</link>
      <guid>https://dev.to/sendotltd/country-road-contract-the-countries-and-it-is-a-hamiltonian-cycle-and-that-is-the-easy-half-3686</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Country Road&lt;/strong&gt; in the browser with &lt;strong&gt;five rule sets&lt;/strong&gt; inside. The grid is&lt;br&gt;
cut into countries; one closed loop visits &lt;strong&gt;every country exactly once&lt;/strong&gt;; a&lt;br&gt;
number says how many of that country's cells the loop uses; and two cells&lt;br&gt;
facing each other across a border may not both be empty. Puzzle #49 in the&lt;br&gt;
solver series.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Demo: &lt;a href="https://sen.ltd/portfolio/country-road/" rel="noopener noreferrer"&gt;https://sen.ltd/portfolio/country-road/&lt;/a&gt;&lt;br&gt;
Repo: &lt;a href="https://github.com/sen-ltd/country-road" rel="noopener noreferrer"&gt;https://github.com/sen-ltd/country-road&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsen.ltd%2Fportfolio%2Fcountry-road%2Fassets%2Fscreenshot.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsen.ltd%2Fportfolio%2Fcountry-road%2Fassets%2Fscreenshot.png" alt="Country Road" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  The rules
&lt;/h2&gt;

&lt;p&gt;The grid is cut into &lt;strong&gt;countries&lt;/strong&gt;. Draw &lt;strong&gt;one closed loop&lt;/strong&gt; through cell&lt;br&gt;
centres, orthogonally, never crossing itself. Then:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The loop visits &lt;strong&gt;every country exactly once&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;A number in a country says &lt;strong&gt;how many of its cells the loop uses&lt;/strong&gt;.
Unnumbered countries are unconstrained.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Two orthogonally adjacent cells in different countries may not both be off
the loop.&lt;/strong&gt; (Two empty cells &lt;em&gt;inside&lt;/em&gt; one country are fine.)&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  Contract the countries and this is a Hamiltonian cycle problem
&lt;/h2&gt;

&lt;p&gt;Shrink each country to a single node; join two nodes when their countries share&lt;br&gt;
a border. Rule 1 then says the loop's country order is a cyclic sequence hitting&lt;br&gt;
every node exactly once:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The loop induces a Hamiltonian cycle on the region adjacency graph.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Two consequences, and the whole solver is built around them.&lt;/p&gt;
&lt;h3&gt;
  
  
  A cut vertex is a proof of impossibility
&lt;/h3&gt;

&lt;p&gt;Every Hamiltonian graph is 2-connected. So &lt;strong&gt;a partition whose region graph has&lt;br&gt;
a cut vertex or a bridge admits no solution at all&lt;/strong&gt; — for any numbers&lt;br&gt;
whatsoever.&lt;/p&gt;

&lt;p&gt;The cleanest counterexample is the strip partition. Make every row a country and&lt;br&gt;
the region graph is a path, so everything but the two ends is a cut vertex:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  n×n cut into rows: cut vertex true, Hamiltonian false, solutions 0   (n = 4, 5, 6)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;hasCutVertex&lt;/code&gt; is Hopcroft–Tarjan, &lt;code&gt;O(V+E)&lt;/code&gt;, and it rejects the board &lt;strong&gt;without&lt;br&gt;
looking at a single number&lt;/strong&gt;. The brute-force counter, which knows nothing about&lt;br&gt;
graphs, independently returns 0.&lt;/p&gt;
&lt;h3&gt;
  
  
  "Two border crossings per country" is a 2-factor, not a Hamiltonian cycle
&lt;/h3&gt;

&lt;p&gt;The loop enters a country once and leaves once, so exactly &lt;strong&gt;two&lt;/strong&gt; of its border&lt;br&gt;
edges are used. As a relaxation that is degree-two on every node of the region&lt;br&gt;
graph — a &lt;strong&gt;2-factor&lt;/strong&gt; — and the gap between a 2-factor and a Hamiltonian cycle&lt;br&gt;
is exactly the subtour that TSP practitioners spend their lives eliminating.&lt;/p&gt;

&lt;p&gt;The ladder is that structure, one rung at a time:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;rung&lt;/th&gt;
&lt;th&gt;what it knows&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;region&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;cell-level bookkeeping: an empty cell carries no road, a used edge puts both ends on the road, two empty cells may not face each other across a border, and a number bounds how many cells are used&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;once&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;every country exactly once: exactly two border edges used, at least one cell on the road, the same border never crossed twice, and a country's road cells connected &lt;strong&gt;inside&lt;/strong&gt; the country&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;loop&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;the loop's own structure: degree two, dead ends, cycles that close too early or skip a country, road cells stranded out of reach&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;macro&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Hamiltonicity of the region graph. Every Hamiltonian cycle is enumerated &lt;strong&gt;once per puzzle&lt;/strong&gt; into a bitmask catalogue; propagating is then set arithmetic — keep the cycles containing every crossed border and avoiding every closed one, then read the union (a border on no cycle dies) and the intersection (a border on every cycle is forced)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;probe&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;singleton consistency, on cells &lt;strong&gt;and on edges&lt;/strong&gt; — a board can have every cell decided and still two ways to thread the road through them&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;macro&lt;/code&gt; is the subtour elimination. Every propagator is &lt;strong&gt;sound&lt;/strong&gt;, so a rung&lt;br&gt;
that finishes a board without guessing is also a proof that the board has&lt;br&gt;
exactly one solution.&lt;/p&gt;
&lt;h2&gt;
  
  
  What each rung reaches
&lt;/h2&gt;

&lt;p&gt;Share of the board's bits — every cell and every grid edge — decided at the&lt;br&gt;
rung's fixpoint, starting from a board with &lt;em&gt;every&lt;/em&gt; country numbered:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;size&lt;/th&gt;
&lt;th&gt;boards&lt;/th&gt;
&lt;th&gt;region&lt;/th&gt;
&lt;th&gt;once&lt;/th&gt;
&lt;th&gt;loop&lt;/th&gt;
&lt;th&gt;macro&lt;/th&gt;
&lt;th&gt;probe&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;6×6&lt;/td&gt;
&lt;td&gt;80&lt;/td&gt;
&lt;td&gt;14.9%&lt;/td&gt;
&lt;td&gt;15.1%&lt;/td&gt;
&lt;td&gt;18.3%&lt;/td&gt;
&lt;td&gt;30.5%&lt;/td&gt;
&lt;td&gt;63.4%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8×8&lt;/td&gt;
&lt;td&gt;80&lt;/td&gt;
&lt;td&gt;18.1%&lt;/td&gt;
&lt;td&gt;18.2%&lt;/td&gt;
&lt;td&gt;20.5%&lt;/td&gt;
&lt;td&gt;33.4%&lt;/td&gt;
&lt;td&gt;77.8%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10×10&lt;/td&gt;
&lt;td&gt;40&lt;/td&gt;
&lt;td&gt;18.3%&lt;/td&gt;
&lt;td&gt;18.4%&lt;/td&gt;
&lt;td&gt;19.8%&lt;/td&gt;
&lt;td&gt;30.1%&lt;/td&gt;
&lt;td&gt;72.8%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Nothing below &lt;code&gt;probe&lt;/code&gt; finishes boards to speak of — &lt;code&gt;macro&lt;/code&gt; completes 1.3% at&lt;br&gt;
6×6 and 0.0% above it. The shipped bank agrees: the weakest grade it could find&lt;br&gt;
is &lt;code&gt;loop&lt;/code&gt; at 6×6, &lt;code&gt;macro&lt;/code&gt; at 8×8, &lt;code&gt;probe&lt;/code&gt; at 10×10. &lt;strong&gt;No board at any size falls&lt;br&gt;
to &lt;code&gt;region&lt;/code&gt; or &lt;code&gt;once&lt;/code&gt; alone.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Ablation: drop one rung from the full ladder
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;size&lt;/th&gt;
&lt;th&gt;drop&lt;/th&gt;
&lt;th&gt;bits lost at the fixpoint&lt;/th&gt;
&lt;th&gt;boards moved&lt;/th&gt;
&lt;th&gt;probe assumptions&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;6×6&lt;/td&gt;
&lt;td&gt;−region&lt;/td&gt;
&lt;td&gt;889&lt;/td&gt;
&lt;td&gt;40/40&lt;/td&gt;
&lt;td&gt;+31.6%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6×6&lt;/td&gt;
&lt;td&gt;−once&lt;/td&gt;
&lt;td&gt;71&lt;/td&gt;
&lt;td&gt;9/40&lt;/td&gt;
&lt;td&gt;+9.4%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6×6&lt;/td&gt;
&lt;td&gt;−loop&lt;/td&gt;
&lt;td&gt;482&lt;/td&gt;
&lt;td&gt;36/40&lt;/td&gt;
&lt;td&gt;+28.5%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6×6&lt;/td&gt;
&lt;td&gt;−macro&lt;/td&gt;
&lt;td&gt;607&lt;/td&gt;
&lt;td&gt;32/40&lt;/td&gt;
&lt;td&gt;+39.2%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8×8&lt;/td&gt;
&lt;td&gt;−region&lt;/td&gt;
&lt;td&gt;1240&lt;/td&gt;
&lt;td&gt;30/30&lt;/td&gt;
&lt;td&gt;+110.9%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8×8&lt;/td&gt;
&lt;td&gt;−once&lt;/td&gt;
&lt;td&gt;59&lt;/td&gt;
&lt;td&gt;10/30&lt;/td&gt;
&lt;td&gt;+46.5%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8×8&lt;/td&gt;
&lt;td&gt;−loop&lt;/td&gt;
&lt;td&gt;458&lt;/td&gt;
&lt;td&gt;30/30&lt;/td&gt;
&lt;td&gt;+116.8%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8×8&lt;/td&gt;
&lt;td&gt;−macro&lt;/td&gt;
&lt;td&gt;591&lt;/td&gt;
&lt;td&gt;25/30&lt;/td&gt;
&lt;td&gt;+57.8%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;once&lt;/code&gt; is the row worth staring at. It is nearly free at the fixpoint — 59 bits&lt;br&gt;
across 30 boards at 8×8, and it moves only a third of them — and yet removing it&lt;br&gt;
makes the search buy the same facts back at &lt;strong&gt;46.5% more assumptions&lt;/strong&gt;.&lt;br&gt;
Incremental reach and ablation point in opposite directions about it, so both&lt;br&gt;
get reported.&lt;/p&gt;
&lt;h2&gt;
  
  
  And then the Hamiltonian cycle turns out to be the easy half
&lt;/h2&gt;

&lt;p&gt;The framing above makes the macro problem sound like the hard part. It is not,&lt;br&gt;
and finding out is one measurement: take the ambiguous boards and ask what the&lt;br&gt;
&lt;strong&gt;second solution&lt;/strong&gt; changes.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;size&lt;/th&gt;
&lt;th&gt;ambiguous boards&lt;/th&gt;
&lt;th&gt;second solution walks the same country order&lt;/th&gt;
&lt;th&gt;a different one&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;6×6&lt;/td&gt;
&lt;td&gt;51&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;92.2%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;7.8%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8×8&lt;/td&gt;
&lt;td&gt;34&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;85.3%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;14.7%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Nearly all ambiguity is micro: same countries, same order, different cells used&lt;br&gt;
inside them. Which is precisely the job of the numbers — and the numbers mostly&lt;br&gt;
do not do it. With &lt;strong&gt;every&lt;/strong&gt; country numbered, only 18.0% of 6×6 boards and&lt;br&gt;
10.0% of 8×8 boards are unique.&lt;/p&gt;

&lt;p&gt;The correlation even runs backwards:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Hamiltonian cycles in the region graph&lt;/th&gt;
&lt;th&gt;6×6 boards&lt;/th&gt;
&lt;th&gt;unique&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;exactly 1&lt;/td&gt;
&lt;td&gt;28&lt;/td&gt;
&lt;td&gt;7.1%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2–4&lt;/td&gt;
&lt;td&gt;45&lt;/td&gt;
&lt;td&gt;17.8%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5–16&lt;/td&gt;
&lt;td&gt;26&lt;/td&gt;
&lt;td&gt;30.8%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;A board with no macro freedom at all is the least likely to be unique.&lt;/strong&gt; The&lt;br&gt;
confound is country size: small countries make the region graph dense (many&lt;br&gt;
macro cycles) &lt;em&gt;and&lt;/em&gt; leave no room to route inside a country. Turn that dial&lt;br&gt;
directly and the whole effect is size's:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;size&lt;/th&gt;
&lt;th&gt;avg country&lt;/th&gt;
&lt;th&gt;unique&lt;/th&gt;
&lt;th&gt;median macro cycles&lt;/th&gt;
&lt;th&gt;ladder reach&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;6×6&lt;/td&gt;
&lt;td&gt;2.5&lt;/td&gt;
&lt;td&gt;40.0%&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;41.6%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6×6&lt;/td&gt;
&lt;td&gt;3.5&lt;/td&gt;
&lt;td&gt;20.0%&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;33.3%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6×6&lt;/td&gt;
&lt;td&gt;4.5&lt;/td&gt;
&lt;td&gt;6.7%&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;27.7%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6×6&lt;/td&gt;
&lt;td&gt;6.0&lt;/td&gt;
&lt;td&gt;3.3%&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;21.3%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8×8&lt;/td&gt;
&lt;td&gt;2.5&lt;/td&gt;
&lt;td&gt;18.3%&lt;/td&gt;
&lt;td&gt;54&lt;/td&gt;
&lt;td&gt;34.6%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8×8&lt;/td&gt;
&lt;td&gt;6.0&lt;/td&gt;
&lt;td&gt;1.7%&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;22.7%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;h2&gt;
  
  
  The partition can be a wall, so don't start from one
&lt;/h2&gt;

&lt;p&gt;Partition-first generation is a trap, and the trap is measurable. Random&lt;br&gt;
partitions, before a single number exists:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;size&lt;/th&gt;
&lt;th&gt;countries&lt;/th&gt;
&lt;th&gt;cut vertex&lt;/th&gt;
&lt;th&gt;region graph Hamiltonian&lt;/th&gt;
&lt;th&gt;board solvable&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;6×6&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;13.3%&lt;/td&gt;
&lt;td&gt;86.7%&lt;/td&gt;
&lt;td&gt;83.3%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6×6&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;11.7%&lt;/td&gt;
&lt;td&gt;88.3%&lt;/td&gt;
&lt;td&gt;74.2%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6×6&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;4.2%&lt;/td&gt;
&lt;td&gt;95.8%&lt;/td&gt;
&lt;td&gt;84.2%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6×6&lt;/td&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;0.0%&lt;/td&gt;
&lt;td&gt;100.0%&lt;/td&gt;
&lt;td&gt;90.0%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Hamiltonicity of the region graph is necessary but &lt;strong&gt;not sufficient&lt;/strong&gt;: the gap&lt;br&gt;
between the last two columns is the micro problem refusing to route.&lt;/p&gt;

&lt;p&gt;So the generator runs the other way, and cannot dead-end:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Inflate&lt;/strong&gt; one closed loop. Start from a 2×2 square, repeatedly push an edge
out into the neighbouring 2×2 and replace it with a three-edge detour. The
result is a single closed circuit by construction — no rejection, no
connectivity check.&lt;/li&gt;
&lt;li&gt;Cut the loop into consecutive &lt;strong&gt;arcs&lt;/strong&gt;. Each arc seeds one country, so the
loop already visits every country once and &lt;strong&gt;the arc order is a Hamiltonian
cycle on the region graph.&lt;/strong&gt; The macro problem is solved before the board
exists.&lt;/li&gt;
&lt;li&gt;Hand every connected blob of off-loop cells to one country &lt;strong&gt;whole&lt;/strong&gt; — which
is exactly rule 3.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Legality is structural. Only uniqueness has to be bought, by erasing numbers for&lt;br&gt;
as long as the ladder still finishes:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;size&lt;/th&gt;
&lt;th&gt;countries&lt;/th&gt;
&lt;th&gt;numbers kept (adversarial)&lt;/th&gt;
&lt;th&gt;numbers kept (random erasure)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;6×6&lt;/td&gt;
&lt;td&gt;6.7&lt;/td&gt;
&lt;td&gt;2.9&lt;/td&gt;
&lt;td&gt;5.4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8×8&lt;/td&gt;
&lt;td&gt;11.3&lt;/td&gt;
&lt;td&gt;4.7&lt;/td&gt;
&lt;td&gt;10.1&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;h2&gt;
  
  
  Three engines, and a number from outside the repository
&lt;/h2&gt;

&lt;p&gt;Every board is counted three ways that share only the geometry helpers: a&lt;br&gt;
propagating search, a cells-first brute force (fix the cells, count the&lt;br&gt;
routings), and a loops-first brute force (enumerate every simple cycle of the&lt;br&gt;
grid, read the empty cells off as the complement). They agree on &lt;strong&gt;60/60&lt;/strong&gt;&lt;br&gt;
boards.&lt;/p&gt;

&lt;p&gt;And the whole thing is pinned to a count that exists outside this repo. Give&lt;br&gt;
&lt;strong&gt;every cell its own country&lt;/strong&gt; and rule 1 becomes "visit every cell exactly&lt;br&gt;
once", so a clue-free board has as many solutions as the grid graph has&lt;br&gt;
Hamiltonian cycles — OEIS &lt;a href="https://oeis.org/A003763" rel="noopener noreferrer"&gt;A003763&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  2×2 singletons: 1      4×4: 6      6×6: 1072
  2×m strips:     1, for every m from 3 to 8
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;"Finished without search ⇔ unique" is checked against brute force in both&lt;br&gt;
directions on 120 boards: 0 finished-but-ambiguous, 0 unique-but-stalled. 37&lt;br&gt;
tests in all.&lt;/p&gt;
&lt;h2&gt;
  
  
  One debugging lesson
&lt;/h2&gt;

&lt;p&gt;The bug that cost the most time was in &lt;code&gt;loop&lt;/code&gt;'s premature-closure test. It&lt;br&gt;
compared the size of a closed component against the number of cells &lt;em&gt;known&lt;/em&gt; to&lt;br&gt;
be on the road — and within a single pass an edge can be forced after its&lt;br&gt;
endpoint was last looked at. One cell that is on the road by its edges but still&lt;br&gt;
blank in the cell array makes a finished loop look one cell too long, and a&lt;br&gt;
sound-looking propagator kills the correct solution.&lt;/p&gt;

&lt;p&gt;The way it surfaced is the standard harness for this series: every rung's&lt;br&gt;
fixpoint must agree, bit for bit, with &lt;strong&gt;every&lt;/strong&gt; solution brute force returns. If&lt;br&gt;
one propagator is unsound, "finished without search" stops being a uniqueness&lt;br&gt;
proof, and everything built on top of it — the grades, the bank, the ablation&lt;br&gt;
tables — is quietly wrong.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;src/country-road.ts   rules, geometry, five rungs, referee, region-graph theorems
src/brute.ts          two brute-force counters sharing nothing but geometry
src/generate.ts       loop-first generation, partitions, clue erosion
tools/stats.mts       every table in this article
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;strong&gt;Demo&lt;/strong&gt;: &lt;a href="https://sen.ltd/portfolio/country-road/" rel="noopener noreferrer"&gt;https://sen.ltd/portfolio/country-road/&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Repo&lt;/strong&gt;: &lt;a href="https://github.com/sen-ltd/country-road" rel="noopener noreferrer"&gt;https://github.com/sen-ltd/country-road&lt;/a&gt;&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>algorithms</category>
      <category>gamedev</category>
      <category>puzzle</category>
    </item>
    <item>
      <title>Creek: a puzzle with a closed form, and why the numbers on the edge of the paper are the ones to erase</title>
      <dc:creator>SEN LLC</dc:creator>
      <pubDate>Thu, 27 Aug 2026 23:31:17 +0000</pubDate>
      <link>https://dev.to/sendotltd/creek-a-puzzle-with-a-closed-form-and-why-the-numbers-on-the-edge-of-the-paper-are-the-ones-to-8od</link>
      <guid>https://dev.to/sendotltd/creek-a-puzzle-with-a-closed-form-and-why-the-numbers-on-the-edge-of-the-paper-are-the-ones-to-8od</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Creek&lt;/strong&gt; in the browser with &lt;strong&gt;five rule sets&lt;/strong&gt; inside. The numbers are not&lt;br&gt;
in the cells — they sit on the &lt;strong&gt;corners&lt;/strong&gt; of the grid, and each one counts&lt;br&gt;
the shaded cells among the (at most) four squares that touch it. Every&lt;br&gt;
unshaded cell must join one connected &lt;strong&gt;creek&lt;/strong&gt;. Puzzle #48 in the solver&lt;br&gt;
series.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Demo: &lt;a href="https://sen.ltd/portfolio/creek/" rel="noopener noreferrer"&gt;https://sen.ltd/portfolio/creek/&lt;/a&gt;&lt;br&gt;
Repo: &lt;a href="https://github.com/sen-ltd/creek" rel="noopener noreferrer"&gt;https://github.com/sen-ltd/creek&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsen.ltd%2Fportfolio%2Fcreek%2Fassets%2Fscreenshot.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsen.ltd%2Fportfolio%2Fcreek%2Fassets%2Fscreenshot.png" alt="Creek" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  This puzzle has a closed form
&lt;/h2&gt;

&lt;p&gt;A corner of the paper touches exactly &lt;strong&gt;one&lt;/strong&gt; cell, so it names that cell&lt;br&gt;
outright. An edge corner touches two, an interior corner four. Writing&lt;br&gt;
&lt;code&gt;C(i,j)&lt;/code&gt; for the number on corner &lt;code&gt;(i,j)&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;C(i,j) = x[i−1][j−1] + x[i−1][j] + x[i][j−1] + x[i][j]   (out-of-range terms dropped)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is the &lt;strong&gt;mixed second difference&lt;/strong&gt; of the board, and inclusion–exclusion&lt;br&gt;
inverts it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;x[r][c] = Σ_{i≤r, j≤c} (−1)^((r−i)+(c−j)) · C(i,j)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;The answer is the chequerboard-signed running total of the clues.&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;solveByScan&lt;/code&gt; in the repo is that formula in six lines.&lt;/p&gt;

&lt;p&gt;Measured on 600 random fully clued answers at each of 6×6, 8×8 and 10×10: the&lt;br&gt;
closed form reproduces the answer &lt;strong&gt;100%&lt;/strong&gt; of the time, the board is unique&lt;br&gt;
&lt;strong&gt;100%&lt;/strong&gt; of the time, and &lt;code&gt;count&lt;/code&gt; — the &lt;em&gt;weakest&lt;/em&gt; rung in the ladder, which&lt;br&gt;
does nothing but tally one corner — finishes &lt;strong&gt;100%&lt;/strong&gt; of them. Repeatedly&lt;br&gt;
counting a corner that has one unknown cell left &lt;em&gt;is&lt;/em&gt; that triangular scan.&lt;/p&gt;

&lt;p&gt;So there is no puzzle in a fully clued board. Everything difficult about&lt;br&gt;
Creek lives in the numbers the setter rubbed out.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;numbers kept (8×8, of 81)&lt;/th&gt;
&lt;th&gt;unique&lt;/th&gt;
&lt;th&gt;finished by &lt;code&gt;count&lt;/code&gt;
&lt;/th&gt;
&lt;th&gt;finished by the whole ladder&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;81 (100%)&lt;/td&gt;
&lt;td&gt;100.0%&lt;/td&gt;
&lt;td&gt;100.0%&lt;/td&gt;
&lt;td&gt;100.0%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;73 (90%)&lt;/td&gt;
&lt;td&gt;99.2%&lt;/td&gt;
&lt;td&gt;98.5%&lt;/td&gt;
&lt;td&gt;99.2%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;65 (80%)&lt;/td&gt;
&lt;td&gt;89.0%&lt;/td&gt;
&lt;td&gt;82.7%&lt;/td&gt;
&lt;td&gt;89.0%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;57 (70%)&lt;/td&gt;
&lt;td&gt;56.5%&lt;/td&gt;
&lt;td&gt;42.3%&lt;/td&gt;
&lt;td&gt;56.5%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;49 (60%)&lt;/td&gt;
&lt;td&gt;19.5%&lt;/td&gt;
&lt;td&gt;10.0%&lt;/td&gt;
&lt;td&gt;19.5%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;41 (50%)&lt;/td&gt;
&lt;td&gt;2.3%&lt;/td&gt;
&lt;td&gt;0.5%&lt;/td&gt;
&lt;td&gt;2.3%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;h2&gt;
  
  
  The ink on the edge of the paper is the ink you can throw away
&lt;/h2&gt;

&lt;p&gt;The corner clue is the most &lt;em&gt;powerful&lt;/em&gt; number on the board — it names a cell&lt;br&gt;
with no reasoning at all — and it is the one to erase. Take an answer and&lt;br&gt;
delete either (a) the whole border ring of corners, or (b) the same number of&lt;br&gt;
corners drawn from the interior:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;board&lt;/th&gt;
&lt;th&gt;erase the ring&lt;/th&gt;
&lt;th&gt;erase the same count from the interior&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;6×6 (24 numbers)&lt;/td&gt;
&lt;td&gt;unique &lt;strong&gt;92.5%&lt;/strong&gt;, dof left 11.00&lt;/td&gt;
&lt;td&gt;unique &lt;strong&gt;0.0%&lt;/strong&gt;, dof left 15.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8×8 (32 numbers)&lt;/td&gt;
&lt;td&gt;unique &lt;strong&gt;97.2%&lt;/strong&gt;, dof left 15.00&lt;/td&gt;
&lt;td&gt;unique &lt;strong&gt;0.0%&lt;/strong&gt;, dof left 19.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10×10 (40 numbers)&lt;/td&gt;
&lt;td&gt;unique &lt;strong&gt;99.7%&lt;/strong&gt;, dof left 19.00&lt;/td&gt;
&lt;td&gt;unique &lt;strong&gt;1.0%&lt;/strong&gt;, dof left 23.03&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The same number of equations goes away, and the &lt;strong&gt;rank barely moves&lt;/strong&gt; — four&lt;br&gt;
extra degrees of freedom out of a hundred variables. Uniqueness goes from&lt;br&gt;
~100% to ~0%.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The collapse is not about how big the kernel is. It is about what shape it&lt;br&gt;
is.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  The kernel is enormous and almost entirely illegal
&lt;/h2&gt;

&lt;p&gt;Erase the border ring and only genuine 2×2 windows remain. If two boards&lt;br&gt;
agree on every 2×2 sum, their difference &lt;code&gt;d&lt;/code&gt; has a chequerboard twist&lt;br&gt;
&lt;code&gt;e[i][j] = (−1)^(i+j) d[i][j]&lt;/code&gt; with vanishing mixed second difference, hence&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;e[i][j] = u_i + v_j
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and the kernel has dimension exactly &lt;strong&gt;w+h−1&lt;/strong&gt; (checked against the row&lt;br&gt;
reduction at eight different shapes).&lt;/p&gt;

&lt;p&gt;Now restrict &lt;code&gt;d&lt;/code&gt; to &lt;code&gt;{−1,0,+1}&lt;/code&gt;, since both boards are 0/1 matrices. The&lt;br&gt;
catalogue collapses to three shapes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;row&lt;/strong&gt; — one whole row flipped in chequerboard alternation,&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;col&lt;/strong&gt; — one whole column, likewise,&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;cross&lt;/strong&gt; — row &lt;em&gt;r&lt;/em&gt; and column &lt;em&gt;c&lt;/em&gt; with opposite signs, crossing cell
untouched.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;There is no small ambiguity in a border-erased Creek board.&lt;/strong&gt; The cheapest&lt;br&gt;
second solution costs an entire row. Which is why:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;board&lt;/th&gt;
&lt;th&gt;kernel dimension&lt;/th&gt;
&lt;th&gt;±1 sign patterns&lt;/th&gt;
&lt;th&gt;still unique&lt;/th&gt;
&lt;th&gt;has a legal flip&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;6×6&lt;/td&gt;
&lt;td&gt;11&lt;/td&gt;
&lt;td&gt;2,048&lt;/td&gt;
&lt;td&gt;93.2%&lt;/td&gt;
&lt;td&gt;6.5% (row 23, col 15, cross 1)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8×8&lt;/td&gt;
&lt;td&gt;15&lt;/td&gt;
&lt;td&gt;32,768&lt;/td&gt;
&lt;td&gt;98.2%&lt;/td&gt;
&lt;td&gt;1.8% (row 5, col 6, cross 0)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10×10&lt;/td&gt;
&lt;td&gt;19&lt;/td&gt;
&lt;td&gt;524,288&lt;/td&gt;
&lt;td&gt;100.0%&lt;/td&gt;
&lt;td&gt;0.0%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;findFlipCertificate&lt;/code&gt; walks that catalogue with no search at all. It explains&lt;br&gt;
&lt;strong&gt;98.1%&lt;/strong&gt; of ambiguous border-erased boards at 6×6 (107 of them) and &lt;strong&gt;100%&lt;/strong&gt;&lt;br&gt;
at 8×8 (30), with &lt;strong&gt;zero&lt;/strong&gt; false positives on unique boards. On &lt;em&gt;randomly&lt;/em&gt;&lt;br&gt;
erased boards, where interior windows are missing and the theorem no longer&lt;br&gt;
applies, it explains &lt;strong&gt;0.3%&lt;/strong&gt; and &lt;strong&gt;0.1%&lt;/strong&gt;. The certificate works exactly&lt;br&gt;
where its proof does, and the measurement says so.&lt;/p&gt;

&lt;h2&gt;
  
  
  The rule ladder
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;rung&lt;/th&gt;
&lt;th&gt;what it reads&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;count&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;one corner: a cardinality constraint on ≤4 cells, already GAC at that scope&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;linear&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;the whole clue system, row-reduced &lt;strong&gt;once&lt;/strong&gt; at build time, then bound-propagated&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pair&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;two corners one step apart share a domino — enumerate their ≤6 cells exactly&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;connect&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;the creek is one piece: dead components go black, cut vertices stay white&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;probe&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;assume a colour, run the sub-ladder, drop it on explosion&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Ablation: only the non-linear rung changes anything
&lt;/h3&gt;

&lt;p&gt;Drop one rung, run to a fixpoint, compare bit for bit against the full ladder&lt;br&gt;
on 120 random boards per size:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;dropped&lt;/th&gt;
&lt;th&gt;fixpoint moved&lt;/th&gt;
&lt;th&gt;boards completed&lt;/th&gt;
&lt;th&gt;probe assumptions&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;−&lt;code&gt;count&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;0/120, 0/120, 1/120&lt;/td&gt;
&lt;td&gt;61→61, 29→29, 7→7&lt;/td&gt;
&lt;td&gt;+0.8%, +6.2%, +3.9%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;−&lt;code&gt;linear&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;0/120, 0/120, 0/120&lt;/td&gt;
&lt;td&gt;61→61, 29→29, 7→7&lt;/td&gt;
&lt;td&gt;+0.0%, +0.4%, +2.6%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;−&lt;code&gt;pair&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;0/120, 0/120, 0/120&lt;/td&gt;
&lt;td&gt;61→61, 29→29, 7→7&lt;/td&gt;
&lt;td&gt;+7.2%, +5.8%, +9.2%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;−&lt;code&gt;connect&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;37/120, 52/120, 64/120&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;61→42, 29→16, 7→5&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;+16.8%, +8.4%, −6.4%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;(6×6, 8×8, 10×10.) The three &lt;em&gt;linear&lt;/em&gt; rungs are &lt;strong&gt;mutually redundant&lt;/strong&gt;:&lt;br&gt;
remove any one and the surviving two rebuild its fixpoint to the bit. They&lt;br&gt;
are not free, though — dropping &lt;code&gt;pair&lt;/code&gt; costs the prober 6–9% more&lt;br&gt;
assumptions, dropping &lt;code&gt;count&lt;/code&gt; 1–6%. &lt;strong&gt;Only &lt;code&gt;connect&lt;/code&gt;, the one rule in the&lt;br&gt;
ladder that is not linear algebra, moves the answer.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The incremental reading points the other way, as it always does: &lt;code&gt;count&lt;/code&gt;&lt;br&gt;
34.2% → &lt;code&gt;linear&lt;/code&gt; 35.0% → &lt;code&gt;pair&lt;/code&gt; 35.0% → &lt;code&gt;connect&lt;/code&gt; 45.0% → &lt;code&gt;probe&lt;/code&gt; 50.8% at&lt;br&gt;
6×6. Read increments alone and every rung looks essential; read the ablation&lt;br&gt;
alone and three of them look like decoration. Both tables ship.&lt;/p&gt;

&lt;h3&gt;
  
  
  Two incomparable rungs with the same finish line
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;linear&lt;/code&gt; reasons about the whole board over the rationals. &lt;code&gt;pair&lt;/code&gt; looks at six&lt;br&gt;
cells but is allowed to know they are &lt;strong&gt;integers&lt;/strong&gt;. Neither contains the&lt;br&gt;
other. On &lt;strong&gt;9,000&lt;/strong&gt; random boards:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;bits &lt;code&gt;linear&lt;/code&gt; finds that &lt;code&gt;pair&lt;/code&gt; does not: &lt;strong&gt;756&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;bits &lt;code&gt;pair&lt;/code&gt; finds that &lt;code&gt;linear&lt;/code&gt; does not: &lt;strong&gt;1,947&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;boards where their fixpoints differ at all: 742&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;boards one finishes and the other does not: 0&lt;/strong&gt; — in either direction&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And yet the shipped bank &lt;em&gt;does&lt;/em&gt; contain &lt;code&gt;pair&lt;/code&gt;-graded boards, because thinning&lt;br&gt;
a board to a locally minimal clue set drives it onto precisely the frontier&lt;br&gt;
where the two rungs separate; that happens 1.7% of the time. &lt;strong&gt;The null result&lt;br&gt;
was a statement about where you sample, not about the rules.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The dials on the answer's side
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Shading density.&lt;/strong&gt; A thin creek in a big bank is easy, a wide one is hard&lt;br&gt;
(8×8, keeping 60% of the numbers at random):&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;shaded&lt;/th&gt;
&lt;th&gt;unique&lt;/th&gt;
&lt;th&gt;adversarially minimal numbers&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;20%&lt;/td&gt;
&lt;td&gt;8.7%&lt;/td&gt;
&lt;td&gt;32 of 81&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;40%&lt;/td&gt;
&lt;td&gt;13.3%&lt;/td&gt;
&lt;td&gt;29 of 81&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;60%&lt;/td&gt;
&lt;td&gt;24.7%&lt;/td&gt;
&lt;td&gt;22 of 81&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;70%&lt;/td&gt;
&lt;td&gt;42.7%&lt;/td&gt;
&lt;td&gt;18 of 81&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Creek shape.&lt;/strong&gt; Hold the area fixed and change only the &lt;em&gt;shoreline&lt;/em&gt;, by&lt;br&gt;
growing towards cells with fewer white neighbours:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;growth&lt;/th&gt;
&lt;th&gt;shoreline (edges)&lt;/th&gt;
&lt;th&gt;0s printed&lt;/th&gt;
&lt;th&gt;4s printed&lt;/th&gt;
&lt;th&gt;unique&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;blob (t=1)&lt;/td&gt;
&lt;td&gt;26.5&lt;/td&gt;
&lt;td&gt;35.6%&lt;/td&gt;
&lt;td&gt;10.3%&lt;/td&gt;
&lt;td&gt;25.3%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;t=2&lt;/td&gt;
&lt;td&gt;40.4&lt;/td&gt;
&lt;td&gt;25.1%&lt;/td&gt;
&lt;td&gt;6.6%&lt;/td&gt;
&lt;td&gt;16.7%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;t=4&lt;/td&gt;
&lt;td&gt;51.2&lt;/td&gt;
&lt;td&gt;18.2%&lt;/td&gt;
&lt;td&gt;4.0%&lt;/td&gt;
&lt;td&gt;15.3%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;tendrils (t=8)&lt;/td&gt;
&lt;td&gt;55.9&lt;/td&gt;
&lt;td&gt;15.3%&lt;/td&gt;
&lt;td&gt;3.1%&lt;/td&gt;
&lt;td&gt;14.7%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Same size, same white area, same number of printed numbers — and the&lt;br&gt;
uniqueness rate halves. The mechanism is in the histogram: &lt;strong&gt;a 0 or a 4&lt;br&gt;
decides four cells on its own&lt;/strong&gt;, and a winding creek prints far fewer of&lt;br&gt;
them. Doubling the shoreline trades the extremes for 1s.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Adversarial ink against random ink.&lt;/strong&gt; A locally minimal clue set needs&lt;br&gt;
16 / 29 / 43 numbers at 6×6 / 8×8 / 10×10 — about &lt;strong&gt;35% of the lattice&lt;/strong&gt;,&lt;br&gt;
remarkably flat across sizes. Random disclosure needs &lt;strong&gt;2.0×&lt;/strong&gt; as many.&lt;/p&gt;

&lt;h2&gt;
  
  
  The generator cannot dead-end
&lt;/h2&gt;

&lt;p&gt;A Creek answer is &lt;em&gt;any&lt;/em&gt; shading whose unshaded cells are connected, so the&lt;br&gt;
generator builds the creek instead of searching for one: seed a cell, then&lt;br&gt;
absorb frontier cells one at a time. The frontier is non-empty until the white&lt;br&gt;
set is the whole board, so growth never rejects, never restarts and never&lt;br&gt;
fails.&lt;/p&gt;

&lt;h2&gt;
  
  
  The census, checked against formulas rather than against itself
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;1×m boards&lt;/strong&gt; — the white cells are one interval, so &lt;code&gt;m(m+1)/2 + 1&lt;/code&gt;:
2, 4, 7, 11, 16, 22, 29, 37 — matched exactly by exhaustive enumeration.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;2×m boards&lt;/strong&gt; — the two cells of a column are adjacent, so legal boards are
exactly those whose white columns form a run with consecutive columns
overlapping. The transfer matrix gives 4, 14, 41, 109, 276, 682, 1665,
4041, 9780, 23638 — matched exactly — and continues 57097, 137877, 332900, …&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;n×n boards&lt;/strong&gt; — 2, 14, 219, 11507.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Injectivity of the full clue map&lt;/strong&gt; — exhaustively at 3×3, 4×3, 4×4:
512 → 512, 4,096 → 4,096, 65,536 → 65,536 distinct clue fields. &lt;strong&gt;No two
boards ever print the same numbers.&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Kernel dimension&lt;/strong&gt; — predicted &lt;code&gt;w+h−1&lt;/code&gt;, confirmed by row reduction at
eight shapes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Engine agreement: 300 small boards × five rule levels, &lt;strong&gt;100%&lt;/strong&gt; agreement with&lt;br&gt;
a raw engine that shares no rule, no candidate array and no row reduction&lt;br&gt;
with the ladder.&lt;/p&gt;

&lt;p&gt;One more identity, about the ladder rather than the board: on 9,000 boards&lt;br&gt;
across three sizes and five erasure rates, &lt;strong&gt;&lt;code&gt;probe&lt;/code&gt; finishes a board if and&lt;br&gt;
only if the board is unique&lt;/strong&gt; — 0 exceptions in either direction.&lt;/p&gt;

&lt;h2&gt;
  
  
  In short
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The numbers live on the &lt;strong&gt;corners&lt;/strong&gt;, and the clue field is the board's mixed
second difference — so a fully clued board has a &lt;strong&gt;closed form&lt;/strong&gt; and no
puzzle in it; &lt;code&gt;count&lt;/code&gt; alone finishes 100% of them&lt;/li&gt;
&lt;li&gt;Erasing the 24-corner &lt;strong&gt;border ring&lt;/strong&gt; of a 6×6 leaves &lt;strong&gt;92.5%&lt;/strong&gt; of boards
unique; erasing 24 &lt;strong&gt;interior&lt;/strong&gt; corners leaves &lt;strong&gt;0.0%&lt;/strong&gt; — same equation
count, four degrees of freedom apart. Shape of the kernel, not size&lt;/li&gt;
&lt;li&gt;That kernel is exactly &lt;code&gt;(−1)^(i+j)(u_i + v_j)&lt;/code&gt;, dimension &lt;strong&gt;w+h−1&lt;/strong&gt;, and at
±1 it is three shapes: &lt;strong&gt;row, column, cross&lt;/strong&gt;. The cheapest ambiguity costs
a whole row, which is why a 19-dimensional kernel leaves &lt;strong&gt;0%&lt;/strong&gt; of 10×10
boards ambiguous&lt;/li&gt;
&lt;li&gt;The certificate explains &lt;strong&gt;98–100%&lt;/strong&gt; of border-erased ambiguity with no
search and &lt;strong&gt;0.1–0.3%&lt;/strong&gt; of randomly-erased ambiguity — it works exactly
where its proof does&lt;/li&gt;
&lt;li&gt;Ablation: the three linear rungs are &lt;strong&gt;bit-identical replacements&lt;/strong&gt; for each
other; only &lt;strong&gt;&lt;code&gt;connect&lt;/code&gt;&lt;/strong&gt; moves any fixpoint. Increments say the opposite,
and both ship&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;linear&lt;/code&gt; and &lt;code&gt;pair&lt;/code&gt; are &lt;strong&gt;incomparable&lt;/strong&gt; (756 vs 1,947 bits) yet separated
&lt;strong&gt;0/9,000&lt;/strong&gt; boards at the finish line — until thinning drives boards onto
the frontier, where they separate 1.7% of the time&lt;/li&gt;
&lt;li&gt;Doubling the &lt;strong&gt;shoreline&lt;/strong&gt; at constant area halves the uniqueness rate,
because 0s and 4s are the only numbers that decide four cells at once&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;30 tests. TypeScript, zero runtime dependencies.&lt;/p&gt;

&lt;p&gt;Demo: &lt;a href="https://sen.ltd/portfolio/creek/" rel="noopener noreferrer"&gt;https://sen.ltd/portfolio/creek/&lt;/a&gt;&lt;br&gt;
Repo: &lt;a href="https://github.com/sen-ltd/creek" rel="noopener noreferrer"&gt;https://github.com/sen-ltd/creek&lt;/a&gt;&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>algorithms</category>
      <category>gamedev</category>
      <category>puzzle</category>
    </item>
    <item>
      <title>Numbrix: one number colours the whole board, and the ruler rung that provably pays nothing</title>
      <dc:creator>SEN LLC</dc:creator>
      <pubDate>Thu, 27 Aug 2026 02:14:32 +0000</pubDate>
      <link>https://dev.to/sendotltd/numbrix-one-number-colours-the-whole-board-and-the-ruler-rung-that-provably-pays-nothing-2j4c</link>
      <guid>https://dev.to/sendotltd/numbrix-one-number-colours-the-whole-board-and-the-ruler-rung-that-provably-pays-nothing-2j4c</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Numbrix&lt;/strong&gt; in the browser with &lt;strong&gt;five rule sets&lt;/strong&gt; inside. Fill the grid&lt;br&gt;
with &lt;strong&gt;1 … n&lt;/strong&gt; so that &lt;strong&gt;consecutive numbers share an edge&lt;/strong&gt;. Strip the&lt;br&gt;
labels and the answer is a &lt;strong&gt;Hamiltonian path&lt;/strong&gt; of the grid graph — the&lt;br&gt;
numbers only record the order you walked it in. Puzzle #47 in the solver&lt;br&gt;
series.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Demo: &lt;a href="https://sen.ltd/portfolio/numbrix/" rel="noopener noreferrer"&gt;https://sen.ltd/portfolio/numbrix/&lt;/a&gt;&lt;br&gt;
Repo: &lt;a href="https://github.com/sen-ltd/numbrix" rel="noopener noreferrer"&gt;https://github.com/sen-ltd/numbrix&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbc84xog6v1ep4piza4wd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbc84xog6v1ep4piza4wd.png" alt="Numbrix" width="800" height="719"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  One number colours the whole board
&lt;/h2&gt;

&lt;p&gt;Colour the grid like a chessboard. The walk changes colour at every step, so&lt;br&gt;
the colour of the cell holding &lt;em&gt;v&lt;/em&gt; is the colour of the cell holding 1,&lt;br&gt;
flipped &lt;em&gt;v−1&lt;/em&gt; times: &lt;strong&gt;value parity and cell colour are locked together&lt;/strong&gt;,&lt;br&gt;
globally. Print a single number anywhere and every other number on the board&lt;br&gt;
learns which half of the grid it lives in.&lt;/p&gt;

&lt;p&gt;This is the cheapest and widest clue this series has measured. On random 8×8&lt;br&gt;
answers, counting surviving cell×number pairs:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;board&lt;/th&gt;
&lt;th&gt;numbers printed&lt;/th&gt;
&lt;th&gt;after &lt;code&gt;pin&lt;/code&gt;
&lt;/th&gt;
&lt;th&gt;after &lt;code&gt;link&lt;/code&gt;
&lt;/th&gt;
&lt;th&gt;cells pinned&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;8×8&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;100.0%&lt;/td&gt;
&lt;td&gt;100.0%&lt;/td&gt;
&lt;td&gt;0.0%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8×8&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;96.9%&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;43.0%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;1.6%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8×8&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;93.9%&lt;/td&gt;
&lt;td&gt;36.9%&lt;/td&gt;
&lt;td&gt;3.3%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8×8&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;88.0%&lt;/td&gt;
&lt;td&gt;27.7%&lt;/td&gt;
&lt;td&gt;6.8%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8×8&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;76.8%&lt;/td&gt;
&lt;td&gt;13.5%&lt;/td&gt;
&lt;td&gt;17.5%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10×10&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;98.0%&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;44.4%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;1.0%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10×10&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;84.7%&lt;/td&gt;
&lt;td&gt;19.5%&lt;/td&gt;
&lt;td&gt;9.8%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Plain bookkeeping (&lt;code&gt;pin&lt;/code&gt;) removes one printed number from 63 other cells and&lt;br&gt;
stops. Turning the same clue into a global statement is the chain rule's&lt;br&gt;
doing. And &lt;strong&gt;the first clue takes more than half; every clue after it is&lt;br&gt;
suddenly cheap&lt;/strong&gt; — the chessboard is only bought once.&lt;/p&gt;

&lt;p&gt;The solver hard-codes none of this. The value chain 1—2—…—n is a&lt;br&gt;
&lt;em&gt;tree-shaped&lt;/em&gt; constraint network, arc consistency on a tree is exact, and the&lt;br&gt;
chessboard falls out as a consequence rather than a rule.&lt;/p&gt;

&lt;p&gt;Two corollaries, both checked on 1,400 sampled answers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;value parity ≡ cell colour (1,400 / 1,400)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;an odd cell count puts both ends of the walk on the same colour&lt;/strong&gt;, an even
one puts them on opposite colours (600 odd boards and 800 even boards, no
exceptions)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The ruler rung that pays nothing
&lt;/h2&gt;

&lt;p&gt;For a puzzle about consecutive numbers, everybody's second rule is a ruler.&lt;br&gt;
Walking from &lt;em&gt;u&lt;/em&gt; to &lt;em&gt;v&lt;/em&gt; takes exactly |v−u| steps and no walk beats the grid&lt;br&gt;
distance, so a cell far from every home of &lt;em&gt;u&lt;/em&gt; loses a whole interval of&lt;br&gt;
numbers around &lt;em&gt;u&lt;/em&gt;. It is sound, it is cheap, and it is &lt;strong&gt;the technique&lt;br&gt;
humans actually use&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It is also &lt;strong&gt;provably worthless after &lt;code&gt;link&lt;/code&gt;&lt;/strong&gt;. The value chain is a path, arc&lt;br&gt;
consistency on it is exact, so every candidate &lt;code&gt;link&lt;/code&gt; leaves standing takes&lt;br&gt;
part in some complete walk — and that walk is itself the witness for the&lt;br&gt;
distance bound. &lt;strong&gt;Anything you can prove with a ruler, the chain has already&lt;br&gt;
proved.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To keep the claim measurable rather than rhetorical, &lt;code&gt;ruleSpan&lt;/code&gt; still ships,&lt;br&gt;
unused by the ladder. On 160 random boards:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;board&lt;/th&gt;
&lt;th&gt;boards&lt;/th&gt;
&lt;th&gt;bits the ruler deletes after &lt;code&gt;link&lt;/code&gt;
&lt;/th&gt;
&lt;th&gt;bits after &lt;code&gt;pin&lt;/code&gt; alone&lt;/th&gt;
&lt;th&gt;pinned by pin+ruler&lt;/th&gt;
&lt;th&gt;pinned by pin+link&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;4×4&lt;/td&gt;
&lt;td&gt;40&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;2,851&lt;/td&gt;
&lt;td&gt;55.8%&lt;/td&gt;
&lt;td&gt;57.3%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6×6&lt;/td&gt;
&lt;td&gt;40&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;20,904&lt;/td&gt;
&lt;td&gt;63.3%&lt;/td&gt;
&lt;td&gt;64.9%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8×8&lt;/td&gt;
&lt;td&gt;40&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;75,417&lt;/td&gt;
&lt;td&gt;56.4%&lt;/td&gt;
&lt;td&gt;57.8%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10×10&lt;/td&gt;
&lt;td&gt;40&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;196,219&lt;/td&gt;
&lt;td&gt;59.4%&lt;/td&gt;
&lt;td&gt;61.2%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Not a weak rule — a redundant one. On its own it does very nearly the chain's&lt;br&gt;
job (1.4–1.8 points less reach). After the chain it deletes nothing at all.&lt;/p&gt;

&lt;h2&gt;
  
  
  What survives the argument is distinctness
&lt;/h2&gt;

&lt;p&gt;The relaxation the chain solves exactly is a &lt;em&gt;walk&lt;/em&gt;: it may step on its own&lt;br&gt;
tail. Everything the real puzzle knows beyond that says the walk is a &lt;em&gt;path&lt;/em&gt; —&lt;br&gt;
that it uses distinct cells. There are two ways to say it.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;block&lt;/code&gt;, the pigeonhole.&lt;/strong&gt; The values a…b need b−a+1 &lt;strong&gt;distinct&lt;/strong&gt; cells,
all from the union of their surviving homes. A smaller union kills the
board; a union of exactly that size is a tight set whose cells belong to the
block and lose everything else. Read from the cells instead of the values
("if b−a+1 cells have nothing left but a…b, every &lt;em&gt;other&lt;/em&gt; cell loses a…b")
it prunes the other direction. Both halves of Hall's condition.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;edge&lt;/code&gt;, the degree count.&lt;/strong&gt; Forget numbers; look at the drawing. Every
cell has path-degree 2 except the two ends. A cell with exactly two possible
edges must use both; forced edges glue into runs whose labels are
consecutive by construction; a run may never close a cycle; and what
survives must keep the board connected.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Stacking rungs from the bottom (cells pinned, random reveals):&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;board&lt;/th&gt;
&lt;th&gt;reveal&lt;/th&gt;
&lt;th&gt;&lt;code&gt;pin&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;link&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;block&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;edge&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;probe&lt;/code&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;8×8&lt;/td&gt;
&lt;td&gt;20%&lt;/td&gt;
&lt;td&gt;20.9%&lt;/td&gt;
&lt;td&gt;43.3%&lt;/td&gt;
&lt;td&gt;47.5%&lt;/td&gt;
&lt;td&gt;53.5%&lt;/td&gt;
&lt;td&gt;74.7%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8×8&lt;/td&gt;
&lt;td&gt;30%&lt;/td&gt;
&lt;td&gt;30.7%&lt;/td&gt;
&lt;td&gt;71.9%&lt;/td&gt;
&lt;td&gt;74.5%&lt;/td&gt;
&lt;td&gt;84.6%&lt;/td&gt;
&lt;td&gt;88.8%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8×8&lt;/td&gt;
&lt;td&gt;40%&lt;/td&gt;
&lt;td&gt;40.6%&lt;/td&gt;
&lt;td&gt;86.6%&lt;/td&gt;
&lt;td&gt;87.4%&lt;/td&gt;
&lt;td&gt;94.1%&lt;/td&gt;
&lt;td&gt;96.9%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10×10&lt;/td&gt;
&lt;td&gt;20%&lt;/td&gt;
&lt;td&gt;21.0%&lt;/td&gt;
&lt;td&gt;47.0%&lt;/td&gt;
&lt;td&gt;50.7%&lt;/td&gt;
&lt;td&gt;61.5%&lt;/td&gt;
&lt;td&gt;77.8%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10×10&lt;/td&gt;
&lt;td&gt;30%&lt;/td&gt;
&lt;td&gt;31.5%&lt;/td&gt;
&lt;td&gt;78.8%&lt;/td&gt;
&lt;td&gt;80.2%&lt;/td&gt;
&lt;td&gt;88.6%&lt;/td&gt;
&lt;td&gt;93.4%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10×10&lt;/td&gt;
&lt;td&gt;40%&lt;/td&gt;
&lt;td&gt;41.4%&lt;/td&gt;
&lt;td&gt;90.6%&lt;/td&gt;
&lt;td&gt;91.3%&lt;/td&gt;
&lt;td&gt;97.3%&lt;/td&gt;
&lt;td&gt;97.9%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  One load-bearing rung, three accelerators
&lt;/h2&gt;

&lt;p&gt;That table adds rungs from the bottom. Deleting one from the &lt;em&gt;top&lt;/em&gt; says&lt;br&gt;
something different, and you need both to avoid lying to yourself:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;10×10, variant&lt;/th&gt;
&lt;th&gt;cells pinned&lt;/th&gt;
&lt;th&gt;boards whose fixpoint moved&lt;/th&gt;
&lt;th&gt;pin scans&lt;/th&gt;
&lt;th&gt;link scans&lt;/th&gt;
&lt;th&gt;edge runs&lt;/th&gt;
&lt;th&gt;probes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;full&lt;/td&gt;
&lt;td&gt;84.9%&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;496,439&lt;/td&gt;
&lt;td&gt;471,796&lt;/td&gt;
&lt;td&gt;4,484&lt;/td&gt;
&lt;td&gt;1,763&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;−pin&lt;/td&gt;
&lt;td&gt;84.9%&lt;/td&gt;
&lt;td&gt;0 / 12&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;556,574&lt;/td&gt;
&lt;td&gt;5,250&lt;/td&gt;
&lt;td&gt;1,763&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;−link&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;37.3%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;12 / 12&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;26,300&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;263&lt;/td&gt;
&lt;td&gt;72&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;−block&lt;/td&gt;
&lt;td&gt;84.9%&lt;/td&gt;
&lt;td&gt;1 / 12&lt;/td&gt;
&lt;td&gt;714,182&lt;/td&gt;
&lt;td&gt;687,840&lt;/td&gt;
&lt;td&gt;6,726&lt;/td&gt;
&lt;td&gt;2,015&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;−edge&lt;/td&gt;
&lt;td&gt;84.9%&lt;/td&gt;
&lt;td&gt;1 / 12&lt;/td&gt;
&lt;td&gt;703,965&lt;/td&gt;
&lt;td&gt;660,469&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;2,520&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;−probe&lt;/td&gt;
&lt;td&gt;74.3%&lt;/td&gt;
&lt;td&gt;9 / 12&lt;/td&gt;
&lt;td&gt;11,300&lt;/td&gt;
&lt;td&gt;11,300&lt;/td&gt;
&lt;td&gt;113&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Only &lt;code&gt;link&lt;/code&gt; carries reach.&lt;/strong&gt; Everything else is speed. Dropping the degree&lt;br&gt;
count leaves the same cells pinned on 11 of 12 boards — while raising the&lt;br&gt;
bookkeeping bill by &lt;strong&gt;42%&lt;/strong&gt; and the probe count by &lt;strong&gt;43%&lt;/strong&gt;, because the probe&lt;br&gt;
has to re-derive by contradiction what the drawing said for free. What &lt;code&gt;edge&lt;/code&gt;&lt;br&gt;
looked like it was earning in the incremental table was really "work the&lt;br&gt;
probe didn't have to do".&lt;/p&gt;

&lt;h2&gt;
  
  
  Ink, spent well and spent badly
&lt;/h2&gt;

&lt;p&gt;A Numbrix clue set is small — but only if the setter picks it. The left&lt;br&gt;
column is the irredundant set an adversary finds (reveal until the level&lt;br&gt;
finishes, then take back every number it can do without); the right is what&lt;br&gt;
the same board needs when numbers are revealed in random order until the&lt;br&gt;
answer becomes unique.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;board&lt;/th&gt;
&lt;th&gt;adversarial, &lt;code&gt;edge&lt;/code&gt; level&lt;/th&gt;
&lt;th&gt;as % of cells&lt;/th&gt;
&lt;th&gt;random reveal until unique (median)&lt;/th&gt;
&lt;th&gt;ratio&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;4×4&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;18.8%&lt;/td&gt;
&lt;td&gt;31%&lt;/td&gt;
&lt;td&gt;1.7×&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6×6&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;16.7%&lt;/td&gt;
&lt;td&gt;22%&lt;/td&gt;
&lt;td&gt;1.3×&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8×8&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;15.6%&lt;/td&gt;
&lt;td&gt;30%&lt;/td&gt;
&lt;td&gt;1.9×&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10×10&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;15.0%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;49%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;3.3×&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The adversarial share &lt;em&gt;falls&lt;/em&gt; as the board grows — 15% of a 10×10 is enough —&lt;br&gt;
while random ink wants half the board. Give the probe the same job and 10×10&lt;br&gt;
drops to 12 numbers.&lt;/p&gt;

&lt;p&gt;At the bottom of the ladder there is a wall rather than a curve. With only the&lt;br&gt;
bijection to reason from, a cell becomes pinned exactly when it is printed or&lt;br&gt;
when it is the last unclaimed one, so &lt;strong&gt;&lt;code&gt;pin&lt;/code&gt; cannot finish any board that is&lt;br&gt;
not already printed in full&lt;/strong&gt;. Measured: &lt;strong&gt;15 of 16&lt;/strong&gt; numbers on a 4×4 and&lt;br&gt;
&lt;strong&gt;35 of 36&lt;/strong&gt; on a 6×6, every single time. The bank has no &lt;code&gt;pin&lt;/code&gt; grade because&lt;br&gt;
no such puzzle exists.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reading a second answer off the answer
&lt;/h2&gt;

&lt;p&gt;A Numbrix answer is a walk, so the cheapest way to build a &lt;em&gt;different&lt;/em&gt; answer&lt;br&gt;
out of one you have is the classic &lt;strong&gt;2-opt reversal&lt;/strong&gt;: pick two positions on&lt;br&gt;
the path whose cells happen to be grid neighbours, and walk the stretch&lt;br&gt;
between them backwards. It needs one extra edge at each end of the window and&lt;br&gt;
no printed number inside it. Scanning every pair is O(n²) with O(1) work&lt;br&gt;
each — &lt;strong&gt;a second answer read straight off the first, with no search&lt;/strong&gt;.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;board&lt;/th&gt;
&lt;th&gt;ambiguous boards&lt;/th&gt;
&lt;th&gt;explained by one reversal&lt;/th&gt;
&lt;th&gt;false alarms on unique boards&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;4×4&lt;/td&gt;
&lt;td&gt;60&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;83.3%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0 of 35&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6×6&lt;/td&gt;
&lt;td&gt;60&lt;/td&gt;
&lt;td&gt;70.0%&lt;/td&gt;
&lt;td&gt;0 of 24&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8×8&lt;/td&gt;
&lt;td&gt;60&lt;/td&gt;
&lt;td&gt;63.3%&lt;/td&gt;
&lt;td&gt;0 of 3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10×10&lt;/td&gt;
&lt;td&gt;60&lt;/td&gt;
&lt;td&gt;58.3%&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The false-alarm column thins out on the big boards because that stream was&lt;br&gt;
deliberately under-clued to produce ambiguity — so the shipped bank does the&lt;br&gt;
same job at full strength: all &lt;strong&gt;64 boards&lt;/strong&gt; are unique and &lt;strong&gt;not one carries&lt;br&gt;
a certificate&lt;/strong&gt;. That the explained share falls with board size is the honest&lt;br&gt;
reading: on a big grid a second answer can be a re-route the walk never comes&lt;br&gt;
back from.&lt;/p&gt;

&lt;p&gt;The move below a reversal does not exist. A single cell can never change its&lt;br&gt;
number quietly — it would appear twice and another would vanish — and the&lt;br&gt;
tests check that exhaustively over every cell and every alternative on 4×4.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sampling an answer without ever searching for one
&lt;/h2&gt;

&lt;p&gt;A rectangle always has a Hamiltonian path — the boustrophedon one, snaking row&lt;br&gt;
by row — so a Numbrix answer can never fail to exist. The problem is the&lt;br&gt;
opposite: that answer is far too regular to print, and rejection-sampling&lt;br&gt;
random walks until one covers the board is hopeless past 5×5.&lt;/p&gt;

&lt;p&gt;So the generator moves &lt;em&gt;between&lt;/em&gt; answers instead of drawing one. The&lt;br&gt;
&lt;strong&gt;backbite&lt;/strong&gt; move takes a Hamiltonian path, picks one of its two ends, picks a&lt;br&gt;
random grid neighbour &lt;em&gt;u&lt;/em&gt; of that end, and — if &lt;em&gt;u&lt;/em&gt; is not already the next&lt;br&gt;
cell along — adds the edge (end, &lt;em&gt;u&lt;/em&gt;) and deletes the edge that used to enter&lt;br&gt;
&lt;em&gt;u&lt;/em&gt; from the far side. The result is another Hamiltonian path of the same&lt;br&gt;
grid. Always. No rejection, no restart, no failure mode.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;board&lt;/th&gt;
&lt;th&gt;moves per cell&lt;/th&gt;
&lt;th&gt;accepted&lt;/th&gt;
&lt;th&gt;turns in the answer&lt;/th&gt;
&lt;th&gt;distinct answers in 200 draws&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;10×10&lt;/td&gt;
&lt;td&gt;0 (the snake)&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;18.0&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10×10&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;69.8%&lt;/td&gt;
&lt;td&gt;33.1&lt;/td&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10×10&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;71.7%&lt;/td&gt;
&lt;td&gt;50.9&lt;/td&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10×10&lt;/td&gt;
&lt;td&gt;16&lt;/td&gt;
&lt;td&gt;71.8%&lt;/td&gt;
&lt;td&gt;55.9&lt;/td&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10×10&lt;/td&gt;
&lt;td&gt;60 (shipped)&lt;/td&gt;
&lt;td&gt;72.0%&lt;/td&gt;
&lt;td&gt;55.4&lt;/td&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The snake has 2(n−1) = 18 turns and exactly one form. Sixteen moves per cell&lt;br&gt;
triples the turn count and the sampler has stopped moving — 200 draws, 200&lt;br&gt;
different answers, about seven moves in ten accepted at every size.&lt;/p&gt;

&lt;h2&gt;
  
  
  The external ledger
&lt;/h2&gt;

&lt;p&gt;The raw engine shares no candidate machinery with the ladder: it walks, and&lt;br&gt;
scores completed walks with the rule text. Switch the printed numbers off and&lt;br&gt;
it becomes a census machine — and these are &lt;strong&gt;published&lt;/strong&gt; combinatorics, not&lt;br&gt;
something this repository can quietly agree with itself about.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;board&lt;/th&gt;
&lt;th&gt;directed Hamiltonian paths, engine&lt;/th&gt;
&lt;th&gt;published&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;3×3&lt;/td&gt;
&lt;td&gt;40&lt;/td&gt;
&lt;td&gt;40 — OEIS A096969&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4×4&lt;/td&gt;
&lt;td&gt;552&lt;/td&gt;
&lt;td&gt;552&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5×5&lt;/td&gt;
&lt;td&gt;8,648&lt;/td&gt;
&lt;td&gt;8,648&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6×6&lt;/td&gt;
&lt;td&gt;458,696&lt;/td&gt;
&lt;td&gt;458,696&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;board&lt;/th&gt;
&lt;th&gt;Hamiltonian cycles, engine&lt;/th&gt;
&lt;th&gt;published / proved&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;4×4&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;6 — OEIS A003763&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6×6&lt;/td&gt;
&lt;td&gt;1,072&lt;/td&gt;
&lt;td&gt;1,072&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3×3, 5×5&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0 — theorem: a cycle alternates colours, an odd cell count cannot&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;And one identity proved rather than looked up. On the 2×m ladder a walk can&lt;br&gt;
only leave a column through its own rung, so it sweeps the columns&lt;br&gt;
monotonically from each end and is fixed by its turning column — giving&lt;br&gt;
&lt;strong&gt;m² − m + 2&lt;/strong&gt; undirected Hamiltonian paths. The engine, which knows nothing&lt;br&gt;
about ladders, produced 4, 8, 14, 22, 32, 44, 58 for m = 2…8. Exactly.&lt;/p&gt;

&lt;h2&gt;
  
  
  probe ⇔ unique
&lt;/h2&gt;

&lt;p&gt;The two engines agreed on every solution count they both finished. And&lt;br&gt;
&lt;strong&gt;probe-completion ⇔ uniqueness&lt;/strong&gt; held on 160 boards in &lt;strong&gt;both directions with&lt;br&gt;
zero disagreements&lt;/strong&gt;:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;board&lt;/th&gt;
&lt;th&gt;boards&lt;/th&gt;
&lt;th&gt;probe finishes &amp;amp; unique&lt;/th&gt;
&lt;th&gt;probe stalls &amp;amp; ambiguous&lt;/th&gt;
&lt;th&gt;disagreements&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;4×4&lt;/td&gt;
&lt;td&gt;40&lt;/td&gt;
&lt;td&gt;21&lt;/td&gt;
&lt;td&gt;19&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6×6&lt;/td&gt;
&lt;td&gt;40&lt;/td&gt;
&lt;td&gt;16&lt;/td&gt;
&lt;td&gt;24&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8×8&lt;/td&gt;
&lt;td&gt;40&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;33&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10×10&lt;/td&gt;
&lt;td&gt;40&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;34&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Every one of the 64 shipped boards was re-proved unique by both engines before&lt;br&gt;
shipping.&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;One printed number colours the whole board.&lt;/strong&gt; Surviving cell×number pairs
on an 8×8 go 100% → 43.0% with one clue; a second only reaches 36.9%. The
chessboard is bought once. The solver hard-codes none of it — arc
consistency on the path-shaped value chain rediscovers it&lt;/li&gt;
&lt;li&gt;Corollaries, no exceptions on 1,400 answers: value parity ≡ cell colour, and
&lt;strong&gt;an odd cell count puts both ends of the walk on the same colour&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The ruler rung deletes 0 bits after &lt;code&gt;link&lt;/code&gt;&lt;/strong&gt; (160 boards). Not weak —
redundant: on its own it deletes 2,851–196,219 bits and comes within 1.4–1.8
points of the chain's reach. Anything a distance argument can prove, an
exact arc consistency on a tree has already proved&lt;/li&gt;
&lt;li&gt;What survives the argument is &lt;strong&gt;distinctness&lt;/strong&gt;: &lt;code&gt;block&lt;/code&gt; (both halves of
Hall's condition) and &lt;code&gt;edge&lt;/code&gt; (degree and connectivity) are the two ways to
say the walk is a path&lt;/li&gt;
&lt;li&gt;The incremental table and the ablation table disagree, and both are true:
only &lt;strong&gt;&lt;code&gt;link&lt;/code&gt;&lt;/strong&gt; carries reach (84.9% → 37.3% without it), while dropping
&lt;code&gt;edge&lt;/code&gt; leaves 11 of 12 fixpoints bit-identical and raises the bookkeeping
bill &lt;strong&gt;42%&lt;/strong&gt; and the probe count &lt;strong&gt;43%&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Adversarial ink: &lt;strong&gt;15 numbers on a 10×10 (15%)&lt;/strong&gt; against 49% revealed at
random — 3.3×. &lt;code&gt;pin&lt;/code&gt; provably needs n−1, so no &lt;code&gt;pin&lt;/code&gt;-grade puzzle exists&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;2-opt reversal certificate&lt;/strong&gt; explains 58–83% of ambiguous boards with
no search and 0 false alarms; a single cell can never change alone&lt;/li&gt;
&lt;li&gt;Generation is &lt;strong&gt;backbite&lt;/strong&gt; — moving between answers, never searching for
one. 16 moves per cell gives 200 distinct answers in 200 draws&lt;/li&gt;
&lt;li&gt;External ledger: 40 / 552 / 8,648 / 458,696 directed Hamiltonian paths
(A096969), 6 / 1,072 cycles (A003763), 0 on odd boards (theorem), and a
self-proved m² − m + 2 for the 2×m ladder, every term&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;33 tests. TypeScript, zero runtime dependencies.&lt;/p&gt;

&lt;p&gt;Demo: &lt;a href="https://sen.ltd/portfolio/numbrix/" rel="noopener noreferrer"&gt;https://sen.ltd/portfolio/numbrix/&lt;/a&gt;&lt;br&gt;
Repo: &lt;a href="https://github.com/sen-ltd/numbrix" rel="noopener noreferrer"&gt;https://github.com/sen-ltd/numbrix&lt;/a&gt;&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>algorithms</category>
      <category>gamedev</category>
      <category>puzzle</category>
    </item>
    <item>
      <title>Kojun: the clue you draw before you write a digit, and two walls where boards stop existing</title>
      <dc:creator>SEN LLC</dc:creator>
      <pubDate>Wed, 26 Aug 2026 15:11:29 +0000</pubDate>
      <link>https://dev.to/sendotltd/kojun-the-clue-you-draw-before-you-write-a-digit-and-two-walls-where-boards-stop-existing-6ma</link>
      <guid>https://dev.to/sendotltd/kojun-the-clue-you-draw-before-you-write-a-digit-and-two-walls-where-boards-stop-existing-6ma</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Kojun&lt;/strong&gt; in the browser with &lt;strong&gt;five rule sets&lt;/strong&gt; inside. The grid is&lt;br&gt;
divided into &lt;strong&gt;regions&lt;/strong&gt;; a region of k cells holds each of &lt;strong&gt;1…k exactly&lt;br&gt;
once&lt;/strong&gt;, two cells sharing an edge never hold equal digits — across region&lt;br&gt;
borders too — and of two vertically adjacent cells in the same region,&lt;br&gt;
&lt;strong&gt;the upper one is larger&lt;/strong&gt;. Puzzle #46 in the solver series.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Demo: &lt;a href="https://sen.ltd/portfolio/kojun/" rel="noopener noreferrer"&gt;https://sen.ltd/portfolio/kojun/&lt;/a&gt;&lt;br&gt;
Repo: &lt;a href="https://github.com/sen-ltd/kojun" rel="noopener noreferrer"&gt;https://github.com/sen-ltd/kojun&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fthjfmvas69dt8j4b5rhi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fthjfmvas69dt8j4b5rhi.png" alt="Kojun" width="800" height="688"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  The first clue is drawn, not written
&lt;/h2&gt;

&lt;p&gt;Every clue this series has measured so far was a printed number. Kojun has&lt;br&gt;
printed givens too — but before a single digit hits the paper, the setter&lt;br&gt;
has already committed a clue: &lt;strong&gt;the partition itself&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A region's outline says three things. The digit range (size k means 1…k),&lt;br&gt;
the internal slope (every in-region vertical edge points downhill), and&lt;br&gt;
sometimes the entire content: a region shaped like a &lt;strong&gt;column of height k&lt;br&gt;
reads k, k−1, …, 1 from the top&lt;/strong&gt; — the chain of interval bounds "upper&lt;br&gt;
exceeds the lower cell's minimum" resolves every cell with zero givens.&lt;/p&gt;

&lt;p&gt;On the default partition stream (region sizes 4–7), the shapes alone pin&lt;br&gt;
&lt;strong&gt;9–11% of every board's cells before the first given is revealed&lt;/strong&gt; — and&lt;br&gt;
almost all of that work belongs to &lt;code&gt;order&lt;/code&gt;, the interval rule on vertical&lt;br&gt;
edges:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;n&lt;/th&gt;
&lt;th&gt;&lt;code&gt;neigh&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;once&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;order&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;region&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;probe&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;6×6&lt;/td&gt;
&lt;td&gt;1.6%&lt;/td&gt;
&lt;td&gt;1.7%&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;9.3%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;9.3%&lt;/td&gt;
&lt;td&gt;9.9%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10×10&lt;/td&gt;
&lt;td&gt;1.6%&lt;/td&gt;
&lt;td&gt;1.6%&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;11.1%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;11.1%&lt;/td&gt;
&lt;td&gt;11.5%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;h2&gt;
  
  
  Regions that cannot coexist — a soft wall of granularity
&lt;/h2&gt;

&lt;p&gt;Try to make the partition a &lt;em&gt;stronger&lt;/em&gt; clue and the puzzle resists in a&lt;br&gt;
strange way: &lt;strong&gt;the board itself stops existing&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In a finished grid, the set of all cells holding v is a &lt;strong&gt;global&lt;br&gt;
independent set&lt;/strong&gt; — equal digits never share an edge, whatever region they&lt;br&gt;
belong to — and every region of size ≥ v contains a v. So small regions&lt;br&gt;
pack the board with 1s and 2s until those classes no longer embed. The&lt;br&gt;
all-singletons partition is the limiting theorem: every cell must hold 1,&lt;br&gt;
two of them always touch, so no legal board exists at any size ≥ 2.&lt;/p&gt;

&lt;p&gt;Measured, the collapse starts far above the theorem. One partition, one&lt;br&gt;
fill attempt, nothing redrawn:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;8×8, region sizes&lt;/th&gt;
&lt;th&gt;admits a board&lt;/th&gt;
&lt;th&gt;mean region size&lt;/th&gt;
&lt;th&gt;pinned by shape alone (&lt;code&gt;order&lt;/code&gt;)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1–1 (all singletons)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.0%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;1.00&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2–3&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.0%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;2.40&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2–5&lt;/td&gt;
&lt;td&gt;2.5%&lt;/td&gt;
&lt;td&gt;3.26&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;56.3%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3–6&lt;/td&gt;
&lt;td&gt;28.8%&lt;/td&gt;
&lt;td&gt;4.00&lt;/td&gt;
&lt;td&gt;24.2%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4–7 (the default)&lt;/td&gt;
&lt;td&gt;51.3%&lt;/td&gt;
&lt;td&gt;4.70&lt;/td&gt;
&lt;td&gt;11.4%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5–9&lt;/td&gt;
&lt;td&gt;75.0%&lt;/td&gt;
&lt;td&gt;5.91&lt;/td&gt;
&lt;td&gt;7.0%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The tension runs against the setter: &lt;strong&gt;the shapes that say the most (56%&lt;br&gt;
of cells pinned at sizes 2–5) are exactly the shapes that barely exist.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  The verticality dial ends in a second wall
&lt;/h2&gt;

&lt;p&gt;The vertical rule reads only in-region vertical edges, so the same&lt;br&gt;
4–7-cell budget per region says more laid tall than laid flat. Sweeping&lt;br&gt;
the growth bias:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;8×8, vbias&lt;/th&gt;
&lt;th&gt;admits a board&lt;/th&gt;
&lt;th&gt;cells in column regions&lt;/th&gt;
&lt;th&gt;pinned by shape (&lt;code&gt;order&lt;/code&gt;)&lt;/th&gt;
&lt;th&gt;median givens to buy a &lt;code&gt;region&lt;/code&gt;-level finish (6×6)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0.00 (flat)&lt;/td&gt;
&lt;td&gt;98.8%&lt;/td&gt;
&lt;td&gt;0.7%&lt;/td&gt;
&lt;td&gt;0.9%&lt;/td&gt;
&lt;td&gt;18&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0.50&lt;/td&gt;
&lt;td&gt;60.0%&lt;/td&gt;
&lt;td&gt;6.9%&lt;/td&gt;
&lt;td&gt;10.8%&lt;/td&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0.75&lt;/td&gt;
&lt;td&gt;25.0%&lt;/td&gt;
&lt;td&gt;24.5%&lt;/td&gt;
&lt;td&gt;25.2%&lt;/td&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1.00 (tall)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.0%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;74.6%&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The pinning power climbs 0.9% → 25% — and then the boards vanish. The&lt;br&gt;
culprit is self-solvingness itself: &lt;strong&gt;two column regions of height k side&lt;br&gt;
by side are both forced to k…1, and their equal digits touch.&lt;/strong&gt; A shape&lt;br&gt;
that solves itself cannot sit next to another one.&lt;/p&gt;

&lt;p&gt;The last column is the price of ink. A unique &lt;code&gt;region&lt;/code&gt;-grade board costs a&lt;br&gt;
median 18 givens on flat 6×6 partitions — half the board — and 3 on the&lt;br&gt;
tall partitions that survive. You can pay for most of the puzzle with&lt;br&gt;
outline instead of digits; the fee is that such partitions almost never&lt;br&gt;
exist.&lt;/p&gt;
&lt;h2&gt;
  
  
  Random givens are nearly worthless
&lt;/h2&gt;

&lt;p&gt;The givens have their own lesson. Revealing 30% of all cells at random&lt;br&gt;
leaves 6×6 boards unique &lt;strong&gt;0.0% of the time&lt;/strong&gt; (50% reveals: 6%; at 8×8&lt;br&gt;
even 50% gives 0%). Meanwhile the generator's adversarial reveal —&lt;br&gt;
grow-until-solved, then greedily delete — buys uniqueness with a median of&lt;br&gt;
&lt;strong&gt;12 givens&lt;/strong&gt;. Where a given lands matters almost infinitely more than how&lt;br&gt;
many there are. The lesson from Nanro (#326), where 19 adversarial hints&lt;br&gt;
did what 19 random ones failed to do in 30 of 30 tries, survives in a&lt;br&gt;
puzzle where the setter fully owns hint placement.&lt;/p&gt;
&lt;h2&gt;
  
  
  One roof over the ladder — and on naked boards, even the roof goes quiet
&lt;/h2&gt;

&lt;p&gt;The ladder: &lt;code&gt;neigh&lt;/code&gt; (a pinned grid neighbour erases its digit here),&lt;br&gt;
&lt;code&gt;once&lt;/code&gt; (the region as a permutation: pinned cells erase, lone homes pin),&lt;br&gt;
&lt;code&gt;order&lt;/code&gt; (interval bounds on vertical edges), &lt;code&gt;region&lt;/code&gt; (enumerate every&lt;br&gt;
complete assignment of one region and keep exactly the supported values),&lt;br&gt;
&lt;code&gt;probe&lt;/code&gt; (assume, propagate, delete on contradiction).&lt;/p&gt;

&lt;p&gt;&lt;code&gt;once&lt;/code&gt; (a census of homes per digit) and &lt;code&gt;order&lt;/code&gt; (a geometry of edges) are&lt;br&gt;
incomparable middle rungs. But every deletion the three cheap rules can&lt;br&gt;
justify lives inside a single region, or crosses one boundary edge to a&lt;br&gt;
pinned cell — exactly what &lt;code&gt;region&lt;/code&gt;'s enumeration checks. The roof&lt;br&gt;
subsumes all three, as a theorem; ablation confirms it in bits:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;10×10&lt;/th&gt;
&lt;th&gt;cells pinned&lt;/th&gt;
&lt;th&gt;fixpoints moved&lt;/th&gt;
&lt;th&gt;region assignments&lt;/th&gt;
&lt;th&gt;probes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;full&lt;/td&gt;
&lt;td&gt;12.7%&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;8,196&lt;/td&gt;
&lt;td&gt;706&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;−neigh&lt;/td&gt;
&lt;td&gt;12.7%&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0 of 20&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;11,129&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;706&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;−once&lt;/td&gt;
&lt;td&gt;12.7%&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0 of 20&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;9,914&lt;/td&gt;
&lt;td&gt;706&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;−order&lt;/td&gt;
&lt;td&gt;12.7%&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0 of 20&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;9,413&lt;/td&gt;
&lt;td&gt;706&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;−region&lt;/td&gt;
&lt;td&gt;12.7%&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0 of 20&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;975&lt;/td&gt;
&lt;td&gt;706&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;−probe&lt;/td&gt;
&lt;td&gt;11.7%&lt;/td&gt;
&lt;td&gt;18 of 20&lt;/td&gt;
&lt;td&gt;975&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Dropping any cheap rule leaves the fixpoint bit-for-bit identical at every&lt;br&gt;
size; what moves is the bill (−&lt;code&gt;neigh&lt;/code&gt; raises the roof's enumeration work&lt;br&gt;
by a third). That much is familiar from this series. The fifth row is the&lt;br&gt;
new part: &lt;strong&gt;on this stream, removing the roof changes nothing either.&lt;/strong&gt; On&lt;br&gt;
naked boards every deletion the roof can make, the probe re-derives — the&lt;br&gt;
whole ladder above &lt;code&gt;order&lt;/code&gt; falls silent.&lt;/p&gt;

&lt;p&gt;The middle wakes up when givens arrive. The shipped bank (80 boards)&lt;br&gt;
fills &lt;strong&gt;all five grades at every size&lt;/strong&gt;: printed digits separate the rungs&lt;br&gt;
that the naked stream collapses. A bare partition flattens the ladder to&lt;br&gt;
two levels; givens unfold it back to five.&lt;/p&gt;
&lt;h2&gt;
  
  
  The multinomial census
&lt;/h2&gt;

&lt;p&gt;Soundness is pinned by an independent engine that shares no machinery with&lt;br&gt;
the ladder: it deals &lt;strong&gt;whole regions one at a time&lt;/strong&gt; — the search space is&lt;br&gt;
literally Π kᵢ! — checking placed digits only against the raw rule text,&lt;br&gt;
and scoring every leaf with the validator. It agreed with the propagating&lt;br&gt;
search on &lt;strong&gt;482/482&lt;/strong&gt; solution counts.&lt;/p&gt;

&lt;p&gt;It also faces an external identity. An isolated p×q rectangular region (p&lt;br&gt;
rows, q columns, no givens) is constrained only in its columns, each&lt;br&gt;
strictly decreasing downward — so the count of fillings must be the&lt;br&gt;
multinomial:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(pq)! / (p!)^q   — choose each column's digits; their order inside is forced
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The engine, which knows nothing about multinomials, landed on every term&lt;br&gt;
asked: 1×5 = 120, 3×2 = 20, 4×2 = 70, 3×3 = 1,680, 2×5 = 113,400 — and&lt;br&gt;
k×1 = 1, the counting-theory version of "a column is its own solution."&lt;/p&gt;

&lt;h2&gt;
  
  
  A second solution read straight off the answer — 98–100% explained
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;A single cell can never change value silently&lt;/strong&gt;: its region would gain a&lt;br&gt;
duplicate and lose a digit (the tests prove this exhaustively over every&lt;br&gt;
cell and every alternative value). So the cheapest ambiguity is a &lt;em&gt;swap&lt;/em&gt; —&lt;br&gt;
two ungiven cells of one region trading digits with every law intact — and&lt;br&gt;
one scan of the finished grid finds it, no search at all:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;n&lt;/th&gt;
&lt;th&gt;non-unique boards&lt;/th&gt;
&lt;th&gt;explained by one swap&lt;/th&gt;
&lt;th&gt;false alarms on unique boards&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;4×4&lt;/td&gt;
&lt;td&gt;296&lt;/td&gt;
&lt;td&gt;291 (98.3%)&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6×6&lt;/td&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;td&gt;200 (&lt;strong&gt;100.0%&lt;/strong&gt;)&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8×8&lt;/td&gt;
&lt;td&gt;240&lt;/td&gt;
&lt;td&gt;240 (&lt;strong&gt;100.0%&lt;/strong&gt;)&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Magnets (#328) got 37–47% out of its pair certificate. Kojun's ambiguity&lt;br&gt;
is almost entirely confined inside single regions — the small bijections&lt;br&gt;
lock digits so tightly that multi-region rearrangements are almost never&lt;br&gt;
the cheapest second solution. And the probe ladder agreed with true&lt;br&gt;
uniqueness on &lt;strong&gt;all 680 stream boards, in both directions&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Kojun's first clue is &lt;strong&gt;the partition&lt;/strong&gt;: column regions solve themselves
with zero givens, and default shapes pin 9–11% of all cells on their own
(nearly all of it &lt;code&gt;order&lt;/code&gt;'s work)&lt;/li&gt;
&lt;li&gt;Digit classes are board-wide independent sets, so &lt;strong&gt;small regions are
the most informative and the least existent&lt;/strong&gt;: at 8×8, sizes 2–3 admit
0% of boards, 5–9 admit 75%; the all-singletons partition is empty by
theorem&lt;/li&gt;
&lt;li&gt;The verticality dial raises shape-pinning 0.9% → 25% while existence
falls 98.8% → 0% — &lt;strong&gt;self-solving shapes cannot sit next to each
other&lt;/strong&gt;. Ink cost: 18 givens flat, 3 tall&lt;/li&gt;
&lt;li&gt;Random givens are nearly worthless (30% reveals: 0% unique); 12
adversarial ones do the job&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;region&lt;/code&gt; roof provably subsumes the three cheap rules — ablation is
bit-identical everywhere — and on naked boards the roof itself is
redundant; only givens wake the ladder's middle (the bank still fills
all five grades at every size)&lt;/li&gt;
&lt;li&gt;The independent Π kᵢ! engine matched 482/482 counts and reproduced the
&lt;strong&gt;multinomial census (pq)!/(p!)^q&lt;/strong&gt; on every rectangle asked&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;in-region swap certificate&lt;/strong&gt; explains 98–100% of non-unique boards
with zero false alarms; probe ⇔ unique held on all 680 boards&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;27 tests. TypeScript, zero runtime dependencies.&lt;/p&gt;

&lt;p&gt;Demo: &lt;a href="https://sen.ltd/portfolio/kojun/" rel="noopener noreferrer"&gt;https://sen.ltd/portfolio/kojun/&lt;/a&gt;&lt;br&gt;
Repo: &lt;a href="https://github.com/sen-ltd/kojun" rel="noopener noreferrer"&gt;https://github.com/sen-ltd/kojun&lt;/a&gt;&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>algorithms</category>
      <category>gamedev</category>
      <category>puzzle</category>
    </item>
    <item>
      <title>Magnets: a clue that can't see half the board, and a generator that cannot dead-end</title>
      <dc:creator>SEN LLC</dc:creator>
      <pubDate>Mon, 24 Aug 2026 23:32:40 +0000</pubDate>
      <link>https://dev.to/sendotltd/magnets-a-clue-that-cant-see-half-the-board-and-a-generator-that-cannot-dead-end-39mm</link>
      <guid>https://dev.to/sendotltd/magnets-a-clue-that-cant-see-half-the-board-and-a-generator-that-cannot-dead-end-39mm</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Magnets&lt;/strong&gt; in the browser with &lt;strong&gt;five rule sets&lt;/strong&gt; inside. The board is&lt;br&gt;
pre-tiled into dominoes; each domino either becomes a &lt;strong&gt;magnet&lt;/strong&gt; — a &lt;code&gt;+&lt;/code&gt;&lt;br&gt;
pole on one half, a &lt;code&gt;−&lt;/code&gt; pole on the other — or stays &lt;strong&gt;neutral&lt;/strong&gt;. Two&lt;br&gt;
cells sharing an edge may never hold the same pole, and the margins count&lt;br&gt;
every row and column's &lt;code&gt;+&lt;/code&gt; cells and &lt;code&gt;−&lt;/code&gt; cells. Puzzle #45 in the solver&lt;br&gt;
series.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Demo: &lt;a href="https://sen.ltd/portfolio/magnets/" rel="noopener noreferrer"&gt;https://sen.ltd/portfolio/magnets/&lt;/a&gt;&lt;br&gt;
Repo: &lt;a href="https://github.com/sen-ltd/magnets" rel="noopener noreferrer"&gt;https://github.com/sen-ltd/magnets&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F988ngk9z4bz56coa4390.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F988ngk9z4bz56coa4390.png" alt="Magnets" width="800" height="688"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  The difference clue is blind to half the board
&lt;/h2&gt;

&lt;p&gt;Each line (row or column) carries two numbers: its &lt;code&gt;+&lt;/code&gt; count and its &lt;code&gt;−&lt;/code&gt;&lt;br&gt;
count. The useful way to read them is as a &lt;strong&gt;sum&lt;/strong&gt; and a &lt;strong&gt;difference&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;sum&lt;/em&gt; counts magnetised cells and cannot tell &lt;code&gt;+&lt;/code&gt; from &lt;code&gt;−&lt;/code&gt;. The&lt;br&gt;
&lt;em&gt;difference&lt;/em&gt; can — but &lt;strong&gt;it cannot see any domino lying inside the line&lt;/strong&gt;.&lt;br&gt;
A domino tucked horizontally into a row contributes one &lt;code&gt;+&lt;/code&gt; and one &lt;code&gt;−&lt;/code&gt; if&lt;br&gt;
it is a magnet, and nothing if it is neutral; either way it cancels out of&lt;br&gt;
the difference. What survives is exactly the cells whose domino &lt;em&gt;crosses&lt;/em&gt;&lt;br&gt;
the line, one half in, one half out:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;plusClue − minusClue = Σ over crossing cells of σ,   σ ∈ {+1, −1, 0}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The difference clue is a &lt;strong&gt;signed flux through the line's boundary&lt;/strong&gt;, and&lt;br&gt;
the in-line dominoes drop out of that integral identically. A Kakuro sum&lt;br&gt;
talks about every cell in its scope; a Magnets difference is structurally&lt;br&gt;
unable to mention half of its own line.&lt;/p&gt;

&lt;p&gt;The solver's third rung, &lt;code&gt;flux&lt;/code&gt;, reasons from that identity alone: interval&lt;br&gt;
bounds on the sum of σ terms, plus one parity fact — when every other&lt;br&gt;
crossing cell is known magnetised, the remainder's parity is forced.&lt;/p&gt;
&lt;h2&gt;
  
  
  Turn the tiling sideways and the same 32 numbers say nothing
&lt;/h2&gt;

&lt;p&gt;The identity has a measurable consequence. Give the tiling generator a&lt;br&gt;
horizontal bias &lt;code&gt;hbias&lt;/code&gt; and sweep it, keeping the clue count fixed at 32&lt;br&gt;
numbers per 8×8 board:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;hbias&lt;/th&gt;
&lt;th&gt;crossing cells per row&lt;/th&gt;
&lt;th&gt;rows with difference 0&lt;/th&gt;
&lt;th&gt;pinned by &lt;code&gt;flux&lt;/code&gt;
&lt;/th&gt;
&lt;th&gt;pinned by probe&lt;/th&gt;
&lt;th&gt;exactly one answer&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0.00 (all vertical)&lt;/td&gt;
&lt;td&gt;8.00&lt;/td&gt;
&lt;td&gt;28.4%&lt;/td&gt;
&lt;td&gt;1.6%&lt;/td&gt;
&lt;td&gt;3.8%&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.0%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0.25&lt;/td&gt;
&lt;td&gt;6.16&lt;/td&gt;
&lt;td&gt;33.0%&lt;/td&gt;
&lt;td&gt;10.8%&lt;/td&gt;
&lt;td&gt;71.7%&lt;/td&gt;
&lt;td&gt;23.8%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0.50&lt;/td&gt;
&lt;td&gt;4.51&lt;/td&gt;
&lt;td&gt;39.8%&lt;/td&gt;
&lt;td&gt;20.4%&lt;/td&gt;
&lt;td&gt;87.3%&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;50.0%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0.75&lt;/td&gt;
&lt;td&gt;2.74&lt;/td&gt;
&lt;td&gt;46.6%&lt;/td&gt;
&lt;td&gt;15.7%&lt;/td&gt;
&lt;td&gt;80.1%&lt;/td&gt;
&lt;td&gt;35.0%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1.00 (all horizontal)&lt;/td&gt;
&lt;td&gt;0.00&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;100.0%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;2.7%&lt;/td&gt;
&lt;td&gt;7.7%&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.0%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;At &lt;code&gt;hbias = 1&lt;/code&gt; every domino lies inside its row, so &lt;strong&gt;every row's&lt;br&gt;
difference clue is identically zero&lt;/strong&gt; — it carries no bits at all. The&lt;br&gt;
information moves wholesale into the columns… and the puzzle dies anyway:&lt;br&gt;
uniqueness collapses from 50% in the isotropic middle to 0% at both ends.&lt;/p&gt;

&lt;p&gt;The culprit is the certificate below. Parallel dominoes stacked on the same&lt;br&gt;
two tracks are precisely the configuration that can trade states silently,&lt;br&gt;
and an anisotropic tiling mass-produces it. An isotropic tiling keeps both&lt;br&gt;
readings of the clue pair alive; an anisotropic one kills one reading and&lt;br&gt;
paves the board with silent pairs.&lt;/p&gt;
&lt;h2&gt;
  
  
  A generator that cannot dead-end — as a theorem
&lt;/h2&gt;

&lt;p&gt;Every generator in this series has claimed "no search, no rejection", but&lt;br&gt;
always as a measurement. Magnets is stronger: the filling phase &lt;strong&gt;provably&lt;br&gt;
cannot fail&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Drawing an answer takes two steps. The tiling is laid scan-order with a&lt;br&gt;
bounded restart. The filling then visits dominoes in random order and gives&lt;br&gt;
each a state that is legal &lt;em&gt;right now&lt;/em&gt; — and since &lt;strong&gt;a neutral domino&lt;br&gt;
conflicts with nothing&lt;/strong&gt;, the set of legal states is never empty. Neutral&lt;br&gt;
is a structural escape hatch:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Both magnet orientations may be blocked by neighbours — neutral never is.&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;legalPole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;PLUS&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nf"&gt;legalPole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;MINUS&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;PLUS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;MINUS&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;legalPole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;MINUS&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nf"&gt;legalPole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;PLUS&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;MINUS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;PLUS&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="c1"&gt;// options may be empty; grid[a] = grid[b] = NEUTRAL always advances.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The price of the guarantee is a density dial, and both of its ends are&lt;br&gt;
easy:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;8×8, magnetise&lt;/th&gt;
&lt;th&gt;mean magnetisation&lt;/th&gt;
&lt;th&gt;
&lt;code&gt;count&lt;/code&gt; finishes&lt;/th&gt;
&lt;th&gt;probe finishes&lt;/th&gt;
&lt;th&gt;exactly one answer&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0.0&lt;/td&gt;
&lt;td&gt;0.0%&lt;/td&gt;
&lt;td&gt;100.0%&lt;/td&gt;
&lt;td&gt;100.0%&lt;/td&gt;
&lt;td&gt;100.0%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0.4&lt;/td&gt;
&lt;td&gt;36.6%&lt;/td&gt;
&lt;td&gt;8.3%&lt;/td&gt;
&lt;td&gt;41.7%&lt;/td&gt;
&lt;td&gt;41.7%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0.8&lt;/td&gt;
&lt;td&gt;65.7%&lt;/td&gt;
&lt;td&gt;0.0%&lt;/td&gt;
&lt;td&gt;56.7%&lt;/td&gt;
&lt;td&gt;56.7%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1.0&lt;/td&gt;
&lt;td&gt;75.7%&lt;/td&gt;
&lt;td&gt;0.0%&lt;/td&gt;
&lt;td&gt;50.0%&lt;/td&gt;
&lt;td&gt;50.0%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;An all-neutral board is trivially unique (every clue is 0); a packed board&lt;br&gt;
is rigid again because adjacency dictates. Ambiguity lives in the middle,&lt;br&gt;
at the density where the adjacency rule has started to bite but not yet to&lt;br&gt;
rule.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two incomparable rungs under one roof
&lt;/h2&gt;

&lt;p&gt;The ladder is five levels: &lt;code&gt;pole&lt;/code&gt; (raw bookkeeping — domino coupling plus&lt;br&gt;
"a pinned pole erases its neighbours"), then &lt;code&gt;count&lt;/code&gt; (each clue as a&lt;br&gt;
per-sign census over all cells of the line) and &lt;code&gt;flux&lt;/code&gt; (the signed sum over&lt;br&gt;
crossing cells only), then &lt;code&gt;gac&lt;/code&gt;, then &lt;code&gt;probe&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;count&lt;/code&gt; and &lt;code&gt;flux&lt;/code&gt; are &lt;strong&gt;incomparable&lt;/strong&gt; — the census sees every cell but&lt;br&gt;
cannot mix signs; the flux mixes signs but sees only the crossing cells.&lt;br&gt;
Neither subsumes the other. But every constraint of this puzzle lives&lt;br&gt;
&lt;em&gt;inside some line&lt;/em&gt;: horizontal adjacency in the row, vertical adjacency in&lt;br&gt;
the column, and each domino's coupling in whichever line the domino lies&lt;br&gt;
in. So &lt;code&gt;gac&lt;/code&gt; — exact enumeration of one line at a time — is a roof over&lt;br&gt;
both middle rungs, and over &lt;code&gt;pole&lt;/code&gt; too. That is a theorem that predicts the&lt;br&gt;
ablation table, and the measurement agreed bit for bit:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;10×10&lt;/th&gt;
&lt;th&gt;finished&lt;/th&gt;
&lt;th&gt;cells pinned&lt;/th&gt;
&lt;th&gt;fixpoints that moved&lt;/th&gt;
&lt;th&gt;line assignments built&lt;/th&gt;
&lt;th&gt;probes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;full&lt;/td&gt;
&lt;td&gt;40.0%&lt;/td&gt;
&lt;td&gt;80.5%&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;3,424&lt;/td&gt;
&lt;td&gt;215&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;−pole&lt;/td&gt;
&lt;td&gt;40.0%&lt;/td&gt;
&lt;td&gt;80.5%&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0 of 20&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;6,071&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;215&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;−count&lt;/td&gt;
&lt;td&gt;40.0%&lt;/td&gt;
&lt;td&gt;80.5%&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0 of 20&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;3,491&lt;/td&gt;
&lt;td&gt;215&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;−flux&lt;/td&gt;
&lt;td&gt;40.0%&lt;/td&gt;
&lt;td&gt;80.5%&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0 of 20&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;3,548&lt;/td&gt;
&lt;td&gt;215&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;−gac&lt;/td&gt;
&lt;td&gt;25.0%&lt;/td&gt;
&lt;td&gt;58.6%&lt;/td&gt;
&lt;td&gt;8 of 20&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;476&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;−probe&lt;/td&gt;
&lt;td&gt;25.0%&lt;/td&gt;
&lt;td&gt;40.9%&lt;/td&gt;
&lt;td&gt;15 of 20&lt;/td&gt;
&lt;td&gt;327&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Remove any of the three cheap rules and the fixpoint does not move by a&lt;br&gt;
single bit, on any board, at any size (6×6 and 8×8 show the same zeros).&lt;br&gt;
What moves is the bill: dropping &lt;code&gt;pole&lt;/code&gt; nearly doubles the roof's&lt;br&gt;
enumeration work. The middle rungs' preconditioning discount is small&lt;br&gt;
(2.8–9.6%); the biggest accelerator was the cheapest bookkeeping. Only the&lt;br&gt;
roof and the probe change what gets solved.&lt;/p&gt;

&lt;p&gt;One more zero worth printing: &lt;code&gt;pole&lt;/code&gt; alone finishes 0.0% of boards at&lt;br&gt;
every size. With no domino revealed, coupling and adjacency have no&lt;br&gt;
purchase — 100% of this puzzle's information is in the margins.&lt;/p&gt;

&lt;h2&gt;
  
  
  The √2 census
&lt;/h2&gt;

&lt;p&gt;Soundness is pinned by an independent engine that shares no machinery with&lt;br&gt;
the ladder: it deals each domino its three states in scan order, with only&lt;br&gt;
raw bookkeeping, and scores every leaf against the rule text. The two&lt;br&gt;
engines agreed on &lt;strong&gt;462/462&lt;/strong&gt; solution counts across mixed clue regimes.&lt;/p&gt;

&lt;p&gt;But engine-vs-engine agreement can miss a shared misunderstanding, so the&lt;br&gt;
raw engine also gets checked against something outside the repo. On a&lt;br&gt;
clue-free 1×2k strip, the number of legal fillings obeys the transfer&lt;br&gt;
matrix over {neutral, +−, −+}, giving &lt;code&gt;a(k) = 2a(k−1) + a(k−2)&lt;/code&gt; — OEIS&lt;br&gt;
&lt;strong&gt;A001333, the numerators of the continued-fraction convergents of √2&lt;/strong&gt;:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;k&lt;/th&gt;
&lt;th&gt;1&lt;/th&gt;
&lt;th&gt;2&lt;/th&gt;
&lt;th&gt;3&lt;/th&gt;
&lt;th&gt;4&lt;/th&gt;
&lt;th&gt;5&lt;/th&gt;
&lt;th&gt;6&lt;/th&gt;
&lt;th&gt;7&lt;/th&gt;
&lt;th&gt;8&lt;/th&gt;
&lt;th&gt;9&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;engine&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;17&lt;/td&gt;
&lt;td&gt;41&lt;/td&gt;
&lt;td&gt;99&lt;/td&gt;
&lt;td&gt;239&lt;/td&gt;
&lt;td&gt;577&lt;/td&gt;
&lt;td&gt;1,393&lt;/td&gt;
&lt;td&gt;3,363&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;All nine terms, horizontal and transposed. √2 has never read our code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reading a second solution straight off the answer
&lt;/h2&gt;

&lt;p&gt;Under full clues, &lt;strong&gt;a single domino can never change state silently&lt;/strong&gt;:&lt;br&gt;
flipping a magnet moves the ± counts of the two lines it crosses, and&lt;br&gt;
toggling magnet ↔ neutral moves every line it touches. The tests prove this&lt;br&gt;
exhaustively — every domino, every alternative state, on a stream of random&lt;br&gt;
boards. So the cheapest ambiguity is a &lt;em&gt;pair&lt;/em&gt;: two parallel dominoes on the&lt;br&gt;
same two tracks trading states so that all four line counts balance.&lt;/p&gt;

&lt;p&gt;Scanning a finished grid for such a pair — no search, no solver — explains&lt;br&gt;
a large share of all non-uniqueness, with zero false alarms:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;n&lt;/th&gt;
&lt;th&gt;non-unique boards&lt;/th&gt;
&lt;th&gt;explained by one pair&lt;/th&gt;
&lt;th&gt;certificates on unique boards&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;4×4&lt;/td&gt;
&lt;td&gt;92&lt;/td&gt;
&lt;td&gt;34 (37.0%)&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6×6&lt;/td&gt;
&lt;td&gt;83&lt;/td&gt;
&lt;td&gt;39 (47.0%)&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8×8&lt;/td&gt;
&lt;td&gt;71&lt;/td&gt;
&lt;td&gt;29 (40.8%)&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;And probe ⇔ unique held on the whole stream: &lt;strong&gt;680 boards, no exception in&lt;br&gt;
either direction&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A line's clue pair splits into a sum and a difference, and the
difference is &lt;strong&gt;structurally blind to in-line dominoes&lt;/strong&gt; — it is a
signed flux through the line's boundary.&lt;/li&gt;
&lt;li&gt;The anisotropy dial runs uniqueness 0% → 50% → 0% with the clue count
fixed: &lt;strong&gt;the orientation of the tiling decides how much the same numbers
say&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Neutral-is-always-legal makes the filling generator dead-end-free &lt;strong&gt;as a
theorem&lt;/strong&gt;, not a retry statistic; its density dial is easy at both ends
and hard in the middle.&lt;/li&gt;
&lt;li&gt;Two incomparable middle rungs under one exact roof: ablation leaves the
fixpoint &lt;strong&gt;bit-identical&lt;/strong&gt; without any cheap rule, while &lt;code&gt;−pole&lt;/code&gt; doubles
the roof's work.&lt;/li&gt;
&lt;li&gt;The raw engine reproduces &lt;strong&gt;the √2 convergent numerators (A001333)&lt;/strong&gt; on
strips, nine terms, and matched the propagating engine 462/462.&lt;/li&gt;
&lt;li&gt;A tiny impossibility theorem (no silent single-domino move) turns into a
&lt;strong&gt;pair certificate&lt;/strong&gt; that explains ~40% of non-uniqueness with zero
false positives.&lt;/li&gt;
&lt;li&gt;probe ⇔ unique: 680 boards, no exceptions. 31 tests.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All code is public: &lt;a href="https://github.com/sen-ltd/magnets" rel="noopener noreferrer"&gt;https://github.com/sen-ltd/magnets&lt;/a&gt;&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>algorithms</category>
      <category>gamedev</category>
      <category>puzzle</category>
    </item>
  </channel>
</rss>
