# 0h h1 Solver. Solves grids of 0h h1 game. # Copyright (C) 2015 Gabriel Augendre # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . __author__ = 'gaugendre' import sys 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 solve(self): for k in range(0, 10, 1): 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() # print("Taking care of {}".format(square)) if not square.switched and v_prev and v_prev.state != ' ': # print("On vérifie le précédent vertical.") 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() # print("Square {} switched to {}".format(square, # square.state)) elif v_next and v_next.state == v_prev.state: square.state = v_prev.opposite_state() # print("Square {} switched to {}".format(square, # square.state)) if not square.switched and v_next and v_next.state != ' ': # print("On vérifie le suivant vertical.") 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() # print("Square {} switched to {}".format(square, # square.state)) if not square.switched and h_prev and h_prev.state != ' ': # print("On vérifie le précédent horizontal.") 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() # print("Square {} switched to {}".format(square, # square.state)) elif h_next and h_next.state == h_prev.state: square.state = h_prev.opposite_state() # print("Square {} switched to {}".format(square, # square.state)) if not square.switched and h_next and h_next.state != ' ': # print("On vérifie le suivant horizontal.") 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() # print("Square {} switched to {}".format(square, # square.state)) class Square: """ Represents a square in the grid. A square can be either Red, Blue, or Nothing, depending on the text written in it and displayed ('R', 'B' or ' '). """ def __init__(self, grid, vert, horiz, state=' '): self.horiz = horiz self.vert = vert self.switched = False if isinstance(grid, Grid): self.grid = grid else: print("Warning : Attribute grid not instance of Grid", file=sys.stderr) self.grid = None if state in (' ', 'R', 'B'): self._state = state else: print("Warning : Attribute state not in ('R', 'B', ' ')", file=sys.stderr) self._state = ' ' def next_horiz(self): if 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: return None return self.grid.square(self.horiz - 1, self.vert) def next_vert(self): if 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: return None return self.grid.square(self.horiz, self.vert - 1) def __eq__(self, other): if other is None or not isinstance(other, Square): return False else: return self.__hash__() == other.__hash__() def __hash__(self): return hash((self.horiz, self.vert, self.grid)) def __repr__(self): return "({}, {}) : '{}'".format(self.horiz, self.vert, self.state) def _get_state(self): """ Allow to get square state. :return: The square state. Either ' ', 'R' or 'B' """ return self._state def _set_state(self, new_state): """ Changes square state. Accepts only 'R', 'B', or ' '. Other values are not accepted and the square is not modified. """ if new_state in ('R', 'B', ' '): self._state = new_state self.switched = True else: print("Error :", new_state, "not in ('R', 'B', ' ').") state = property(_get_state, _set_state) def opposite_state(self): if self.state == 'R': return 'B' elif self.state == 'B': return 'R' else: return ' ' def is_empty(self): return self.state == ' '