diff --git a/sources/grid.py b/sources/grid.py index f99bd1f..4691d8b 100644 --- a/sources/grid.py +++ b/sources/grid.py @@ -18,12 +18,17 @@ __author__ = 'gaugendre' import sys -def string_from_list(line) -> str: +def string_from_list(line): """ 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. + :rtype: str + + .. warnings:: The items of the list must be squares or have an attribute + called 'state'. """ string = "" for square in line: @@ -31,12 +36,18 @@ def string_from_list(line) -> str: return string -def non_space_element(line) -> str: +def non_space_element(line): """ 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. + :rtype: str + + :Example: + >>> non_space_element('Ceci est un test') + 13 """ return len(line.replace(' ', '')) @@ -53,7 +64,7 @@ class Square: self.vert = vert self.switched = False self.base = base - if isinstance(grid, Grid): + if not grid or isinstance(grid, Grid): self.grid = grid else: print("Warning : Attribute grid not instance of Grid", @@ -67,22 +78,54 @@ class Square: self._state = ' ' def next_horiz(self): - if self.horiz == self.grid.size - 1: + """ + A method to get the next square horizontally. + + :return: The next square, horizontally. + :rtype: Square + + .. warnings:: The square must be part of a grid + """ + if not self.grid or self.horiz == self.grid.size - 1: return None return self.grid.square(self.horiz + 1, self.vert) def prev_horiz(self): - if self.horiz == 0: + """ + A method to get the previous square horizontally. + + :return: The previous square, horizontally. + :rtype: Square + + .. warnings:: The square must be part of a grid + """ + if not self.grid or self.horiz == 0: return None return self.grid.square(self.horiz - 1, self.vert) def next_vert(self): - if self.vert == self.grid.size - 1: + """ + A method to get the next square vertically. + + :return: The next square, vertically. + :rtype: Square + + .. warnings:: The square must be part of a grid + """ + if not self.grid or self.vert == self.grid.size - 1: return None return self.grid.square(self.horiz, self.vert + 1) def prev_vert(self): - if self.vert == 0: + """ + A method to get the previous square vertically. + + :return: The previous square, vertically. + :rtype: Square + + .. warnings:: The square must be part of a grid + """ + if not self.grid or self.vert == 0: return None return self.grid.square(self.horiz, self.vert - 1) @@ -98,14 +141,17 @@ class Square: def __repr__(self): return "({}, {}) : '{}'".format(self.horiz, self.vert, self.state) - def _get_state(self): + @property + def state(self): """ Allow to get square state. + :return: The square state. Either ' ', 'R' or 'B' """ return self._state - def _set_state(self, new_state): + @state.setter + def state(self, new_state): """ Changes square state. Accepts only 'R', 'B', or ' '. Other values are not accepted and the square is not modified. @@ -116,9 +162,22 @@ class Square: else: print("Error :", new_state, "not in ('R', 'B', ' ').") - state = property(_get_state, _set_state) - def opposite_state(self): + """ + Returns the opposite state of the current Square. + + The opposite state of 'R' is 'B', and vice-versa. + The opposite state of ' ' is ' '. + + :return: The opposite state of the current square. + :rtype: str + + :Example: + >>> Square(None, 0, 0, 'R').opposite_state() + 'B + >>> Square(None, 0, 0, ' ').opposite_state() + ' '' + """ if self.state == 'R': return 'B' elif self.state == 'B': @@ -127,17 +186,48 @@ class Square: return ' ' def is_empty(self): + """ + Simply tells if the square contains nothing or not. + + :return: True if the square contains ' ', else False. + :rtype: bool + + :Example: + >>> Square(None, 0, 0, ' ').is_empty() + True + >>> Square(None, 0, 0, 'R').is_empty() + False + """ return self.state == ' ' def all_prev_horiz(self): + """ + Get the list of all previous squares, horizontally. + + :return: A list containing all the previous squares horizontally. + :rtype: list + + .. seealso:: prev_horiz() + .. warnings:: The square must be part of a grid. + """ h_prev = self.prev_horiz() all_prev_horiz_list = [] while h_prev: all_prev_horiz_list.append(h_prev) h_prev = h_prev.prev_horiz() + return all_prev_horiz_list def all_next_horiz(self): + """ + Get the list of all next squares, horizontally. + + :return: A list containing all the next squares horizontally. + :rtype: list + + .. seealso:: next_horiz() + .. warnings:: The square must be part of a grid. + """ h_next = self.next_horiz() all_next_horiz_list = [] while h_next: @@ -146,6 +236,15 @@ class Square: return all_next_horiz_list def all_prev_vert(self): + """ + Get the list of all previous squares, vertically. + + :return: A list containing all the previous squares vertically. + :rtype: list + + .. seealso:: prev_vert() + .. warnings:: The square must be part of a grid. + """ v_prev = self.prev_vert() all_prev_vert_list = [] while v_prev: @@ -154,6 +253,15 @@ class Square: return all_prev_vert_list def all_next_vert(self): + """ + Get the list of all next squares, vertically. + + :return: A list containing all the next squares vertically. + :rtype: list + + .. seealso:: next_vert() + .. warnings:: The square must be part of a grid. + """ v_next = self.next_vert() all_next_vert_list = [] while v_next: @@ -165,7 +273,11 @@ class Square: """ List of squares in the same line. Does not include the considered square. + :return: The list of the squares in the same line. + + .. seealso:: all_prev_horiz(), all_next_horiz() + .. warnings:: The square must be part of a grid. """ line_list = [] line_list.extend(self.all_prev_horiz()) @@ -177,7 +289,11 @@ class Square: """ List of squares in the same column. Does not include the considered square. + :return: The list of the squares in the same column. + + .. seealso:: all_prev_vert(), all_next_vert() + .. warnings:: The square must be part of a grid. """ line_list = [] line_list.extend(self.all_prev_vert()) @@ -186,13 +302,17 @@ class Square: return line_list -def solve_three_square(square) -> bool: +def solve_three_square(square): """ + Prevent 'three in a row'. + 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. + :rtype: bool """ solved = False if square.is_empty(): @@ -284,10 +404,11 @@ class Grid: self.squares_to_modify = squares_to_modify @property - def squares(self) -> list: + def squares(self): """ A method to get the squares in the grid. :return: The squares in the grid. + :rtype: list """ return self._squares @@ -295,9 +416,12 @@ class Grid: 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 + + .. warnings:: The array must be a list containing + lists of characters (square array). """ squares = [] i = 0 @@ -311,14 +435,16 @@ class Grid: i += 1 self._squares = squares - def square(self, horiz, vert) -> Square: + def square(self, horiz, vert): """ 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 + :rtype: Square """ return self._squares[vert][horiz] @@ -333,33 +459,39 @@ class Grid: representation += "\n" return representation - def squares_on_line(self, line_number) -> list: + def squares_on_line(self, line_number): """ 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. + :rtype: list """ return self.squares[line_number] - def squares_on_column(self, col_number) -> list: + def squares_on_column(self, col_number): """ 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. + :rtype: list """ col = [] for line in self.squares: col.append(line[col_number]) return col - def solve_threes(self) -> bool: + def solve_threes(self): """ Solves the grid recursively to prevent 'three in a row'. + :return: True if a square has been modified, else False. + :rtype: bool """ solved = False for square in self.squares_to_modify: @@ -368,6 +500,10 @@ class Grid: return solved def solve(self): + """ + Solves the grid using 'three in a row', 'same number of red and blue + on the same line or column' and, later, 'no identical line or column'. + """ solved = True while solved: if not self.solve_threes(): @@ -377,6 +513,13 @@ class Grid: # self.solve_different_lines_or_columns() def solve_same_number(self): + """ + Solves the grid implementing the fact that there is always the same + number of red and blue on the same line or column. + + :return: True if a square has been modified, else False. + :rtype: bool + """ solved = False for square in self.square_list: if square.is_empty(): @@ -414,6 +557,15 @@ class Grid: return solved def solve_different_lines_or_columns(self): + """ + Solves the grid implementing the fact that there isn't two identical + lines or columns. + + :return: True if a square has been modified, else False. + :rtype: bool + + .. warnings:: Function still not finished. DOESN'T WORK. + """ for square in self.square_list: line = string_from_list(square.same_line()) col = string_from_list(square.same_column())