I was playing around with my own Sudoku solver and was looking for some pointers to good and fast design when I came across this:
def r(a):i=a.find('0');~i or exit(a);[m in[(i-j)%9*(i/9^j/9)*(i/27^j/27|i%9/3^j%9/3)or a[j]for j in range(81)]or r(a[:i]+m+a[i+1:])for m in'%d'%5**18] from sys import*;r(argv[1])
My own implementation solves Sudokus the same way I solve them in my head but how does this cryptic algorithm work?
http://scottkirkwood.blogspot.com/2006/07/shortest-sudoku-solver-in-python.html
Well, you can make things a little easier by fixing up the syntax:
Cleaning up a little:
Okay, so this script expects a command-line argument, and calls the function r on it. If there are no zeros in that string, r exits and prints out its argument.
I guess this means that zeros correspond to open spaces, and a puzzle with no zeros is solved. Then there’s that nasty recursive expression.
The loop is interesting:
for m in'%d'%5**18Why 5**18? It turns out that
'%d'%5**18evaluates to'3814697265625'. This is a string that has each digit 1-9 at least once, so maybe it’s trying to place each of them. In fact, it looks like this is whatr(a[:i]+m+a[i+1:])is doing: recursively calling r, with the first blank filled in by a digit from that string. But this only happens if the earlier expression is false. Let’s look at that:m in [(i-j)%9*(i/9^j/9)*(i/27^j/27|i%9/3^j%9/3) or a[j] for j in range(81)]So the placement is done only if m is not in that monster list. Each element is either a number (if the first expression is nonzero) or a character (if the first expression is zero). m is ruled out as a possible substitution if it appears as a character, which can only happen if the first expression is zero. When is the expression zero?
It has three parts that are multiplied:
(i-j)%9which is zero if i and j are a multiple of 9 apart, i.e. the same column.(i/9^j/9)which is zero if i/9 == j/9, i.e. the same row.(i/27^j/27|i%9/3^j%9/3)which is zero if both of these are zero:i/27^j^27which is zero if i/27 == j/27, i.e. the same block of three rowsi%9/3^j%9/3which is zero if i%9/3 == j%9/3, i.e. the same block of three columnsIf any of these three parts is zero, the entire expression is zero. In other words, if i and j share a row, column, or 3×3 block, then the value of j can’t be used as a candidate for the blank at i. Aha!
Note that if none of the placements work out, r will return and back up to the point where something else can be chosen, so it’s a basic depth first algorithm.
Not using any heuristics, it’s not particularly efficient. I took this puzzle from Wikipedia (http://en.wikipedia.org/wiki/Sudoku):
Addendum: How I would rewrite it as a maintenance programmer (this version has about a 93x speedup 🙂