Here is the interface to the SudokuSolver
class.
# - - - - - c l a s s S u d o k u S o l v e r - - - - - class SudokuSolver: """Represents one sudoku puzzle.
The constructor takes three arguments:
givenPuzzle
The initial puzzle as a string. The format of this
string is the same as the format of the file
described in Section 2, “Encoding the puzzle”. You can use
the .read()
method on a
file object to read the entire file and store it in
a string.
solutionObserver
An Observer function that will be called whenever
the SudokuSolver
instance detects a complete solution to
the puzzle. Write the procedure
with
this calling sequence:
S
S
( solver )
where the solver
argument
will be the SudokuSolver
instance.
changeObserver
An Observer function that will be called whenever a
cell of the puzzle changes during the solution
process. Write this procedure
with
calling sequence:
C
C
( solver, row, col, state )
solver
The SudokuSolver
instance after the state change.
row
The row index of the cell that changed, in the interval [0,8].
col
The column index of the cell that changed, in the interval [0,8].
state
The new state of the cell, an integer in the interval [0,9]. A value of 0 indicates that the cell is being set back to empty.
Here is the intended function for the constructor.
Note that it raises a ValueError
exception if the givenPuzzle
argument is not a correctly formed puzzle.
Exports: SudokuSolver ( givenPuzzle, solutionObserver=None, changeObserver=None ): [ (givenPuzzle is a sudoku puzzle as a string) and (solutionObserver is a procedure or None) and (changeObserver is a procedure or None) -> if givenPuzzle is a valid sudoku puzzle -> return a SudokuSolver object representing that puzzle in its initial state else -> raise ValueError ]
Methods and attributes of the SudokuSolver
include:
.givenPuzzle: [ as passed to constructor, read-only ] .solutionObserver: [ as passed to constructor, read-only ] .changeObserver: [ as passed to constructor, read-only ] .solve() [ call self.changeObserver (if any) for every change to a cell value and call self.solutionObserver for every solution of self ]
The .get()
method is used to
query the state of one cell of the puzzle.
.get(r, c): [ r and c are integers -> if (0<=r<MAT_L) and (0<=c<MAT_L) -> return the state of the cell at row r and column c as 0 for empty, or an integer in [1,9] if set else -> raise KeyError ]
As a convenience for a quick display of the state of a
puzzle (initially or at solution time), we provide a
.write()
function that displays
the puzzle in the same format as the input files (with
our recommended extra spaces added).
.write(outFile): [ outFile is a writeable file -> outFile +:= a representation of self's state in input-file format ]
Two more attributes accumulate statistics that may be of
interest to the caller after the .solve()
method has returned:
State/Invariants: .nStateChanges: [ number of cell state changes so far ] .nSolutions: [ number of solutions seen so far ]
Here are the internal attributes of the instance. The
.__given
attribute holds a copy
of the puzzle in its initial state, so we can determine
whether a cell's value was set initially or added in the
solving process. The .__board
attribute holds the current state of the puzzle.
.__given: [ the initial state of the puzzle as a list of integers, 0 for empty, or in [1,9] if set ] .__board: [ the current state of the puzzle as a list of integers, 0 for empty, or in [1,9] if set ] """
Both these attributes represent the puzzle as a list of
81 integers. In this list, 0 represents a blank cell,
and integers 1 through 9 represent the digit in a cell
that has been filled in. The mapping from row and column
indices (
) to indices
R
,
C
in these lists works like this:
X
To convert from board index to row and column:
R, C = divmod ( X, 9 )
To convert from row and column to board index:
X = (R * 9) + C