280 likes | 294 Views
Computing Science 1P. Large Group Tutorial 20. Simon Gay Department of Computing Science University of Glasgow. 2006/07. Example: More Sudoku. You are probably familiar with sudoku puzzles:. Each row, column and 3x3 square must be filled in to contain the digits 1 – 9.
E N D
Computing Science 1P Large Group Tutorial 20 Simon Gay Department of Computing Science University of Glasgow 2006/07
Example: More Sudoku You are probably familiar with sudoku puzzles: Each row, column and 3x3 square must be filled in to contain the digits 1 – 9. Computing Science 1P Tutorial 20 - Simon Gay
Data Structure for Sudoku A sudoku grid is basically a 9x9 matrix, so the natural data structure is a list of lists. (Could use a dictionary, but little point.) We can either use a list of 9 rows, or a list of 9 columns. Each row or column is itself a list of 9 numbers. It doesn't matter whether we choose rows or columns, as long as we remember which it is. Whatever we do, dealing with the 3x3 squares will be a little awkward. Computing Science 1P Tutorial 20 - Simon Gay
Sudoku as a list of rows [ [0,0,3,0,0,9,4,6,0], [0,0,6,0,0,0,1,0,0], [0,0,0,6,3,2,0,0,0], [5,0,0,0,0,1,0,0,2], [0,2,4,0,0,0,6,8,0], [8,0,0,2,0,0,0,0,7], [0,0,0,5,4,7,0,0,0], [0,0,2,0,0,0,8,0,0], [0,4,5,1,0,0,9,0,0] ] 0 represents an empty square. Computing Science 1P Tutorial 20 - Simon Gay
Solving sudoku How do we start to think about writing a program to solve sudoku puzzles? First idea: just try all the possibilities! Try every way of filling in the blank squares with numbers from 1 to 9, and for each one, check to see whether or not it is a solution. (We defined a function to check for a solution, before Easter). This is an example of a brute force approach. Computing Science 1P Tutorial 20 - Simon Gay
Do you think that this idea will be effective? • Yes • No Computing Science 1P Tutorial 20 - Simon Gay
The brute force approach A typical sudoku might have between 20 and 30 numbers in the grid. Assume that there are 50 blank squares. The number of ways of filling in 50 squares with numbers from 1 to 9 is Assume that on a fast computer we can check 10 million candidate solutions per second. Checking all the possibilities will take seconds, i.e. approx. years. No hope! Computing Science 1P Tutorial 20 - Simon Gay
A more intelligent approach Basic idea: For each square, store a list of numbers which are still possible values for that square. Blank squares are [ 1,2,3,4,5,6,7,8,9] to start with, but the list gets smaller as we fill in other squares. When we discover the value of a particular square, we reduce the list of possibilities for the other squares in the same row, column or 3x3 block. The numbers in the original puzzle get us started. Computing Science 1P Tutorial 20 - Simon Gay
Coordinates We will need to refer to particular squares in the grid, and the obvious way to do this is by using a coordinate system: (row,column) with each ranging from 0 to 8 column 6 row 3 (3,6) Computing Science 1P Tutorial 20 - Simon Gay
Exercise Define a function findRow which is given the coordinates of a square (as a pair, (row,column) ) and returns a list of the squares in the same row. i.e. it returns a list of pairs, each being the coordinates of a square in the same row. def findRow(square): Computing Science 1P Tutorial 20 - Simon Gay
findRow def findRow(square): row = square[0] coords = [] for i in range(9): coords = coords + [(row,i)] return coords findRow( (0,2) ) = [ (0,0),(0,1),(0,2),(0,3),(0,4),(0,5),(0,6), (0,7),(0,8) ] Computing Science 1P Tutorial 20 - Simon Gay
Exercise Similarly, define findCol, which returns a list of the coordinates of the squares in the same column as the given square. Computing Science 1P Tutorial 20 - Simon Gay
findCol def findCol(square): col = square[1] coords = [] for i in range(9): coords = coords + [(i,col)] return coords Computing Science 1P Tutorial 20 - Simon Gay
Exercise Define findBlock, which returns a list of the coordinates of the squares in the same 3x3 block as the given square. findBlock( (1,4) ) = [ (0,3),(0,4),(0,5), (1,3),(1,4),(1,5), (2,3),(2,4),(2,5) ] Computing Science 1P Tutorial 20 - Simon Gay
findBlock def findBlock(square): row = square[0] col = square[1] startRow = (row / 3) * 3 startCol = (col / 3) * 3 coords = [] for i in range(3): for j in range(3): coords = coords + [(startRow+i,startCol+j)] return coords (startRow,startCol) is the top-left corner of the block. E.g. if row = 5, (row / 3) * 3 = (5 / 3) * 3 = 1 * 3 = 3. Computing Science 1P Tutorial 20 - Simon Gay
Exercise It turns out to be more useful to define findRow, findCol and findBlock so that if we call them all for a particular square and combine the results, there is no repetition and the original square is not included. Define new versions. Computing Science 1P Tutorial 20 - Simon Gay
New findRow def findRow(square): row = square[0] col = square[1] coords = [] for i in range(9): if i <> col: coords = coords + [(row,i)] return coords Computing Science 1P Tutorial 20 - Simon Gay
New findCol def findCol(square): row = square[0] col = square[1] coords = [] for i in range(9): if i <> row: coords = coords + [(i,col)] return coords Computing Science 1P Tutorial 20 - Simon Gay
New findBlock def findBlock(square): row = square[0] col = square[1] startRow = (row / 3) * 3 startCol = (col / 3) * 3 coords = [] for i in range(3): for j in range(3): if (startRow+i <> row) and (startCol+j <> col): coords = coords + [(startRow+i,startCol+j)] return coords Computing Science 1P Tutorial 20 - Simon Gay
Example A 4x4 puzzle. Computing Science 1P Tutorial 20 - Simon Gay
Other functions We also need functions remove and initialGrid remove(3,[1,2,3,4,5]) = [1,2,4,5] initialGrid() returns a list of 9 lists, each containing 9 entries, each of which is [1,2,3,4,5,6,7,8,9] Computing Science 1P Tutorial 20 - Simon Gay
Solving Sudoku The main program is based on two functions: eliminate(grid,square,value) removes value from the list of possibilities for square in grid fixValue(grid,square,value) sets square to value and eliminates that value from the possibilities for squares in the same row, column or block Computing Science 1P Tutorial 20 - Simon Gay
eliminate def eliminate(grid,square,value): row = square[0] col = square[1] poss = grid[row][col] if len(poss) > 1: newPoss = remove(value,poss) grid[row][col] = newPoss if len(newPoss) == 1: fixValue(grid,square,newPoss[0]) Computing Science 1P Tutorial 20 - Simon Gay
fixValue def fixValue(grid,square,value): row = square[0] col = square[1] grid[row][col] = [value] coords = findRow(square) + findCol(square) + findBlock(square) for s in coords: eliminate(grid,s,value) Computing Science 1P Tutorial 20 - Simon Gay
The top-level function grid is the original puzzle: a list of lists of integers, with 0 for blank squares g is the list of lists of lists, showing the possible values for each square. def propagate(grid): g = initialGrid() for i in range(9): for j in range(9): if grid[i][j] <> 0: fixValue(g,(i,j),grid[i][j]) return g Computing Science 1P Tutorial 20 - Simon Gay
The main program filename = raw_input("Enter filename: ") printGrid(propagate(readGrid(filename))) Computing Science 1P Tutorial 20 - Simon Gay
Do you think this program can solve all sudokus? • Yes • No • Don't know Computing Science 1P Tutorial 20 - Simon Gay
What's missing? This simple technique is not sufficient to solve all sudoku puzzles. Extending our program to solve all puzzles requires backtracking: trying a possibility, but being prepared to undo the choice if we get stuck. Using backtracking, we can examine all possibilities, but in a much more efficient way than the original brute force idea. If one choice of number turns out to be wrong, we do not consider any other possibilities including that choice. Computing Science 1P Tutorial 20 - Simon Gay