Engineering
Building a Sudoku Engine That's Fast and Reliable
How I approached puzzle generation, validation, and solving for a browser-based Sudoku game.
When I started building the Sudoku game for this site, I thought the hard part would be the UI. Turns out the grid is the easy bit. The real work lives in making sure every puzzle is valid, solvable, and actually fun to play.
This post walks through how I structured the engine — from representing the board to generating puzzles and running a solver that does not choke on harder grids.
1. Goals
Before writing much code, I wrote down what the engine needed to do:
- Generate valid puzzles with a single solution
- Validate player moves in real time
- Solve puzzles quickly enough for hints
- Score difficulty in a way that feels fair to humans
I did not want a solver that only worked on easy puzzles, or a generator that spat out broken boards. Those two things had to work together from the start.
2. Board representation
I kept the board as a flat 81-cell array of numbers (0 for empty, 1–9 for filled). It is simple, easy to serialize, and fast to iterate over.
Each cell index maps to row and column with basic math:
const row = Math.floor(index / 9);
const col = index % 9;
const box = Math.floor(row / 3) * 3 + Math.floor(col / 3);For validation, I maintain three bitmask sets — one for rows, columns, and 3×3 boxes. Checking whether a digit is allowed is a few bitwise operations instead of scanning the whole row every time.
That small change matters when you are validating on every keystroke.
3. Solving approach
The solver uses backtracking with the most-constrained cell first. Pick the empty cell with the fewest possible values, try each candidate, and recurse. Classic approach, but it works well for standard 9×9 Sudoku.
For hints, I run the solver on a copy of the board and return the next logical move rather than filling the entire grid. That keeps hints feeling like nudges instead of spoilers.
Puzzle generation works backwards: start from a complete valid grid, remove clues while checking that the solution stays unique. Fewer clues usually means harder puzzles, though the relationship is not perfectly linear — which is why I added a simple difficulty score on top.
4. What I learned
Building a Sudoku engine taught me to respect "simple" problems. The rules fit on a napkin, but getting generation, validation, and UX to play nicely takes more care than I expected.
If you are working on something similar, my advice is to nail the data model first and test the solver heavily before polishing the interface. Everything else builds on that foundation.