160 likes | 251 Views
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
E N D
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.
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.
answer[][] will hold our current board. • options[][][] will hold the options available for each cell. public class sudoku { private int[][] answer; private boolean[][][] options; // Constructor that sets up our answer board and our set of options. public sudoku(int[][] initBoard) { answer = new int[SIZE][SIZE]; options = new boolean[SIZE][SIZE][SIZE]; for (inti=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 (initBoard[i][j] > 0) { // Set all options to false. for (int k=0; k<SIZE; k++) 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++) options[i][j][k] = true; } } // end j } // end i } Read in the current answer board. If there is already a number there, all options are set to false except for the number at that spot. If BLANK, all options are true.
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?
Determine whether any of the rows have been completely solved OR violate the constraints. public boolean go() { intmyRows = checkRows(); intmyCols = checkCols(); intmyBoxes = checkBoxes(); // Base case: given a completed puzzle. if (myRows == SOLVED && myCols == SOLVED && myBoxes == SOLVED) return true; // Base case: given an invalid puzzle. else if (myRows == INVALID || myCols == INVALID || myBoxes == INVALID) return false; // Redo our options here. reset(); reduceChoiceRows(); reduceChoiceCols(); reduceChoiceBoxes(); // Choose the next square to "guess" at. intgetNextBestSq = getBest(); intnextRow = getNextBestSq/SIZE; intnextCol = getNextBestSq%SIZE; See if the puzzle is already solved. OR if any constraints are violated. 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 (inti=0; i<SIZE; i++) { if (options[nextRow][nextCol][i]) { // Try this answer. answer[nextRow][nextCol] = i+1; // See what happens here. boolean result = go(); // If it works, immediately return true! if (result) return true; // 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(); } } // If none of our options worked, well, it's not solvable! return false; Now we check each available option, for the nextRow, nextCol If it’s possible, set the answer to the next available option Recursively solve the puzzle If that choice worked, we’re done! Otherwise, undo that choice and redo our options. 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 intcheckRows() { booleanseenZero = false; // 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; // Now go through each number in this row. for (intcol=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; // The rows are solved properly, if we get here. return SOLVED; } Checks if the answer rows are consistent. Returns INVALID if not, VALID if so but there are empty squares 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. If it’s zero, mark that the row is unfinished. 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. 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/lectures/ • 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