Algorithm for solving Sudoku
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
A reliable Sudoku solver is a constraint search algorithm, not just random guessing. The classic approach combines rule checking with backtracking: choose an empty cell, try a valid number, recurse, and undo the move if it leads to a contradiction. That sounds simple, but a few careful choices make the difference between a slow brute-force solver and a practical one.
Model the Constraints First
A standard Sudoku board is a 9 x 9 grid. A candidate number is valid in a cell only if it does not already appear in:
- the same row
- the same column
- the same
3 x 3box
The simplest solver repeatedly asks two questions:
- which empty cell should I fill next?
- which digits are allowed there?
Once those are implemented correctly, backtracking becomes straightforward.
A Basic Backtracking Solver
Here is a direct Python implementation:
This works because every recursive call moves the puzzle closer to a complete assignment. If a later step fails, the solver backtracks and tries another choice.
Why Backtracking Is Enough for Most Puzzles
Sudoku is a constraint satisfaction problem. A naive brute-force approach would try all possible fillings, but backtracking prunes impossible states early.
That pruning matters. The solver never explores boards that already violate row, column, or box constraints.
For many ordinary puzzles, this basic strategy is already fast enough. The biggest practical improvement is not changing the whole algorithm. It is choosing the next empty cell more intelligently.
Choose the Most Constrained Cell First
A common optimization is the “minimum remaining values” heuristic. Instead of filling the first empty cell, choose the empty cell with the fewest legal candidates.
That reduces branching early and makes hard puzzles much faster.
Then use that in the recursive solver instead of find_empty.
This change does not alter correctness. It just makes the search tree smaller.
Constraint Tracking with Sets
Another optimization is to maintain sets of used digits per row, column, and box. That avoids scanning the entire row and box every time you test a candidate.
The idea is:
- '
rows[r]holds digits already used in rowr' - '
cols[c]holds digits already used in columnc' - '
boxes[b]holds digits already used in boxb'
Then validity checks become constant-time membership tests.
This is especially useful when solving many puzzles in a batch.
When Logic-Only Solving Is Different
Some Sudoku discussions focus on human-style techniques such as:
- naked singles
- hidden singles
- naked pairs
- box-line interactions
Those are useful if you want the solver to mimic human reasoning or produce explanation steps. But if your goal is simply to solve the puzzle correctly, backtracking with good heuristics is usually simpler and more robust.
So there are really two different solver goals:
- produce any valid solution quickly
- solve using only explainable human-style deduction steps
Do not confuse them.
Common Pitfalls
The biggest pitfall is forgetting to undo the assignment when recursion fails. Without that backtracking reset, the board state becomes corrupted.
Another issue is writing a validity check that includes the current cell itself incorrectly after assignment.
Developers also often assume “brute force” means bad. In Sudoku, backtracking plus pruning is a perfectly respectable and effective algorithm.
Finally, if you need puzzle explanations rather than just a solved board, the algorithm design changes significantly.
Summary
- A good Sudoku solver is usually a backtracking constraint solver.
- The core checks are row, column, and box validity.
- Basic backtracking works, but choosing the most constrained empty cell improves performance a lot.
- Set-based bookkeeping can make candidate checks much faster.
- Human-style logic solvers and search-based solvers are related, but they solve different product goals.

