# Sudoku solver, by Rimon Barr # Started: Sat Sep 2 10:18:30 EDT 2006 # Finished: Sat Sep 2 11:44:58 EDT 2006 (1h26) __doc__ = '''python sudoku.py []+ where contains a 9x9 csv board, using pieces 1-9, and either nothing or '0' as empty. ''' import sys, operator, traceback def solve(cells, pieces, rgns, c2r=None): ra=[pieces-set([cells[c] for c in ri if cells[c] in pieces]) for i,ri in zip(range(len(rgns)),rgns)] # available by region if c2r is None: c2r={} # region lookup for i,ri in zip(range(len(rgns)),rgns): for ci in ri: c2r.setdefault(ci,[]).append(i) # input check ru=[[cells[c] for c in ri if cells[c] in pieces] for i,ri in zip(range(len(rgns)),rgns)] # used by region if reduce(operator.or_,[len(v)!=len(set(v)) for v in ru], False): return None # invalid start ca=[(ci,reduce(operator.and_,[ra[ri] for ri in c2r[ci]],pieces)) for ci in cells if cells[ci] not in pieces] # available by open cell ca.sort(lambda x,y: cmp(len(x[1]),len(y[1]))) if not ca: return dict(cells) ci,p=ca[0]; cv,n,soln=cells[ci],0,None for pi in p: try: cells[ci]=pi; r=solve(cells, pieces, rgns, c2r) finally: cells[ci]=cv if not r: continue n+=1; soln=r if n>1: raise ValueError, 'multiple solutions' return soln def solve333(board): # define constraints R = [[(r,c) for c in range(9)] for r in range(9)] # rows C = [[(r,c) for r in range(9)] for c in range(9)] # cols S = sum([[sum([[(r+sr*3,c+sc*3) for r in range(3)] for c in range(3)],[]) for sr in range(3)] for sc in range(3)],[]) # 3x3 sq # convert to sparse, and solve v0 = dict(sum([[((r,c),board[r][c]) for r in range(9)] for c in range(9)],[])) return solve(v0, set(range(1,10)), R+C+S) def show333(cells): if cells is None: print 'no solution'; return for r in range(9): print ','.join([str(cells[(r,c)]) for c in range(9)]) for fname in sys.argv[1:]: print 'File:', fname try: board = [[int(c or '0') for c in l.strip().split(',')] for l in open(fname).readlines()] try: show333(solve333(board)) except ValueError, e: print e except: print 'Unexpected error:'; traceback.print_exception(*sys.exc_info()) print