Building a Sudoku solver from scratch in the browser
A deep dive into constraint propagation, backtracking search, and making it all run fast enough to feel instant — no server, no dependencies.
I wanted to understand how constraint solvers work at a fundamental level, so I built a Sudoku solver entirely in the browser with zero dependencies. The result solves any valid puzzle in under 2ms.
The algorithm: constraint propagation + backtracking
The core insight is that you don't need to try every possibility. Before backtracking, you propagate constraints: if a cell can only hold one value, assign it. If a unit (row, column, box) can only place a digit in one cell, place it there. This alone solves most newspaper-level puzzles without any search.
function propagate(grid: Grid, cell: number, digit: number): Grid | false {
const peers = PEERS[cell];
for (const peer of peers) {
const result = eliminate(grid, peer, digit);
if (result === false) return false;
grid = result;
}
return grid;
}Representing the board as a bitmask
Each cell stores a 9-bit integer where each bit represents whether that digit is still possible. This makes intersection and elimination O(1) bit operations instead of array traversals. The full board is a typed array of 81 uint16 values — 162 bytes.
Why this matters
Bit operations are dramatically faster than array methods in tight loops. On a modern V8 engine, a full solve with backtracking takes ~0.4ms on the hardest known puzzles. The UI stays at 60fps even when solving in a requestAnimationFrame.
The UI: making it feel alive
The grid is rendered on a Canvas element for performance, with a React state layer on top for cell selection. Constraint propagation runs reactively as you type, highlighting cells that would become contradictions in red — so you see the solver thinking in real time.
The goal wasn't just to solve Sudoku. It was to build something that teaches you how it thinks.