Sudoku solver
Marko Rauhamaa
marko at pacujo.net
Thu Mar 26 11:42:05 EDT 2015
Dave Angel <davea at davea.name>:
> When in a playful mood, I wonder if all the Sudoku puzzles out there
> are just permutations of a few hundred written by Will Shortz.
A sudoku solver can be trivially turned into a puzzle generator:
========================================================================
$ ./sudoku.py --generate >puzzle.dat
$ cat puzzle.dat
3 . 2 . 4 . . . .
4 5 . . . 6 . . .
6 . . . 9 . . 8 .
. . . . . . 5 . .
. 6 4 . . 9 . 3 .
. 7 3 5 . . . 4 8
. . . . . . 8 . .
. 8 . . 7 . . . 3
. . . . 1 . . . 2
$ ./sudoku.py <puzzle.dat
3 9 2 8 4 7 1 6 5
4 5 8 1 3 6 7 2 9
6 1 7 2 9 5 3 8 4
8 2 1 4 6 3 5 9 7
5 6 4 7 8 9 2 3 1
9 7 3 5 2 1 6 4 8
1 4 9 3 5 2 8 7 6
2 8 5 6 7 4 9 1 3
7 3 6 9 1 8 4 5 2
========================================================================
========================================================================
#!/usr/bin/env python3
import sys, random
M = 3
N = M * M
P = M * N
Q = M * P
EMPTY = "."
buddies = [ [ buddy
for buddy in range(Q)
if buddy != slot and
(buddy % N == slot % N or
buddy // N == slot // N or
buddy // P == slot // P and
buddy % N // M == slot % N // M) ]
for slot in range(Q) ]
interned = { n : n for n in range(1, N + 1) }
candidates = list(interned.values())
def main():
if len(sys.argv) > 1 and sys.argv[1] == "--generate":
generate()
return
board = []
for n in sys.stdin.read().split():
try:
board.append(int(n))
except ValueError:
board.append(EMPTY)
for solution in solve(board):
report(solution)
def generate():
report(minimize(next(solve([ EMPTY ] * Q))))
def solve(board, slot=0):
if slot == Q:
yield board[:]
elif board[slot] is EMPTY:
shuffled = candidates[:]
random.shuffle(shuffled)
for candidate in shuffled:
for buddy in buddies[slot]:
if board[buddy] is candidate:
break
else:
board[slot] = candidate
yield from solve(board, slot + 1)
board[slot] = EMPTY
else:
yield from solve(board, slot + 1)
def minimize(board):
while True:
nonempty_slots = [ slot for slot in range(Q)
if board[slot] is not EMPTY ]
random.shuffle(nonempty_slots)
for slot in nonempty_slots:
removed, board[slot] = board[slot], EMPTY
if uniquely_solvable(board):
break
board[slot] = removed
else:
return board
def uniquely_solvable(board):
it = solve(board[:])
next(it)
try:
next(it)
except StopIteration:
return True
return False
def report(board):
print("\n".join(
" ".join(str(board[row * N + col])
for col in range(N))
for row in range(N)))
print()
if __name__ == '__main__':
main()
========================================================================
Marko
More information about the Python-list
mailing list