Next / Previous / Contents / Shipman's homepage

5.3. class SudokuSolver

Here is the interface to the SudokuSolver class.

sudosolver.py
# - - - - -   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 S with this calling sequence:

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 C with calling sequence:

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.

sudosolver.py
      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:

sudosolver.py
        .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.

sudosolver.py
        .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).

sudosolver.py
        .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:

sudosolver.py
      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.

sudosolver.py
        .__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 (R, C) to indices X in these lists works like this: