Brute force sudoku cracker

Tom Anderson twic at urchin.earth.li
Sat Sep 17 07:34:43 EDT 2005


On Fri, 16 Sep 2005, Bas wrote:

> -any ideas how to easily incorporate advanced solving strategies? 
> solve(problem1) and solve(problem2) give solutions, but solve(problem3) 
> gets stuck...

the only way to solve arbitrary sudoku problems is to guess.

of course, you have to deal with guessing wrongly, and it helps if you can 
make good guesses!

i wrote a solver based entirely on guessing and backtracking a few months 
ago; it's fairly simple, although i wrote it in fairly fine-grained java, 
so there's actually quite a lot of code. i had a very different program 
structure to you, since i was only doing guesswork; i had a recursive 
function that looked like this:

def solve(grid):
 	"""Solves a grid.

The solution is written in the grid; if no solution can be found, does 
nothing to the grid. Returns True if a solution was found, False if not. 
"""
 	x, y = pick_an_empty_cell_to_try(grid)
 	letters = letters_which_can_be_written_in_this_cell(grid, x, y)
 	if (letters == []):
 		return False # there are no legal moves; give up
 	for letter in letters:
 		grid.write(x, y, letter) # try a move ...
 		if (solve(grid)):
 			return True # we win!
 		grid.erase(x, y) # ... undo it if it didn't work
 	return False # none of the legal moves work; give up

the implementation of the grid class is pretty straightforward - it's just 
a two-dimensional matrix with some bells and whistles. 
letters_which_can_be_written_in_this_cell is also fairly simple, although 
it can be made a lot faster by keeping summary information in the grid 
object: i had a set for each row, column and region saying which letters 
had been written already, so the set of available letters was the inverse 
of the union of the sets relevant to the cell; the sets were implemented 
as bitmaps, so this was all very fast.

the only tricky bit is pick_an_empty_cell_to_try; you can have fun trying 
different heuristics here! the nice thing is that it's okay to use quite 
computationally expensive heuristics, since a modestly better choice can 
save huge numbers of recursions.

there are a number of much, much more advanced algorithms out there, doing 
all sorts of clever stuff. however, my algorithm solves any sudoku i can 
throw at it (barring seriously unreasonable stuff) in under a second, so 
i'm happy with it.

tom

-- 
I content myself with the Speculative part [...], I care not for the Practick. I seldom bring any thing to use, 'tis not my way. Knowledge is my ultimate end. -- Sir Nicholas Gimcrack



More information about the Python-list mailing list