From 7e28aff342f4b446e2deafb9b835175060fd9c3a Mon Sep 17 00:00:00 2001 From: flying-scorpio Date: Sat, 30 Nov 2019 17:04:43 +0100 Subject: [PATCH] All functions should be in place, now it's a question of iterating --- board.py | 110 +++++++++++++++++++++++++++++++++++++++--------------- main.py | 10 +++-- square.py | 10 ++--- tests.py | 2 +- 4 files changed, 93 insertions(+), 39 deletions(-) diff --git a/board.py b/board.py index cb18153..ec35074 100644 --- a/board.py +++ b/board.py @@ -11,7 +11,6 @@ class Board: def __init__(self, string): self.lines = [""] * 9 - i = 0 line = 0 while line < 9: @@ -22,11 +21,13 @@ class Board: i += 1 self.columns = [""] * 9 - for col in range(9): for line in self.lines: self.columns[col] += line[col] + self.grids = self.__compute_grid_values() + self.squares = [] + self.__assert_lines_and_columns_have_same_values() def __str__(self): @@ -39,8 +40,8 @@ class Board: else: output += '.' elif isinstance(item, Square): - if len(item.content) == 1: - output += str(item.content)[1:-1] + if len(item.values) == 1: + output += str(item.values)[2:-2] else: output += '.' else: @@ -55,17 +56,43 @@ class Board: for lin in range(len(self.lines)): for col in range(len(self.columns)): if isinstance(self.lines[lin][col], Square): - line_content = self.lines[lin][col].content - column_content = self.columns[col][lin].content + line_values = self.lines[lin][col].values + column_values = self.columns[col][lin].values else: - line_content = self.lines[lin][col] - column_content = self.columns[col][lin] + line_values = self.lines[lin][col] + column_values = self.columns[col][lin] - if line_content != column_content: + if line_values != column_values: differences.append('X') assert len(differences) == 0 + def __compute_grid_values(self): + grids = [""] * 9 + for lin, line in enumerate(self.lines): + for col in range(9): + if line[col] != '.': + if lin // 3 == 0 and col // 3 == 0: + grids[0] += line[col] + elif lin // 3 == 0 and col // 3 == 1: + grids[1] += line[col] + elif lin // 3 == 0 and col // 3 == 2: + grids[2] += line[col] + elif lin // 3 == 1 and col // 3 == 0: + grids[3] += line[col] + elif lin // 3 == 1 and col // 3 == 1: + grids[4] += line[col] + elif lin // 3 == 1 and col // 3 == 2: + grids[5] += line[col] + elif lin // 3 == 2 and col // 3 == 0: + grids[6] += line[col] + elif lin // 3 == 2 and col // 3 == 1: + grids[7] += line[col] + elif lin // 3 == 2 and col // 3 == 2: + grids[8] += line[col] + + return [set(values) for values in grids] + def __compute_possible_values_from_lines(self): """Compute possible values for each number in a line. @@ -74,16 +101,16 @@ class Board: aren't already present in that same line. """ - for line_index, line in enumerate(self.lines): - self.lines[line_index] = list(line) + for lin, line in enumerate(self.lines): + self.lines[lin] = list(line) for column in range(9): if line[column] == '.': - self.lines[line_index][column] = { - number for number in range(1, 10) + self.lines[lin][column] = { + str(number) for number in range(1, 10) if str(number) not in line } else: - self.lines[line_index][column] = {int(line[column])} + self.lines[lin][column] = {line[column]} def __compute_possible_values_from_columns(self): """Compute possible values for each number in a column. @@ -93,16 +120,16 @@ class Board: they aren't already present in that same column. """ - for column_index, column in enumerate(self.columns): - self.columns[column_index] = list(column) + for col, column in enumerate(self.columns): + self.columns[col] = list(column) for line in range(9): if column[line] == '.': - self.columns[column_index][line] = { - number for number in range(1, 10) + self.columns[col][line] = { + str(number) for number in range(1, 10) if str(number) not in column } else: - self.columns[column_index][line] = {int(column[line])} + self.columns[col][line] = {column[line]} def compute_possible_values(self): """Compute possible values for each square in the board.""" @@ -110,7 +137,23 @@ class Board: self.__compute_possible_values_from_lines() self.__compute_possible_values_from_columns() - def intersect_possible_values(self): + def create_squares(self): + """Make each square of the board a Square object.""" + + self.squares = [] + + if isinstance(self.lines[0][0], set): + print("SQUARES CREATED") + for lin, line in enumerate(self.lines): + for col in range(len(self.columns)): + square = Square(lin, col, line[col]) + self.lines[lin][col] = square + self.columns[col][lin] = square + self.squares.append(square) + + self.__assert_lines_and_columns_have_same_values() + + def intersect_lines_and_columns(self): """Remove impossible values from possibilities in lines and columns. Go through each line and for each square intersect the set with the set @@ -123,17 +166,24 @@ class Board: for lin, line in enumerate(self.lines): for col, column in enumerate(self.columns): - self.lines[lin][col] = line[col].intersection(column[lin]) - self.columns[col][lin] = column[lin].intersection(line[col]) + if isinstance(self.lines[lin][col], Square): + self.lines[lin][col].values = line[col].values.intersection(column[lin].values) + self.columns[col][lin].values = column[lin].values.intersection(line[col].values) + else: + self.lines[lin][col] = line[col].intersection(column[lin]) + self.columns[col][lin] = column[lin].intersection(line[col]) self.__assert_lines_and_columns_have_same_values() - def create_squares(self): - """Make each square of the board a Square object.""" + def discard_with_grids(self): + """Remove impossible values in squares, by discarding from grids.""" - for lin, line in enumerate(self.lines): - for col, column in enumerate(self.columns): - self.lines[lin][col] = Square(lin, col, line[col]) - self.columns[col][lin] = Square(lin, col, column[lin]) - - self.__assert_lines_and_columns_have_same_values() + for square in self.squares: + # print(square.values) + # print(self.grids[square.grid_id]) + if len(square.values) > 1: + for value in self.grids[square.grid_id]: + if value in square.values: + square.values.discard(value) + # print(square.values) + # print() diff --git a/main.py b/main.py index 22dec71..1bb38cb 100644 --- a/main.py +++ b/main.py @@ -6,6 +6,8 @@ from board import Board def main(): + """Provided a string representing a Sudoku game, solve it.""" + string = ( "..4...618\n" "9...8....\n" @@ -20,13 +22,15 @@ def main(): board = Board(string) - print(board) + print(f"Original board:\n{board}") board.compute_possible_values() - board.intersect_possible_values() + board.intersect_lines_and_columns() board.create_squares() - print(board) + board.discard_with_grids() + + print(f"Solved board:\n{board}") if __name__ == '__main__': diff --git a/square.py b/square.py index b7e1ebd..ccf4ef6 100644 --- a/square.py +++ b/square.py @@ -4,17 +4,17 @@ class Square: """A Square object represents a square on the board. - The square's content will consist of a set of possible values for that + The square's values will consist of a set of possible values for that square. - The grid attribute identifies in which 9x9 grid the square belongs to. + The grid_id attribute identifies in which 9x9 grid the square belongs to. """ - def __init__(self, line, column, content): + def __init__(self, line, column, values): self.line = line self.column = column - self.grid = self.compute_grid() + self.grid_id = self.compute_grid() self.coordinates = (self.line, self.column) - self.content = content + self.values = values def compute_grid(self): """Given the coordinates, determine which grid the Square belongs to. diff --git a/tests.py b/tests.py index 2198800..c57dba3 100644 --- a/tests.py +++ b/tests.py @@ -33,7 +33,7 @@ class TestSquare(unittest.TestCase): ) for i, square in enumerate(self.board): - self.assertEqual(square.grid, int(correct_grids[i])) + self.assertEqual(square.grid_id, int(correct_grids[i])) if __name__ == '__main__':