Slitherlink gives you a grid. Some cells carry a number from 0 to 3. You draw segments along the grid lines, and when you are done they must form one single closed loop — no branches, no loose ends, and no second loop sitting somewhere else on the board. A cell marked 3 has exactly three of its four sides on that loop.
👉 Live, runs in your browser: https://dev48.in/game/day81-slitherlink.html
The two rules everyone implements
They are both easy and both local.
- Clues. Count the drawn sides of each numbered cell. It must equal the number.
- Degrees. Every lattice vertex must have 0 segments touching it, or exactly 2 — one in, one out. Anything else is a loose end or a junction.
Write a solver that enforces exactly those and it looks finished. It is not.
What the count says
Here is every edge assignment on one 3×3 board that satisfies every clue and leaves every vertex at degree 0 or 2, grouped by how many loops it actually drew:
| what the segments drew | assignments |
|---|---|
| one loop — a real solution | 22 |
| 2 separate loops | 7 |
| 3 separate loops | 4 |
| 4 separate loops | 1 |
34 pass both local tests. 22 are solutions. A solver that stops there accepts twelve boards it must refuse, on this grid alone.
The reason is structural, not a corner case. A graph in which every vertex has degree 0 or 2 is a disjoint union of cycles. It may be one cycle, or two, or five. Slitherlink demands exactly one, and that condition is global — no amount of looking at one cell or one corner can see it.
// necessary, and nowhere near sufficient
function degreesLegal(clues, on) {
for (const v of vertices) {
const d = incidentEdges(v).filter(e => on[e]).length;
if (d !== 0 && d !== 2) return false;
}
return true;
}
// the part that is not local: walk the on-edges and count components
loopCount(clues, on) === 1
Making the search finish
A 3×3 board has 24 candidate segments, so brute force is 2²⁴ — about 16.7 million. Two cheap prunes collapse it.
Assign edges in index order. The moment the last edge of a clued cell is decided, that clue is final — check it now rather than at the leaf. Same for a vertex: once every edge touching it has a value, its degree is final and must be 0 or 2. Both tests fire deep in the tree.
The pruned search touches 0.1752% of the brute-force tree. Without the prunes the 3×3 boards do not finish.
Every 2×2 board there is
Five possibilities per cell — blank, 0, 1, 2, 3 — over four cells. 625 boards:
| boards | |
|---|---|
| no solution at all | 523 |
| exactly one — a real puzzle | 61 |
| more than one — ambiguous | 41 |
Most boards are not puzzles. That is worth knowing before you write a generator.
🔴 And a 4 is legal
I asserted in the self-check that a 4 is impossible, and the check failed. It is satisfiable: the loop is that cell's own perimeter, four segments, every corner at degree 2. Standard puzzles omit 4 because it solves itself, not because it is illegal.
A lone 3 on a 1×1 board genuinely is impossible — three sides is an open path.
How it is checked
The page runs 24 checks in your browser. A separate verifier runs 210 asserts by a route the page does not use: it enumerates every simple cycle in the lattice graph by depth-first search, so "it is one closed loop" is true by construction and never tested for. A solution is then just a cycle whose edges happen to satisfy the clues.
That verifier found a real gap in my own reasoning. I first checked single-loop-ness as connected, with edges equal to vertices. That also admits a lollipop — one cycle with a tree hanging off it. The degrees have to be checked too.
210 verifier asserts, 24 in-page checks, 0 failures. One file, no build step, no dependencies.
Top comments (0)