Reveal: click a covered cell; click a satisfied number to chord Flag: F over the cell under the pointer One solver deduction: S Auto-solve: hold A — one deduction per frame so you can watch it spread New no-guess board: N New random board: R Size: 1 9x9/10 · 2 12x12/22 · 3 16x16/40 The first click is always safe and always opens a region: the mines are laid after it, with the 3x3 around the click excluded from the pool. Green cells are ones the solver proved safe, red ones it proved mined, and the cyan rings mark the revealed number (or the pair of numbers) that justified the deduction. The HUD names which rule fired.
Minesweeper with a constraint-propagation solver you can point at the board, and a generator that uses that solver to guarantee the board is winnable by logic alone — no coin flips. THE INTERESTING BIT The solver reasons only from what a player can see. Each revealed number is a constraint — this set of hidden cells contains exactly this many mines — and three rules are applied to saturation: - COUNTING. Outstanding count of 0 clears every hidden neighbour; a count equal to the hidden-neighbour count flags them all. - SUBSET. If constraint A's cell set sits inside B's, then B\A holds exactly kB - kA mines, and when that is 0 or |B\A| the difference resolves outright. This is the rule that cracks a 1-2-1 wall, which counting alone cannot touch at any depth. - MINE BUDGET. All mines flagged ⇒ everything else is safe; as many hidden cells left as unflagged mines ⇒ all of them are mines. The "no guess needed" generator is then just reject-and-retry: lay mines, open the first click, run the solver, and throw the board away if logic cannot finish it. Whether that is affordable was the whole question, so it was measured in tools/proto.py before any goboscript was written: | board | solvable, counting + budget only | solvable, + subset | attempts to find one | |---|---|---|---| | 9x9 / 10 | 64.0% | 79.5% | mean 1.18, max 2 | | 12x12 / 22 | 46.0% | 74.0% | mean 1.55, max 6 | | 16x16 / 40 | 27.5% | 63.0% | mean 1.90, max 6 | So the subset rule more than doubles the fraction of boards a logical player can finish, and that is what makes retry generation cheap enough to run inside Scratch — a mean of 43,000 elementary operations per accepted 16x16 board, 127,000 in the worst case seen. The attempt counter is drawn while it runs rather than hidden behind a frozen frame. The honest counterpart to that number: the subset rule accounts for only about 2% of the cells it deduces, yet 60% of accepted 16x16 boards need it at least once. It is a rule that almost never does any work and is load-bearing anyway. Verified in the headless scratch-vm harness rather than by reading the code. Over eight runs of the compiled .sb3 — click the centre, hold A — every one generated a no-guess 16x16/40 board (1 to 3 attempts) and auto-solved it to all 216 safe cells revealed, with zero wrong flags and zero revealed mines. The SUBSET counter in the HUD was non-zero on two of the eight, peaking at 5 firings, which is the compiled build demonstrating the rule rather than me asserting it — the other six were boards the counting and budget rules happened to finish on their own. HONEST LIMITATIONS - The solver is a propagator, not a prover. Counting + subset + budget is strictly weaker than full enumeration of mine configurations, so a position it calls STUCK - GUESS may still be logically decidable. In practice this is the standard "single-point + subset" solver strength, and boards it accepts are guaranteed solvable by it, which is what the guarantee means here — a stronger solver would accept more boards, not fewer. - No probability estimate for genuinely ambiguous positions on R boards. If you hit a 50/50 in random mode you are on your own. - The generator caps at 60 rejections. Above the tested densities that cap is reachable; when it is hit the board is kept and the badge honestly drops back to RANDOM rather than claiming a guarantee it did not earn. All original - code, art and sound. See Inside is open.