Question text in black, answers in blue.
nextInt
method of
Scanner
to get the digits from the strings -- could there be spaces between
the digits?
Yes, that is better, and I have now changed the assignment page.
Indeed we should do that -- apologies that it wasn't in the first version of the assignment. The brown additions to the assignment page should answer your questions, which are good ones. We'll also release a sample driver at some point. (Note added later: The driver was released on the evening of Monday 1 October.)
isBad
method is supposed to check all nine rows,
all nine columns, and all nine boxes whenever it is called. But
this seems very wasteful to me. When I call isBad
,
it's when I have just changed one cell of a valid
Board
.
So only one row, one column, and one box could now be bad. Don't I
save time by checking only those?
Yes, that is true. The isBad
method does not interact with the outside world so you may write it
how you want. I had envisioned it with no parameters, checking the
entire Board
as you say. But you could have
isBad
take two int
parameters for the row
and
column of the last Move
, and guarantee only to catch
double numbers caused by that move. Or you could overload the
method name and do it both ways. But I don't expect running time to
be an issue with this program -- if you get the backtrack search
right it should be very fast.
There is an excellent general technique called
checkpointing for search problems when you don't know how long
the
search is supposed to take. Simply add
System.out.println
statements that periodically tell you
something about where the program is in its search. You could start
with having it report every move put on or taken off the stack. If
that
gives you too much information you could put in a counter so it
reports only every thousandth move, or every millionth. If the
sudoku search tells you every time it considers a new number for the
first few open cells, it tells you about reaching the major
subdivisions of the search.
You are solving the puzzle by trial and error. You fill in cells as long as you can with the lowest available number. When you get blocked, you erase the last number you wrote in and increase it by one. The stack is keeping track of the moves you are currently considering, that is, the ones you have made and not yet erased. Making a new move means pushing it onto the stack, and erasing a move means popping it off the stack.
Your search continues until you either find a solution or conclude that there is no solution. (The latter condition happens if your stack becomes empty.) If there is more than one solution, your method should find the first one (in lexicographic order) and return it, never discovering if there are any more.
As you can see from the new driver, the string array is
constructed there. If we had a console application for this class (as
in the Your code uses the string array in the constructor of the
Balanced
class from DJW that we discussed today in
lecture), the console application could ask the user for nine strings
and assemble them into a string array. You are supposed to write
three classes, none of which has to build a string array.
Board
class, which takes the string array as an
argument. It reads the string, probably with its own
Scanner
, and creates the two 2D arrays with the values
given by the strings.
SudokuSolver
object, with no
parameters. What is happening inside this object? Is its only
purpose to call solve(Board b)
?
Yes, that is its only purpose. It would be much
the same if solve
were a static method, as in the
PostFixEvaluator
class of DJW that we will see Friday.
The Balanced
class had objects because each such object
had to store the strings of opening and closing characters. But since
there is nothing for a SudokuSolver
object to remember,
it could be replaced by a static method. (Don't do it, though,
because our driver will try to create an object.)
Board
constructor. You say it gets a
String [ ]
argument, but shouldn't it get arguments of
type int [ ] [ ]
and boolean [ ] [ ]
because
that is what the Board
object is supposed to have?
You're right that the Board
object is supposed
to have those two 2D arrays, but the way it gets them is through the
code in the constructor that you must write for Board
.
That constructor needs to create the two 2D arrays, then load each
entry
of each 2D array with the correct values. It gets the values by
reading them from the nine strings (one for each row) that come to it
in the String [ ]
object that is its parameter. You can
see what a typical such array looks like by looking at the driver
I posted.
Scanner
object?
A Scanner
is a good way to process a
String
, using methods like hasNextInt
and
nextInt
. The PostFixEvaluator
code in Section
3.8 of DJW has good examples of how to do this.
BadMoveException
class. Do I need to write that class? I'm sure
that my code will never cause the exception.
Yes, you should define the BadMoveException
class and your code should
throw the exception whenever a Board
object is asked to change
a fixed cell. It is possible that our grading driver will test this behavior,
though you are right that the current driver does not.
output2
when you meant output1
, and this won't
compile because output2
is not yet defined. You also say "second
test" in the text output to the console, where you mean "first test".
Fixed about 9:00 Friday morning, thanks.
Yes, very much. We want to do most of the grading automatically, which means we need you to check your solver against our driver. There are several things that might be going wrong for you, besides the bug referred to in Question 2.12 above. If you visit the cells in an order other than the one I expect, you will get a different answer for the first test and will fail the test. If your output string does not exactly match mine for the tests, you will fail the tests -- look carefully for things like extra spaces. You should not get a numerically different solution for the second test, because that puzzle has exactly one solution.
Last modified 5 October 2012