Originally posted 23 September 2012, due at 11:59 p.m. EDT on
Saturday
6 October 2012, by placing a .java file in a subdirectoty of your cs187 directory on
your edlab account, called proj2
.
For more information on accessing the edlab, see
here or ask in discussion
section.
(Deadline extended on 5 October 2012.)
Goals of this project:
Questions and answers about this project are collected here.
Note in green added 28 September 2012.
Note in purple added 28 September 2012.
Notes in brown added 29 September 2012.
A Latin square of order 9 is a 9 by 9 array of integers, each in the range from 1 through 9, that never has the same number occurring twice in a row or twice in a column. A sudoku is a Latin square of order 9 that also has the property that if we view the 81 cells as divided into 9 boxes, each a 3 by 3 subsquare, no number occurs twice in the same box.
A sudoku puzzle is a 9 by 9 array of integers in the range from 0 through 9, where a 0 represents a cell that must be filled in. The goal of the puzzle is to replace all the 0's with numbers in the range from 1 through 9 to form a sudoku. In commercial puzzles, care has been taken that there is exactly one sudoku that can be made by replacing the 0's. In general there might be none, or more than one. Your program will either return the first sudoku in lexicographic order, or report that there is no solution.
There are many ways to go about this problem, and we are specifying one which is quite different from the way humans solve such puzzles, but which your computer can execute very quickly. This is a backtrack search -- you will first try to find a number that can go in the first open cell without violating the sudoku property, then a number that can go in the second open cell, and so on. (The order on the cells is left to right in the top row, then left to right in the second row, and so on to the last row.) When you find that no number will go in a particular cell, you backtrack to the previous cell and try the next number there. If you run out of numbers in the first cell, there is no solutions. If you find a complete solution, you stop and report it.
Your input may come from the console as in the sample program on page 182-3 of DJW. The user will enter nine lines of text, each containing nine digits and representing a row of the puzzle. For example, the "difficult" puzzle on the New York Times website for 23 September 2012 (but see below) has the following nine rows:
400520103
090800500
100000000
800430000
000000900
056000700
000600000
030007002
020000405
Note: It is somewhat simpler to read a Board
from a text file if there are spaces between the digits, becasue you can use
the nextInt
method in the Scanner
class. So if we
were to give you the puzzle above as a text file, it would look like this:
4 0 0 5 2 0 1 0 3
0 9 0 8 0 0 5 0 0
1 0 0 0 0 0 0 0 0
8 0 0 4 3 0 0 0 0
0 0 0 0 0 0 9 0 0
0 5 6 0 0 0 7 0 0
0 0 0 6 0 0 0 0 0
0 3 0 0 0 7 0 0 2
0 2 0 0 0 0 4 0 5
I miscopied the Times sudoku puzzle originally, putting two 7's in the same column. I don't know if the fixed version above is exactly what the Times had, but it does have at least one solution.
We will outline your program for you and define your two most important classes:
Board
object is a 9 by 9 array of cells, each containing
an int
in the range from 0 through nine, and a 9 by 9 array of
booleans telling which cells are "fixed". (These are the cells that had
positive numbers in them at the start -- these numbers may not be changed.)
The Board
class should have a method boolean isBad( )
,
which tells whether the current position has a positive number occurring
twice in any row, column, or box. It should have a method
void move(Move m)
that takes a Move
object
(defined below) and changes its entry accordingly. It should throw a
BadMoveException
if the move attempts to change a fixed cell.
You may want to define additional getters and setters.
The Board
class should have a constructor that takes
one parameter of type String [ ]
. This parameter
should be an array of nine strings, each one representing a row of
the puzzle. These strings should have spaces between the digits, as
in the second example above.
Move
object represents an order to change one cell of a
Board
. It has three int
instance fields, the
row and column to be changed and the new value. It has a constructor taking
all three of these values and making a new Move
object with them.
You may want to define additional getters and setters.
SudokuSolver
class where the
actual solution of the puzzle will take place. A
SudokuSolver
object will have a solve
method that takes one parameter of type Board
and
returns a String
. (Since any SudokuSolver
object is basically the same, you need just one constructor with no
parameters.)
The output string from solve
will be either
exactly the string "This puzzle has no solution." or nine
lines
of text describing the (first) completed solution. That is, there
will be nine lines, separated by "\n" characters, and each line will
have exactly nine digits with exactly one space between each pair of
digits.
SudokuSolver
object,
create one or more Board
objects, run the
solve
method on each of the Board
objects,
and compare the resulting strings with the correct answers. We'll
make one such driver available -- we may use different example puzzles
in the actual grading. Move
objects, which you may
implement with either a Stack<Move>
object from
java.util
, or with an ArrayStack<Move>
or LinkedStack<Move>
object from DJW's code base. Note
that the names and definitions of the basic stack operations are different
in these two cases.
The fundamental idea is to use the stack to record the moves that you are still considering. When you rule out a move, you pop it from the stack and undo it by setting the value of the cell it refers to 0. Then you can replace it with the move to set the same cell to the next value. If you come up with a set of moves that fills all the unfixed cells without causing a conflict, that is your solution. If you exhaust all the possibilities for the value of your first cell, there is no solution.
You should put your classes in your EdLab space, in a directory called "cs187/proj2", and test the behavior with a main method or a driver class. (We will test the code with our own driver class.)
If you create your code within Eclipse (which we encourage but don't require), you will want to ignore the warning message that says "The use of the default package is discouraged". Bear in mind that if you make the mistake of declaring the StringBag class in a package, our driver class will not see it (since it will not be in a package) and we won't be able to test your code.
Last modified 5 October 2012