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