#!/usr/bin/python import sys '''Solves a sudoku using recursive backtracking Licensed under the terms of the GNU GPL v2''' import re class InvalidSudokuError: def __str__(self): return "Invalid sudoku" class SudokuUnsolvableError: def __str__(self): return "Sudoku not solvable" class SudokuSolver: def __init__(self,sudoku=0): self.sudoku = sudoku def solveFile(self,filename): self.readSudoku(filename) return self.solve() def setSudoku(self,sudoku): checkSudoku(sudoku) self.sudoku = sudoku def checkSudoku(self,sudoku): pass def solve(self,sudoku=0): if sudoku == 0 and self.sudoku == 0: raise InvalidSudokuError if sudoku != 0: self.sudoku = sudoku self.unknown_count = 0 for i in self.sudoku: for j in i: if j == 0: self.unknown_count =\ self.unknown_count + 1 if self.nextUnknown(): return self.sudoku raise SudokuUnsolvableError '''Returns the coordinates of the next missing number''' def findNextMissing(self): for i,line in enumerate(self.sudoku): for j,val in enumerate(line): if val == 0: return i,j return -1,-1 '''Finds a suitable number for the next missing one''' def nextUnknown(self): x,y = self.findNextMissing() if x == -1: #No missing number left, we solved it return True for i in range(1,10): if self.isValid(x,y,i): self.sudoku[x][y] = i if self.nextUnknown(): return True self.sudoku[x][y] = 0 return False '''Checks wether number n at [x][y] would be valid''' def isValid(self,x,y,n): #Check same row: if n in self.sudoku[x]: return False #Check same column: for row in self.sudoku: if row[y] == n: return False #Check same square: p,q = int(x/3),int(y/3) for i in range(3*p,3*p+3): for j in range(3*q,3*q+3): if self.sudoku[i][j] == n: return False return True '''Reads a sudoku from a file, zeros denote unknown numbers''' def readSudoku(self,filename): f = file(filename) lines = f.readlines() f.close() if len(lines) != 9: raise InvalidSudokuError regexp = re.compile("[0-9]{9}") self.sudoku = [] for line in lines: tmp = [] if regexp.match(line) == None: raise InvalidSudokuError for char in line: if char == "\n" or char == "\r": continue tmp.append(int(char)) self.sudoku.append(tmp) if len(sys.argv) != 2: print "USAGE:",sys.argv[0],"filename" sys.exit(1) solver = SudokuSolver() try: solution = solver.solveFile(sys.argv[1]) if solution == False: print "No solution possible" else: for i in solution: print i except InvalidSudokuError,inst: print str(inst)