More Backtracking Examples - Sudoku
Download
Report
Transcript More Backtracking Examples - Sudoku
Announcements
This Wednesday, Class and Labs are
cancelled!
The last lab is due this Wednesday …
how many people are planning on doing
it?
Finally posted Exam 2 and solution on the
website.
Backtracking
Sudoku
Backtracking
Problems seen so far:
◦
◦
◦
◦
N Queens Problem
Magic Number Square
HW #5 – Tentaizu
Recitation #9 - Maze
Backtracking
For the maze problem, what do we need?
◦ Basically you need a nxn board that stores the
empty spots and the wall spots.
◦ Then an nxn board that keeps track of what’s
been used.
Unlike the N Queens problem you don’t need to know
what’s been “placed”, so the board and a used matrix
will be sufficient.
◦ Then you basically just move forward through the
maze and keep moving until you hit a dead end
(hit a wall, or run off the board) or finish.
Sudoku
Sudoku has the following constraints:
◦ The rows must contain the numbers 1-9 with no repeats.
◦ The columns must contain the numbers 1-9 with no repeats.
◦ The boxes must contain the numbers 1-9 with no repeats.
9
8
8
3
6
4
2
9
4
2
4
9
2
1
6
3
5
7
6
1
7
1
6
1
8
7
3
4
4
5
Sudoku
What will we need to keep
track of?
◦ Our current board
int[][] answer
◦ Our available options for
each square
boolean[][][] options
Once we read in the initial
board,
◦ We can update our options.
If there is a number there,
everything is set to false other
than that number.
If there is not a number there
everything is true.
9
8
8
3
6
4
2
9
4
2
4
9
2
1
6
3
5
7
6
1
7
1
6
1
8
7
3
4
4
5
public class sudoku {
private int[][] answer;
private boolean[][][] options;
• answer[][] will hold our current board.
• options[][][] will hold the options available for each
cell.
// Constructor that sets up our answer board and our set of
options.
public sudoku(int[][] initBoard) {
answer = new int[SIZE][SIZE];
Read
options = new boolean[SIZE][SIZE][SIZE];
in the current answer board.
for (int i=0; i<SIZE; i++) {
for (int j=0; j<SIZE; j++) {
answer[i][j] = initBoard[i][j];
// This is given to us on the initial board.
If there is already a number
if (initBoard[i][j] > 0) {
there, all options are set to
// Set all options to false.
false except for the number
for (int k=0; k<SIZE; k++)
that spot.
options[i][j][k] = false;
// and the correct one to true.
options[i][j][initBoard[i][j] - 1] = true;
}
// Open square for right now.
else {
for (int k=0; k<SIZE; k++)
If BLANK, all options are true.
options[i][j][k] = true;
}
at
Sudoku
Now that we have our answer board
and our options, how will we solve
the Sudoku puzzle using backtracking?
◦ We need to check our current board
to see if it is valid
Are the rows ok? Are the columns ok?
Are the boxes ok?
If any are invalid, then we can return false.
◦ We also need to reduce our options.
Currently our options are only based on
the initial board we filled in.
We want to further reduce our options by
looking at what is in each row, column and
box.
◦ After all of that is done, we want to fill
in the next “best” choice to make a
guess.
What cell would be the best cell to make a
guess at?
9
8
8
3
6
4
2
9
4
2
4
9
2
1
6
3
5
7
6
1
7
1
6
1
8
7
3
4
4
5
public boolean go() {
int myRows = checkRows();
int myCols = checkCols();
int myBoxes = checkBoxes();
Determine whether any of the rows
have been completely solved OR
violate the constraints.
// Base case: given a completed puzzle.
if (myRows == SOLVED && myCols == SOLVED && myBoxes == SOLVED)
return true;
See if the puzzle is already solved.
// Base case: given an invalid puzzle.
else if (myRows == INVALID || myCols == INVALID || myBoxes == INVALID)
return false;
OR if any constraints are violated.
// Redo our options here.
reset();
reduceChoiceRows();
reduceChoiceCols();
reduceChoiceBoxes();
// Choose the next square to "guess" at.
int getNextBestSq = getBest();
int nextRow = getNextBestSq/SIZE;
int nextCol = getNextBestSq%SIZE;
Then we reset our options here
based on our current answer board.
At this point we have checked all rows,
and none of them violated our constraint.
for (int i=0; i<SIZE; i++) {
if (options[nextRow][nextCol][i]) {
Now we check each available option,
for the nextRow, nextCol
// Try this answer.
answer[nextRow][nextCol] = i+1;
// See what happens here.
boolean result = go();
If it’s possible, set the answer to the
next available option
Recursively solve the puzzle
// If it works, immediately return true!
if (result)
return true;
If that choice worked, we’re done!
// If we get here, it didn't work, reset to 0 and try again.
answer[nextRow][nextCol] = 0;
// When we undo a choice, we have to redo our options.
reset();
reduceChoiceRows();
reduceChoiceCols();
reduceChoiceBoxes();
Otherwise, undo that choice and
redo our options.
}
}
// If none of our options worked, well, it's not solvable!
return false;
If none of our options worked, then
it’s not solvable!
Sudoku
Now that we have the basic algorithm, we
still have to fill in the following methods:
◦ CheckRows(), CheckCols(), CheckBoxes()
these will check if any of the rows, columns or boxes
have been violated.
◦ ReduceChoiceRows(), ReduceChoicCols(),
ReduceChoiceBoxes()
these will update our options matrix to reduce the
number of possible numbers that can be used in each
cell.
◦ getBest()
will find the next box to fill in, it will return the one with
the lease available options.
public int checkRows() {
boolean seenZero = false;
Checks if the answer rows are consistent.
Returns INVALID if not, VALID if so but there are empty squares
// Go through each row.
for (int row=0; row<SIZE; row++) {
// At first, we've seen nothing.
boolean[] done = new boolean[SIZE];
for (int k=0; k<SIZE; k++)
done[k] = false;
and SOLVED if all the rows are consistent and SOLVED.
Which of the numbers 1 – 9 have been used
in this row? Before we start looking they’re all false.
// Now go through each number in this row.
for (int col=0; col<SIZE; col++) {
if (answer[row][col] == 0)
seenZero = true;
else if (done[answer[row][col] - 1])
return INVALID;
else
done[answer[row][col] - 1] = true;
}
} // end row
// If we saw a zero, the puzzle isn't yet solved.
if (seenZero)
return VALID;
If the current number has already
been seen, there’s a duplicate!
Otherwise, just mark that we’ve
seen this number already.
If we saw a zero, the rows aren’t solved.
// The rows are solved properly, if we get here.
return SOLVED;
}
If it’s zero, mark that the row is
unfinished.
Otherwise, the rows are solved!
Sudoku
reduceChoiceRows() – reduce the options for
each cell, based upon what the current answer
of each row is.
◦ Go through each row
For each row, Store which squares are open (at first they
will all be open)
Then, see if any are set to a value, if so mark it as closed.
NOW, go through each square in this row that ISN’T set
and put in the only appropriate options based upon what
has been used already.
public void reduceChoiceRows()
Suduko
getBest() – returns the square with the
fewest number of options
◦ Goes through all rows and columns
◦ If a square is found that is not filled in (i.e. 0)
Then determine how many choices are in that cell,
and see if that beats our current choice.
The spot will be returned as SIZE*row + col so that
we can return a single int.
public int getBest()
Optional Homework Problem
Fill in the Sudoku shell posted online and
turn in a completed Sudoku solver.
References
Slides adapted from Arup Guha’s Computer
Science II Lecture notes:
http://www.cs.ucf.edu/~dmarino/ucf/cop3503/le
ctures/
Additional material from the textbook:
Data Structures and Algorithm Analysis in Java (Second
Edition) by Mark Allen Weiss
Additional images:
www.wikipedia.com
xkcd.com