From 41b14087e29d669800e88d7270532bb249c3fd55 Mon Sep 17 00:00:00 2001 From: Gabriel Augendre Date: Wed, 31 Dec 2014 15:48:26 +0100 Subject: [PATCH] prevents three in a row + better implementation from far + test grid creation --- sources/Grid.py | 22 ----- sources/Square.py | 182 ---------------------------------------- sources/grid.py | 194 +++++++++++++++++++++++++++++++++++++++++++ sources/main.py | 88 ++++++++++++++++++++ sources/test_grid.py | 83 ++++++++++++++++++ 5 files changed, 365 insertions(+), 204 deletions(-) delete mode 100644 sources/Grid.py delete mode 100644 sources/Square.py create mode 100644 sources/grid.py create mode 100644 sources/main.py create mode 100644 sources/test_grid.py diff --git a/sources/Grid.py b/sources/Grid.py deleted file mode 100644 index 7ca9a71..0000000 --- a/sources/Grid.py +++ /dev/null @@ -1,22 +0,0 @@ -# 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' - - -class Grid: - def __init__(self): - pass \ No newline at end of file diff --git a/sources/Square.py b/sources/Square.py deleted file mode 100644 index 32a0e22..0000000 --- a/sources/Square.py +++ /dev/null @@ -1,182 +0,0 @@ -# 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' - - -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, horiz, vert): - self.horiz = horiz - self.vert = vert - - def next_horiz(self, width): - if self.horiz == width - 1: - return None - return Square(self.horiz + 1, self.vert) - - def prev_horiz(self): - if self.horiz == 0: - return None - return Square(self.horiz - 1, self.vert) - - def next_vert(self, height): - if self.vert == height - 1: - return None - return Square(self.horiz, self.vert + 1) - - def prev_vert(self): - if self.vert == 0: - return None - return Square(self.horiz, self.vert - 1) - - def __eq__(self, other): - if other is None or not isinstance(other, Square): - return False - else: - return self.vert == other.vert and self.horiz == other.horiz - - def __hash__(self): - return hash((self.horiz, self.vert)) - - -def solve(grid): - y = 0 - while y < len(grid): - x = 0 - while x < len(grid[0]): - if grid[x][y] == ' ': - v_prev_x, v_prev_y = prev_vert(x, y) - v_p_prev_x, v_p_prev_y = prev_vert(v_prev_x, v_prev_y) - v_next_x, v_next_y = next_vert(x, y, len(grid)) - v_n_next_x, v_n_next_y = next_vert(v_next_x, v_next_y, - len(grid)) - - h_prev_x, h_prev_y = prev_horiz(x, y) - h_p_prev_x, h_p_prev_y = prev_horiz(h_prev_x, h_prev_y) - h_next_x, h_next_y = next_horiz(x, y, len(grid[0])) - h_n_next_x, h_n_next_y = next_horiz(h_next_x, h_next_y, - len(grid[0])) - - be_blue = (exists(v_prev_x, v_prev_y) and - exists(v_p_prev_x, v_p_prev_y) and - grid[v_prev_x][v_prev_y] == 'R' and - grid[v_p_prev_x][v_p_prev_y] == 'R') or \ - (exists(v_next_x, v_next_y) and - exists(v_n_next_x, v_n_next_y) and - grid[v_next_x][v_next_y] == 'R' and - grid[v_n_next_x][v_n_next_y] == 'R') or \ - (exists(h_prev_x, h_prev_y >= 0) and - exists(h_p_prev_x, h_p_prev_y) and - grid[h_prev_x][h_prev_y] == 'R' and - grid[h_p_prev_x][h_p_prev_y] == 'R') or \ - (exists(h_next_x, h_next_y) and - exists(h_n_next_y, h_n_next_y) and - grid[h_next_x][h_next_y] == 'R' and - grid[h_n_next_x][h_n_next_y] == 'R') or \ - (exists(h_prev_x, h_prev_y) and - exists(h_next_x, h_next_y) and - grid[h_prev_x][h_prev_y] == 'R' and - grid[h_next_x][h_next_y] == 'R') or \ - (exists(v_prev_x, v_prev_y) and - exists(v_next_x, v_next_y) and - grid[v_prev_x][v_prev_y] == 'R' and - grid[v_next_x][v_next_y] == 'R') - - be_red = (v_prev_x >= 0 and v_prev_y >= 0 and - v_p_prev_x >= 0 and v_p_prev_y >= 0 and - grid[v_prev_x][v_prev_y] == 'B' and - grid[v_p_prev_x][v_p_prev_y] == 'B') or \ - (v_next_x >= 0 and v_next_y >= 0 and - v_n_next_x >= 0 and v_n_next_y >= 0 and - grid[v_next_x][v_next_y] == 'B' and - grid[v_n_next_x][v_n_next_y] == 'B') or \ - (h_prev_x >= 0 and h_prev_y >= 0 and - h_p_prev_x >= 0 and h_p_prev_y >= 0 and - grid[h_prev_x][h_prev_y] == 'B' and - grid[h_p_prev_x][h_p_prev_y] == 'B') or \ - (h_next_x >= 0 and h_next_y >= 0 and - h_n_next_y >= 0 and h_n_next_y >= 0 and - grid[h_next_x][h_next_y] == 'B' and - grid[h_n_next_x][h_n_next_y] == 'B') or \ - (exists(h_prev_x, h_prev_y) and - exists(h_next_x, h_next_y) and - grid[h_prev_x][h_prev_y] == 'B' and - grid[h_next_x][h_next_y] == 'B') or \ - (exists(v_prev_x, v_prev_y) and - exists(v_next_x, v_next_y) and - grid[v_prev_x][v_prev_y] == 'B' and - grid[v_next_x][v_next_y] == 'B') - - if be_blue: - grid[x][y] = 'B' - elif be_red: - grid[x][y] = 'R' - x += 1 - y += 1 - - -def exists(a, b): - return a >= 0 and b >= 0 - - -def next_horiz(horiz, vert, width): - if horiz == width - 1: - return -1, -1 - return horiz + 1, vert - - -def prev_horiz(horiz, vert): - if horiz == 0: - return -1, -1 - return horiz - 1, vert - - -def next_vert(horiz, vert, height): - if vert == height - 1: - return -1, -1 - return horiz, vert + 1 - - -def prev_vert(horiz, vert): - if vert == 0: - return -1, -1 - return horiz, vert - 1 - - -def print_grid(grid): - for line in grid: - for square in line: - if square == ' ': - square = '_' - print(square, end=' ') - print('') - - -if __name__ == "__main__": - grid = [['B', ' ', ' ', ' '], - ['B', 'B', ' ', ' '], - [' ', ' ', ' ', ' '], - [' ', 'B', ' ', 'B']] - print_grid(grid) - solve(grid) - print("") - print_grid(grid) \ No newline at end of file diff --git a/sources/grid.py b/sources/grid.py new file mode 100644 index 0000000..f4dbb87 --- /dev/null +++ b/sources/grid.py @@ -0,0 +1,194 @@ +# 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 == ' ' + diff --git a/sources/main.py b/sources/main.py new file mode 100644 index 0000000..a6dc28b --- /dev/null +++ b/sources/main.py @@ -0,0 +1,88 @@ +__author__ = 'gaugendre' + +from grid import Grid +# def solve(grid): +# y = 0 +# while y < len(grid): +# x = 0 +# while x < len(grid[0]): +# if grid[x][y] == ' ': +# v_prev_x, v_prev_y = prev_vert(x, y) +# v_p_prev_x, v_p_prev_y = prev_vert(v_prev_x, v_prev_y) +# v_next_x, v_next_y = next_vert(x, y, len(grid)) +# v_n_next_x, v_n_next_y = next_vert(v_next_x, v_next_y, +# len(grid)) +# +# h_prev_x, h_prev_y = prev_horiz(x, y) +# h_p_prev_x, h_p_prev_y = prev_horiz(h_prev_x, h_prev_y) +# h_next_x, h_next_y = next_horiz(x, y, len(grid[0])) +# h_n_next_x, h_n_next_y = next_horiz(h_next_x, h_next_y, +# len(grid[0])) +# +# be_blue = (exists(v_prev_x, v_prev_y) and +# exists(v_p_prev_x, v_p_prev_y) and +# grid[v_prev_x][v_prev_y] == 'R' and +# grid[v_p_prev_x][v_p_prev_y] == 'R') or \ +# (exists(v_next_x, v_next_y) and +# exists(v_n_next_x, v_n_next_y) and +# grid[v_next_x][v_next_y] == 'R' and +# grid[v_n_next_x][v_n_next_y] == 'R') or \ +# (exists(h_prev_x, h_prev_y) and +# exists(h_p_prev_x, h_p_prev_y) and +# grid[h_prev_x][h_prev_y] == 'R' and +# grid[h_p_prev_x][h_p_prev_y] == 'R') or \ +# (exists(h_next_x, h_next_y) and +# exists(h_n_next_y, h_n_next_y) and +# grid[h_next_x][h_next_y] == 'R' and +# grid[h_n_next_x][h_n_next_y] == 'R') or \ +# (exists(h_prev_x, h_prev_y) and +# exists(h_next_x, h_next_y) and +# grid[h_prev_x][h_prev_y] == 'R' and +# grid[h_next_x][h_next_y] == 'R') or \ +# (exists(v_prev_x, v_prev_y) and +# exists(v_next_x, v_next_y) and +# grid[v_prev_x][v_prev_y] == 'R' and +# grid[v_next_x][v_next_y] == 'R') +# +# be_red = (v_prev_x >= 0 and v_prev_y >= 0 and +# v_p_prev_x >= 0 and v_p_prev_y >= 0 and +# grid[v_prev_x][v_prev_y] == 'B' and +# grid[v_p_prev_x][v_p_prev_y] == 'B') or \ +# (v_next_x >= 0 and v_next_y >= 0 and +# v_n_next_x >= 0 and v_n_next_y >= 0 and +# grid[v_next_x][v_next_y] == 'B' and +# grid[v_n_next_x][v_n_next_y] == 'B') or \ +# (h_prev_x >= 0 and h_prev_y >= 0 and +# h_p_prev_x >= 0 and h_p_prev_y >= 0 and +# grid[h_prev_x][h_prev_y] == 'B' and +# grid[h_p_prev_x][h_p_prev_y] == 'B') or \ +# (h_next_x >= 0 and h_next_y >= 0 and +# h_n_next_y >= 0 and h_n_next_y >= 0 and +# grid[h_next_x][h_next_y] == 'B' and +# grid[h_n_next_x][h_n_next_y] == 'B') or \ +# (exists(h_prev_x, h_prev_y) and +# exists(h_next_x, h_next_y) and +# grid[h_prev_x][h_prev_y] == 'B' and +# grid[h_next_x][h_next_y] == 'B') or \ +# (exists(v_prev_x, v_prev_y) and +# exists(v_next_x, v_next_y) and +# grid[v_prev_x][v_prev_y] == 'B' and +# grid[v_next_x][v_next_y] == 'B') +# +# if be_blue: +# grid[x][y] = 'B' +# elif be_red: +# grid[x][y] = 'R' +# x += 1 +# y += 1 + + +if __name__ == "__main__": + array = [['B', ' ', ' ', ' '], + ['B', 'B', ' ', ' '], + [' ', ' ', ' ', ' '], + [' ', 'B', ' ', 'B']] + grid = Grid(len(array), array) + print(grid) + grid.solve() + print(grid) \ No newline at end of file diff --git a/sources/test_grid.py b/sources/test_grid.py new file mode 100644 index 0000000..eb6f1d0 --- /dev/null +++ b/sources/test_grid.py @@ -0,0 +1,83 @@ +# 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 pytest +from grid import * + +@pytest.fixture +def array(): + return [['B', ' ', ' ', ' '], + ['B', 'B', ' ', ' '], + [' ', ' ', ' ', ' '], + [' ', 'B', ' ', 'B']] + + +@pytest.fixture +def full_grid(array): + return Grid(len(array), array) + + +@pytest.fixture +def empty_grid(array): + return Grid(len(array)) + + +def test_without_state(empty_grid): + for line in empty_grid.squares: + for square in line: + assert square.state == ' ' + + +def test_with_state(full_grid, array): + i = 0 + for line in full_grid.squares: + j = 0 + for square in line: + assert square.state == array[i][j] + j += 1 + i += 1 + +# @pytest.fixture() +# def matrix(): +# return [[0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1], +# [1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1], +# [1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1], +# [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], +# [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], +# [0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0], +# [1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0], +# [0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0]] +# +# +# def test_out_of_zone(matrix): +# beginning = Pixel(0, 0) +# assert region_growing(matrix, beginning) is None +# +# +# def test_in_zone(matrix): +# beginning = Pixel(1, 1) +# assert region_growing(matrix, beginning) == {Pixel(1, 0), Pixel(1, 1), +# Pixel(1, 2), Pixel(2, 0), +# Pixel(2, 1)} +# +# +# def test_out_of_matrix(matrix): +# beginning = Pixel(15, 12) +# assert region_growing(matrix, beginning) is None + +