Program 2 - Constraint Satisfaction Problems (Sudoku)
Due November 11, 2010
Sudoku is a classic game involving constraint satisfaction. If you do not know how to play Sudoku you can learn the rules at this link. In a Sudoku problem parts of a 9x9 grid are set to values from 1 to 9 and the player must fill in the rest of the grid based on certain constraints:
- Each row must have each of the numbers 1 to 9.
- Each column must have each of the numbers 1 to 9.
- The grid is divided into nine 3x3 subgrids, each of these subgrids must have each of the numbers 1 to 9.
For example, the 2 at position 0,0 means that no 2 can occur in the first row or first column, and no other spot may be a 2 in the upper 3x3 grid.
Some Implementation Details
You can find the code I have implemented at prog2.lisp. This code has a routine solve_sudoku that takes in an initial description of a problem. For example, the sudoku grid above would be described by the variable sudoku_m1:
'((0 0 2) (0 8 8)
(1 0 6) (1 5 4) (1 7 1)
(2 0 5) (2 1 8) (2 3 6) (2 4 9) (2 5 2) (2 7 7)
(3 3 8) (3 4 2) (3 6 7) (3 8 4)
(4 3 1) (4 5 9)
(5 0 8) (5 2 5) (5 4 7) (5 5 6)
(6 1 5) (6 3 2) (6 4 6) (6 5 3) (6 7 4) (6 8 9)
(7 1 2) (7 3 7) (7 8 1)
(8 0 4) (8 8 7)))
Other routines in prog2.lisp are:
- initialize_sudoku - returns a two-dimensional array where each location is set to the list (1 2 3 4 5 6 7 8 9) indicating that initially each location can be any of the digits 1-9.
- create_constraint_groups - returns a list of three two dimensional arrays, each array is 9x9 and each location in the arrays describes the positions related to that location. For example, the first array at the 1,2 location contains the list ((1 0) (1 1) (1 2) (1 3) (1 4) (1 5) (1 6) (1 7) (1 8)), which indicates that the 1,2 location is related to all of the other locations on the list (they form a row). Note, this routine is provided as a convenience, you do not need to use it if you prefer not to.
- show_current_grid - takes in a sudoku grid and prints it out showing for each location the set of possible values at that location.
- solve_sudoku - the main routine, which takes in a description as above, sets the initial problem, then calls the routine forward_propagate_constraints followed by the recursive routine backtrack_search.
To complete the code you must complete the two routines:
- forward_propagate_constraints - takes in the current grid, a list of the locations that have changed, for example, it might be set to ((1 2) (2 3)) which indicates the locations 1,2 and 2,3 have changed. This routine should perform a forward propagation where any location that has been set to a single value should be used to remove that value from that row, column and the 3x3 subgrid. This may then lead to changed locations, each of these locations should be added to the list of changed locations and the process should continue.
- backtrack_search - this routine will take in a current grid and determine if the grid is solved (all locations have only one possibility), unsolvable (some location has no possibilities), or has some remaining locations that have not been determined (e.g., if location 0,0 is (1 3 5) this indicates that 0,0 must be one of the values 1,3,5). In the case that a solution has been reached the solution should be returned. In the case of no solution being possible a nil should be returned. In the case where there is some possible values the location that has the smallest number of possible values should be selected, and then that location repeatedly set to one of those values. For example, in the case above, if 0,0 is the location with the smallest number of values left (where there is more than one possibility) we would call backtrack_search recursively setting 0,0 first to 1 to see if that results in a solution, then to 3 if it doesn't, then to 5. If none of those possibilities results in a solution nil should be returned.
The file sudoku.lisp contains 9 problems defined by a variable each. Once you have completed your code run the routine solve_sudoku on each of those variables and report how many nodes are searched during the backtrack search and then what the final solution is.
What To Hand In
Hand in clean, nicely commented copies of all of your code (make sure to include the class code so we can tell if anything is changed). In addition, print out the solution produced for each problem and how many nodes are investigated during your backtrack search. Finally, email your code to me at email@example.com.