""" Sudoku Solver Written by Owain Jones <odj@aber.ac.uk> Based on the one by Peter Norvig <http://norvig.com/sudoku.html> """ from __future__ import print_function def cross(A, B): """Return the cross-product of elements in A and elements in B""" return [a + b for a in A for b in B] digits = '123456789' rows = 'ABCDEFGHI' cols = digits squares = cross(rows, cols) unitlist = ([cross(rows, col) for col in cols] + [cross(row, cols) for row in rows] + [cross(rs, cs) for rs in ('ABC', 'DEF', 'GHI') for cs in ('123', '456', '789')]) units = dict((s, [u for u in unitlist if s in u]) for s in squares) peers = dict((s, set(sum(units[s], [])) - set([s])) for s in squares) def test(): """A set of unit tests.""" assert len(squares) == 81 assert len(unitlist) == 27 assert all(len(units[s]) == 3 for s in squares) assert all(len(peers[s]) == 20 for s in squares) assert units['C2'] == [['A2', 'B2', 'C2', 'D2', 'E2', 'F2', 'G2', 'H2', 'I2'], ['C1', 'C2', 'C3', 'C4', 'C5', 'C6', 'C7', 'C8', 'C9'], ['A1', 'A2', 'A3', 'B1', 'B2', 'B3', 'C1', 'C2', 'C3']] assert peers['C2'] == set(['A2', 'B2', 'D2', 'E2', 'F2', 'G2', 'H2', 'I2', 'C1', 'C3', 'C4', 'C5', 'C6', 'C7', 'C8', 'C9', 'A1', 'A3', 'B1', 'B3']) print('All tests pass.') def grid_values(grid): """Convert grid into a dict of {square: char} with '0' or '.' for empties.""" chars = [c for c in grid if c in digits or c in '0.'] assert len(chars) == 81 return dict(zip(squares, chars)) def parse_grid(grid): """Convert grid to a dict of possible values, {square: digits}, or return False if a contradiction is detected.""" # To start, every square can be any digit; then assign values from the grid. values = dict((s, digits) for s in squares) for s, d in grid_values(grid).items(): if d in digits and not assign(values, s, d): return False # Fail if we can't assign d to square s. return values # Now we've got the grid building stuff done, on to Constraint Propagation! def eliminate(values, s, d): """Eliminate d from values[s]; propagate when values or places <= 2. Return values, exceptreturn False if a contradiction is detected.""" if d not in values[s]: return values # Already eliminated values[s] = values[s].replace(d, '') # (1) If a square is reduced to one value d2, then eliminate d2 from the peers. if len(values[s]) == 0: return False # Contradiction: removed last value elif len(values[s]) == 1: d2 = values[s] if not all(eliminate(values, s2, d2) for s2 in peers[s]): return False # (2) If a unit u is reduced to only one place for a value d, then put it there. for u in units[s]: dplaces = [s for s in u if d in values[s]] if len(dplaces) == 0: return False # Contradiction: no place for this value elif len(dplaces) == 1: # d can only be in one place in unit; assign it there if not assign(values, dplaces[0], d): return False return values def assign(values, s, d): """Eliminate all the other values (except d) from values[s] and propagate. Return values, except return False if a contradiction is detected.""" other_values = values[s].replace(d, '') if all(eliminate(values, s, d2) for d2 in other_values): return values else: return False # Now before we can go much further, we'll need to display a puzzle. def display(values): """Display these values as a 2D grid.""" width = 1 + max(len(values[s]) for s in squares) line = '+'.join(['-' * (width * 3)] * 3) for r in rows: print(''.join(values[r + c].center(width) + ('|' if c in '36' else '') for c in cols)) if r in 'CF': print(line) print() # Now we're ready to go. Here it is using the first example from a list of easy puzzles # from the Project Euler Sudoku problem. def main(): grid1 = '003020600900305001001806400008102900700000008006708200002609500800203009005010300' grid2 = '4.....8.5.3..........7......2.....6.....8.4......1.......6.3.7.5..2.....1.4......' display(parse_grid(grid1)) print() display(parse_grid(grid2)) if __name__ == '__main__': main()
Run
Reset
Share
Import
Link
Embed
Language▼
English
中文
Python Fiddle
Python Cloud IDE
Follow @python_fiddle
Browser Version Not Supported
Due to Python Fiddle's reliance on advanced JavaScript techniques, older browsers might have problems running it correctly. Please download the latest version of your favourite browser.
Chrome 10+
Firefox 4+
Safari 5+
IE 10+
Let me try anyway!
url:
Go
Python Snippet
Stackoverflow Question