# Part 2: Sudoku Board Game Logic

Walkthrough of writing the logic for our Sudoku Board.

## Creating the Sudoku Board

When we eventually run the `sudoku.py` script, we first need to create a Python representation of the Sudoku board that we pass in as an argument. We’ll start off with a class representing a Sudoku board in `sudoku.py`:

 ```1 2 3 4``` ```class SudokuBoard(object): """ Sudoku Board representation """ ```

When a new board is created, e.g. `new_board = SudokuBoard()`, it should initialize with the name of the `.sudoku` file (which we will create towards the end of the tutorial) we pass in as an argument:

 ```1 2 3 4 5 6``` ```class SudokuBoard(object): """ Sudoku Board representation """ def __init__(self, board_file): self.board = board_file ```

Now we actually want to parse out the `board_file` by making a matrix, or a list of lists. We can do this by creating a private function (denoted by two leading `_`), and setting `self.board` equal to that private function:

 ```1 2 3 4 5 6 7 8 9``` ```class SudokuBoard(object): """ Sudoku Board representation """ def __init__(self, board_file): self.board = __create_board(board_file) def __create_board(self, board_file): pass ```

With `__create_board`, we will iterate over each line in the `.sudoku` file, and each integer in the line, and create the matrix representing the Sudoku board.

 ``` 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19``` ```class SudokuBoard(object): """ Sudoku Board representation """ def __init__(self, board_file): self.board = self.__create_board(board_file) def __create_board(self, board_file): # create an initial matrix, or a list of a list board = [] # iterate over each line # then iterate over each character # Raise an error if there are not 9 lines # Return the constructed board return board ```

Now let’s iterate over each line in the board file, adding each character to the `board` variable, with the appropriate errors raised if the length of a line is not equal to 9, or the number of lines in the file is not equal to 9.

 ``` 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41``` ```class SudokuBoard(object): """ Sudoku Board representation """ def __init__(self, board_file): self.board = self.__create_board(board_file) def __create_board(self, board_file): # create an initial matrix, or a list of a list board = [] # iterate over each line for line in board_file: line = line.strip() # raise error if line is longer or shorter than 9 characters if len(line) != 9: board = [] raise SudokuError( "Each line in the sudoku puzzle must be 9 chars long." ) # create a list for the line board.append([]) # then iterate over each character for c in line: # Raise an error if the character is not an integer if not c.isdigit(): raise SudokuError( "Valid characters for a sudoku puzzle must be in 0-9" ) # Add to the latest list for the line board[-1].append(int(c)) # Raise an error if there are not 9 lines if len(board) != 9: raise SudokuError("Each sudoku puzzle must be 9 lines long") # Return the constructed board return board ```

OK so we initialized `SudokuBoard` object with a `board_file` (e.g. `debug.sudoku`), and created a list of lists (a matrix) to represent the Sudoku board to solve.

Next, we’ll create an object representing the game itself, `SudokuGame`.

## Creating the Sudoku Game

We are representing the game as a Python class because we want to maintain the state of the game. Here, we maintain the state of the board (e.g. every time the user inputs a number), as well as check to see if the latest board state is actually a “win”.

`SudokuGame` will be initialized with our `board_file` to create the actual board for the game:

 ```1 2 3 4 5 6 7 8``` ```class SudokuGame(object): """ A Sudoku game, in charge of storing the state of the board and checking whether the puzzle is completed. """ def __init__(self, board_file): self.board_file = board_file self.start_puzzle = SudokuBoard(board_file).board ```

Next we’ll set up the puzzle for the user to play:

 ``` 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16``` ```class SudokuGame(object): """ A Sudoku game, in charge of storing the state of the board and checking whether the puzzle is completed. """ def __init__(self, board_file): self.board_file = board_file self.start_puzzle = SudokuBoard(board_file).board def start(self): self.game_over = False self.puzzle = [] for i in xrange(9): self.puzzle.append([]) for j in xrange(9): self.puzzle[i].append(self.start_puzzle[i][j]) ```

In `start()`, we set a flag, `self.game_over`, to `False`. When the user plays the game and correctly solves it, we’ll set it to `True`.

We create a copy of the puzzle for two reasons: to create the functionality of clearing the board when the user wants to start over, as well as to check the inputted answers against the start board.

NOTE: We simply can not set `self.puzzle` to `self.start_puzzle`. If we were to, Python actually does not create a brand new object; the variable name `self.puzzle` would just point to `self.start_puzzle`. So any edits to `self.start_puzzle` (e.g. when the user fills in numbers) it would change the `self.puzzle`. We don’t want this – we want to preserve the start puzzle.

Now we will add the logic to actually checking the answers to see if the user has won the puzzle.

We’ll create a function called `check_win` that will check the board’s rows, columns, and each 3x3 square:

 ``` 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16``` ```class SudokuGame(object): # <-- snip --> def check_win(self): for row in xrange(9): if not self.__check_row(row): return False for column in xrange(9): if not self.__check_column(column): return False for row in xrange(3): for column in xrange(3): if not self.__check_square(row, column): return False self.game_over = True return True ```

You might have noticed that there are three helper functions we have yet to define, but basically, we are iterating over each row, each column, and each 3x3 square. If either the row, column, or square does not pass some logic (which we will implement next), we return `False`.

However, if all of them do pass our logic, we set the `game_over` flag to `True`, and return `True`. Later when we implement the user interface, we will be referring to the `game_over` flag.

Now for each helper function that is the logic of checking the inputted numbers:

 ``` 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36``` ```class SudokuGame(object): # <-- snip --> def check_win(self): for row in xrange(9): if not self.__check_row(row): return False for column in xrange(9): if not self.__check_column(column): return False for row in xrange(3): for column in xrange(3): if not self.__check_square(row, column): return False self.game_over = True return True def __check_block(self, block): return set(block) == set(range(1, 10)) def __check_row(self, row): return self.__check_block(self.puzzle[row]) def __check_column(self, column): return self.__check_block( [self.puzzle[row][column] for row in xrange(9)] ) def __check_square(self, row, column): return self.__check_block( [ self.puzzle[r][c] for r in xrange(row * 3, (row + 1) * 3) for c in xrange(column * 3, (column + 1) * 3) ] ) ```

We have the main logic method, `__check_block`. This returns `True` if the block that we’ve passed in (either the row, column, or square) is equal to `set(range(1,10))`. The `set(range(1, 10))` means that only numbers 1 through 9 (the last number in `range` in Python is excluded) are valid. If the block that is passed into the method, then `False` is returned.

`__check_row` and `__check_column` iterates over each row/column of the puzzle with the user’s input, and passes it to `__check_block`. The same with `__check_square`, but rather than a row or a column, it pulls out a 3x3 square.

So that’s it for the `SudokuGame` and `SudokuBoard` objects! Here is the complete code for those two classes:

 ``` 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79``` ```class SudokuBoard(object): """ Sudoku Board representation """ def __init__(self, board_file): self.board = self.__create_board(board_file) def __create_board(self, board_file): board = [] for line in board_file: line = line.strip() if len(line) != 9: raise SudokuError( "Each line in the sudoku puzzle must be 9 chars long." ) board.append([]) for c in line: if not c.isdigit(): raise SudokuError( "Valid characters for a sudoku puzzle must be in 0-9" ) board[-1].append(int(c)) if len(board) != 9: raise SudokuError("Each sudoku puzzle must be 9 lines long") return board class SudokuGame(object): """ A Sudoku game, in charge of storing the state of the board and checking whether the puzzle is completed. """ def __init__(self, board_file): self.board_file = board_file self.start_puzzle = SudokuBoard(board_file).board def start(self): self.game_over = False self.puzzle = [] for i in xrange(9): self.puzzle.append([]) for j in xrange(9): self.puzzle[i].append(self.start_puzzle[i][j]) def check_win(self): for row in xrange(9): if not self.__check_row(row): return False for column in xrange(9): if not self.__check_column(column): return False for row in xrange(3): for column in xrange(3): if not self.__check_square(row, column): return False self.game_over = True return True def __check_block(self, block): return set(block) == set(range(1, 10)) def __check_row(self, row): return self.__check_block(self.puzzle[row]) def __check_column(self, column): return self.__check_block( [self.puzzle[row][column] for row in xrange(9)] ) def __check_square(self, row, column): return self.__check_block( [ self.puzzle[r][c] for r in xrange(row * 3, (row + 1) * 3) for c in xrange(column * 3, (column + 1) * 3) ] ) ```

Next up: adding the graphical user interface of the board.