All functions should be in place, now it's a question of iterating
This commit is contained in:
parent
fa967fd320
commit
7e28aff342
4 changed files with 93 additions and 39 deletions
110
board.py
110
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()
|
||||
|
|
10
main.py
10
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__':
|
||||
|
|
10
square.py
10
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.
|
||||
|
|
2
tests.py
2
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__':
|
||||
|
|
Loading…
Reference in a new issue