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