added multiple comments and optimizing
This commit is contained in:
parent
6fee91e0c4
commit
b2fb7bb25b
1 changed files with 256 additions and 125 deletions
381
sources/grid.py
381
sources/grid.py
|
@ -18,136 +18,27 @@ __author__ = 'gaugendre'
|
|||
import sys
|
||||
|
||||
|
||||
def string_from_list(line):
|
||||
def string_from_list(line) -> str:
|
||||
"""
|
||||
Makes a string from a line of squares.
|
||||
:param line: A line (list) of squares to make a string from.
|
||||
:type line: list
|
||||
:return: A string containing all the states of the squares in the list.
|
||||
"""
|
||||
string = ""
|
||||
for square in line:
|
||||
string += square.state
|
||||
return string
|
||||
|
||||
|
||||
class Grid:
|
||||
def __init__(self, size, array=None):
|
||||
_squares = []
|
||||
square_list = []
|
||||
i = 0
|
||||
while i < size:
|
||||
_squares.append([])
|
||||
j = 0
|
||||
while j < size:
|
||||
if array:
|
||||
_squares[i].append(Square(self, i, j, array[i][j]))
|
||||
else:
|
||||
_squares[i].append(Square(self, i, j))
|
||||
j += 1
|
||||
square_list.extend(_squares[i])
|
||||
i += 1
|
||||
|
||||
self._squares = _squares
|
||||
self.size = size
|
||||
self.square_list = square_list
|
||||
|
||||
def _get_squares(self):
|
||||
return self._squares
|
||||
|
||||
squares = property(fget=_get_squares)
|
||||
|
||||
def square(self, horiz, vert):
|
||||
return self._squares[vert][horiz]
|
||||
|
||||
def __repr__(self):
|
||||
representation = ""
|
||||
for line in self._squares:
|
||||
for square in line:
|
||||
to_print = square.state
|
||||
if to_print == ' ':
|
||||
to_print = '_'
|
||||
representation += to_print + ' '
|
||||
representation += "\n"
|
||||
return representation
|
||||
|
||||
def squares_on_line(self, line_number):
|
||||
return self.squares[line_number]
|
||||
|
||||
def squares_on_column(self, col_number):
|
||||
col = []
|
||||
for line in self.squares:
|
||||
col.append(line[col_number])
|
||||
return col
|
||||
|
||||
def solve_three_in_a_row(self):
|
||||
for square in self.square_list:
|
||||
if square.is_empty():
|
||||
v_prev = square.prev_vert()
|
||||
v_next = square.next_vert()
|
||||
h_prev = square.prev_horiz()
|
||||
h_next = square.next_horiz()
|
||||
|
||||
if not square.switched and v_prev and v_prev.state != ' ':
|
||||
v_p_prev = v_prev.prev_vert()
|
||||
if v_p_prev and v_p_prev.state == v_prev.state:
|
||||
square.state = v_prev.opposite_state()
|
||||
elif v_next and v_next.state == v_prev.state:
|
||||
square.state = v_prev.opposite_state()
|
||||
|
||||
if not square.switched and v_next and v_next.state != ' ':
|
||||
v_n_next = v_next.next_vert()
|
||||
if v_n_next and v_n_next.state == v_next.state:
|
||||
square.state = v_next.opposite_state()
|
||||
|
||||
if not square.switched and h_prev and h_prev.state != ' ':
|
||||
h_p_prev = h_prev.prev_horiz()
|
||||
if h_p_prev and h_p_prev.state == h_prev.state:
|
||||
square.state = h_prev.opposite_state()
|
||||
elif h_next and h_next.state == h_prev.state:
|
||||
square.state = h_prev.opposite_state()
|
||||
|
||||
if not square.switched and h_next and h_next.state != ' ':
|
||||
h_n_next = h_next.next_horiz()
|
||||
if h_n_next and h_n_next.state == h_next.state:
|
||||
square.state = h_next.opposite_state()
|
||||
|
||||
def solve(self):
|
||||
for i in range(0, 2, 1):
|
||||
self.solve_three_in_a_row()
|
||||
self.solve_same_number()
|
||||
self.solve_different_lines_or_columns()
|
||||
|
||||
def solve_same_number(self):
|
||||
for square in self.square_list:
|
||||
if square.is_empty():
|
||||
same_line = square.same_line()
|
||||
count_red = 0
|
||||
count_blue = 0
|
||||
for line_square in same_line:
|
||||
if line_square.state == 'B':
|
||||
count_blue += 1
|
||||
elif line_square.state == 'R':
|
||||
count_red += 1
|
||||
|
||||
if count_red == self.size / 2:
|
||||
square.state = 'B'
|
||||
elif count_blue == self.size / 2:
|
||||
square.state = 'R'
|
||||
|
||||
if not square.switched:
|
||||
same_column = square.same_column()
|
||||
count_red = 0
|
||||
count_blue = 0
|
||||
for line_square in same_column:
|
||||
if line_square.state == 'B':
|
||||
count_blue += 1
|
||||
elif line_square.state == 'R':
|
||||
count_red += 1
|
||||
|
||||
if count_red == self.size / 2:
|
||||
square.state = 'B'
|
||||
elif count_blue == self.size / 2:
|
||||
square.state = 'R'
|
||||
|
||||
def solve_different_lines_or_columns(self):
|
||||
pass
|
||||
# for square in self.square_list:
|
||||
# line = string_from_list(square.same_line())
|
||||
def non_space_element(line) -> str:
|
||||
"""
|
||||
Returns the number of non space characters in a string.
|
||||
:param line: The line where to count characters.
|
||||
:type line: str
|
||||
:return: The number of non space characters.
|
||||
"""
|
||||
return len(line.replace(' ', ''))
|
||||
|
||||
|
||||
class Square:
|
||||
|
@ -157,10 +48,11 @@ class Square:
|
|||
written in it and displayed ('R', 'B' or ' ').
|
||||
"""
|
||||
|
||||
def __init__(self, grid, vert, horiz, state=' '):
|
||||
def __init__(self, grid, vert, horiz, state=' ', base=False):
|
||||
self.horiz = horiz
|
||||
self.vert = vert
|
||||
self.switched = False
|
||||
self.base = base
|
||||
if isinstance(grid, Grid):
|
||||
self.grid = grid
|
||||
else:
|
||||
|
@ -292,3 +184,242 @@ class Square:
|
|||
line_list.append(self)
|
||||
line_list.extend(self.all_next_vert())
|
||||
return line_list
|
||||
|
||||
|
||||
def solve_three_square(square) -> bool:
|
||||
"""
|
||||
Checks before and after the square if there are two squares of the
|
||||
same color in order to prevent 'three in a row'.
|
||||
:param square: The Square to check
|
||||
:type square: Square
|
||||
:return: A boolean : True if something has been done, else False.
|
||||
"""
|
||||
solved = False
|
||||
if square.is_empty():
|
||||
v_prev = square.prev_vert()
|
||||
v_next = square.next_vert()
|
||||
h_prev = square.prev_horiz()
|
||||
h_next = square.next_horiz()
|
||||
|
||||
if not square.switched and v_prev and not v_prev.is_empty():
|
||||
v_p_prev = v_prev.prev_vert()
|
||||
if v_p_prev and v_p_prev.state == v_prev.state:
|
||||
square.state = v_prev.opposite_state()
|
||||
v_p_p_prev = v_p_prev.prev_vert()
|
||||
if v_p_p_prev:
|
||||
solve_three_square(v_p_p_prev)
|
||||
elif v_next and v_next.state == v_prev.state:
|
||||
square.state = v_prev.opposite_state()
|
||||
|
||||
if not square.switched and v_next and not v_next.is_empty():
|
||||
v_n_next = v_next.next_vert()
|
||||
if v_n_next and v_n_next.state == v_next.state:
|
||||
square.state = v_next.opposite_state()
|
||||
v_n_n_next = v_n_next.next_vert()
|
||||
if v_n_n_next:
|
||||
solve_three_square(v_n_n_next)
|
||||
|
||||
if not square.switched and h_prev and not h_prev.is_empty():
|
||||
h_p_prev = h_prev.prev_horiz()
|
||||
if h_p_prev and h_p_prev.state == h_prev.state:
|
||||
square.state = h_prev.opposite_state()
|
||||
h_p_p_prev = h_p_prev.prev_horiz()
|
||||
if h_p_p_prev:
|
||||
solve_three_square(h_p_p_prev)
|
||||
elif h_next and h_next.state == h_prev.state:
|
||||
square.state = h_prev.opposite_state()
|
||||
|
||||
if not square.switched and h_next and not h_next.is_empty():
|
||||
h_n_next = h_next.next_horiz()
|
||||
if h_n_next and h_n_next.state == h_next.state:
|
||||
square.state = h_next.opposite_state()
|
||||
h_n_n_next = h_n_next.next_horiz()
|
||||
if h_n_n_next:
|
||||
solve_three_square(h_n_n_next)
|
||||
|
||||
if square.switched:
|
||||
solved = True
|
||||
return solved
|
||||
|
||||
|
||||
class Grid:
|
||||
"""
|
||||
A Grid is a square array containing Squares.
|
||||
"""
|
||||
def __init__(self, size, array=None):
|
||||
"""
|
||||
Instantiate a grid from a size and maybe an array of characters.
|
||||
If an array is provided, the grid will be filled with squares
|
||||
with state corresponding to the character in the array.
|
||||
:param size: The size of the grid (either width or length).
|
||||
:type size: int
|
||||
:param array: The array used to fill the grid.
|
||||
:type array: list
|
||||
"""
|
||||
_squares = []
|
||||
square_list = []
|
||||
squares_to_modify = []
|
||||
i = 0
|
||||
while i < size:
|
||||
_squares.append([])
|
||||
j = 0
|
||||
while j < size:
|
||||
if array:
|
||||
value = array[i][j]
|
||||
if value != ' ':
|
||||
_squares[i].append(Square(self, i, j, value, True))
|
||||
else:
|
||||
_squares[i].append(Square(self, i, j))
|
||||
squares_to_modify.append(_squares[i][j])
|
||||
else:
|
||||
_squares[i].append(Square(self, i, j))
|
||||
squares_to_modify.append(_squares[i][j])
|
||||
j += 1
|
||||
square_list.extend(_squares[i])
|
||||
i += 1
|
||||
|
||||
self._squares = _squares
|
||||
self.size = size
|
||||
self.square_list = square_list
|
||||
self.squares_to_modify = squares_to_modify
|
||||
|
||||
@property
|
||||
def squares(self) -> list:
|
||||
"""
|
||||
A method to get the squares in the grid.
|
||||
:return: The squares in the grid.
|
||||
"""
|
||||
return self._squares
|
||||
|
||||
@squares.setter
|
||||
def squares(self, array):
|
||||
"""
|
||||
Replace the squares in the grid with the one provided in the array.
|
||||
The array must be a list of list of characters (square array).
|
||||
:param array: The array to replace the squares.
|
||||
:type array: list
|
||||
"""
|
||||
squares = []
|
||||
i = 0
|
||||
size = len(array)
|
||||
while i < size:
|
||||
squares.append([])
|
||||
j = 0
|
||||
while j < size:
|
||||
squares[i].append(Square(self, i, j, array[i][j]))
|
||||
j += 1
|
||||
i += 1
|
||||
self._squares = squares
|
||||
|
||||
def square(self, horiz, vert) -> Square:
|
||||
"""
|
||||
Used to get a specific square in the grid.
|
||||
:param horiz: The horizontal position of the square to get.
|
||||
:type horiz: int
|
||||
:param vert: The vertical position of the square to get.
|
||||
:type vert: int
|
||||
:return: The square at the given position
|
||||
"""
|
||||
return self._squares[vert][horiz]
|
||||
|
||||
def __repr__(self):
|
||||
representation = ""
|
||||
for line in self._squares:
|
||||
for square in line:
|
||||
to_print = square.state
|
||||
if to_print == ' ':
|
||||
to_print = '_'
|
||||
representation += to_print + ' '
|
||||
representation += "\n"
|
||||
return representation
|
||||
|
||||
def squares_on_line(self, line_number) -> list:
|
||||
"""
|
||||
Returns the squares on a line specified by the number
|
||||
(starting from zero).
|
||||
:param line_number: The line to get.
|
||||
:type line_number: int
|
||||
:return: The list containing the squares on the required line.
|
||||
"""
|
||||
return self.squares[line_number]
|
||||
|
||||
def squares_on_column(self, col_number) -> list:
|
||||
"""
|
||||
Returns the squares on a column specified by the number
|
||||
(starting from zero).
|
||||
:param col_number: The column to get.
|
||||
:type col_number: int
|
||||
:return: The list containing the squares on the required column.
|
||||
"""
|
||||
col = []
|
||||
for line in self.squares:
|
||||
col.append(line[col_number])
|
||||
return col
|
||||
|
||||
def solve_threes(self) -> bool:
|
||||
"""
|
||||
Solves the grid recursively to prevent 'three in a row'.
|
||||
:return: True if a square has been modified, else False.
|
||||
"""
|
||||
solved = False
|
||||
for square in self.squares_to_modify:
|
||||
if solve_three_square(square):
|
||||
solved = True
|
||||
return solved
|
||||
|
||||
def solve(self):
|
||||
solved = True
|
||||
while solved:
|
||||
if not self.solve_threes():
|
||||
solved = False
|
||||
if self.solve_same_number():
|
||||
solved = True
|
||||
# self.solve_different_lines_or_columns()
|
||||
|
||||
def solve_same_number(self):
|
||||
solved = False
|
||||
for square in self.square_list:
|
||||
if square.is_empty():
|
||||
same_line = square.same_line()
|
||||
count_red = 0
|
||||
count_blue = 0
|
||||
for line_square in same_line:
|
||||
if line_square.state == 'B':
|
||||
count_blue += 1
|
||||
elif line_square.state == 'R':
|
||||
count_red += 1
|
||||
|
||||
if count_red == self.size / 2:
|
||||
square.state = 'B'
|
||||
elif count_blue == self.size / 2:
|
||||
square.state = 'R'
|
||||
|
||||
if not square.switched:
|
||||
same_column = square.same_column()
|
||||
count_red = 0
|
||||
count_blue = 0
|
||||
for line_square in same_column:
|
||||
if line_square.state == 'B':
|
||||
count_blue += 1
|
||||
elif line_square.state == 'R':
|
||||
count_red += 1
|
||||
|
||||
if count_red == self.size / 2:
|
||||
square.state = 'B'
|
||||
elif count_blue == self.size / 2:
|
||||
square.state = 'R'
|
||||
|
||||
if square.switched:
|
||||
solved = True
|
||||
return solved
|
||||
|
||||
def solve_different_lines_or_columns(self):
|
||||
for square in self.square_list:
|
||||
line = string_from_list(square.same_line())
|
||||
col = string_from_list(square.same_column())
|
||||
colored_line = line.replace(' ', '')
|
||||
if len(colored_line) >= self.size - 2:
|
||||
for i in range(0, self.size, 1):
|
||||
if i != square.vert:
|
||||
line_comp = string_from_list(self.squares_on_line(i))
|
||||
col_comp = string_from_list(self.squares_on_column(i))
|
Loading…
Reference in a new issue