Now we will change our application so that we can enter numbers into the cells of the Sudoku grid. We define the method
setCell:to: that changes the state of a cell and we extend the method
renderCellContentAtRow:col:on: to use this new method.
WebSudoku>>setCell: aCurrentCell to: anInteger
sudoku atCell: aCurrentCell removeAllPossibilitiesBut: anInteger
WebSudoku>>renderCellContentAtRow: rowInteger col: colInteger on: html
| currentCell possibilities |
currentCell := MLCell row: rowInteger col: colInteger.
possibilities := sudoku possibilitiesAt: currentCell.
possibilities numberOfPossibilities = 1
ifTrue: [ ^ html text: possibilities asCompactString ].
with: possibilities asCompactString.
html form: [
callback: [ :value |
| integerValue |
integerValue := value asInteger.
integerValue isNil ifFalse: [
(possibilities includes: integerValue)
ifTrue: [ self setCell: currentCell to: integerValue ] ] ] ]
The above code renders a text input box within a form tag, in each cell where there are more than one possibilities. Now you can type a value into the Sudoku grid and press return to save it, as seen in Figure 113. As you enter new values, you will see the possibilities for cells automatically be automatically reduced.
Now we can also ask the Sudoku model to solve itself by modifying the method
renderContentOn:. We first check whether the Sudoku grid is solved and if not, we add an anchor whose callback will solve the puzzle.
html div id: 'sudokuBoard'; with: [
self renderBoardOn: html.
sudoku solved ifFalse: [
callback: [ sudoku := sudoku solve ];
with: 'Solve' ] ]
Note that the solver uses backtracking, i.e., it finds a missing number by trying a possibility and if it fails to find a solution, it restarts with a different number. To backtrack the solver works on copies of the Sudoku grid, throwing away grids that don’t work and restarting. This is why we need to assign the result of sending the message
solve since it returns a new Sudoku grid. Figure 114 shows the result of clicking on Solve.