diff --git a/pigeon_magnet_solver/board.py b/pigeon_magnet_solver/board.py index bc63fc4..e3c084a 100644 --- a/pigeon_magnet_solver/board.py +++ b/pigeon_magnet_solver/board.py @@ -1,5 +1,7 @@ from dataclasses import dataclass +from .helpers import rotate_r + @dataclass(kw_only=True, slots=True) class Board: @@ -25,6 +27,9 @@ class Board: else: return len(self.rows[0]) + def __len__(self) -> int: + return self.height * self.width + def __post_init__(self) -> None: # check char set chars = {c for c in "".join(self.rows)} @@ -37,9 +42,8 @@ class Board: ), "Inconsistent width!" # check buttons - length = self.height * self.width assert all( - button in range(length) + button in range(len(self)) for button in self.buttons ), "Invalid buttons!" @@ -72,16 +76,36 @@ class Board: for column in self.columns ) - def __idx_to_xy(self, index: int) -> tuple[int, int]: - return index % self.width, index // self.width + def __getitem__(self, key: tuple[int, int]) -> str: + row, col = key - def is_clickable(self, index: int) -> bool: - # check index - assert index in self.buttons, f"{index} is not a button!" + if row not in range(self.height) or col not in range(self.width): + return "x" - # check is button - x, y = self.__idx_to_xy(index) - return self.rows[y][x] == "1" + return self.rows[row][col] + + def __setitem__(self, key: tuple[int, int], value: str): + row, col = key + + if row not in range(self.height) or col not in range(self.width): + return + + old_row = self.rows[row] + self.rows[row] = old_row[:col] + value + old_row[col+1:] def click(self, index: int) -> None: - assert self.is_clickable(index), f"{index} is not clickable!" + # check is clickable + row, col = index // self.width, index % self.width + assert self.rows[row][col] == "1", f"{index} is not clickable!" + + nb_rc = [ + (row - 1, col), + (row, col + 1), + (row + 1, col), + (row, col - 1), + ] + + nb_str = "".join(self[*rc] for rc in nb_rc) + + for rc, val in zip(nb_rc, rotate_r(nb_str)): + self[rc] = val diff --git a/pigeon_magnet_solver/main.py b/pigeon_magnet_solver/main.py index cf20f81..3f8982e 100755 --- a/pigeon_magnet_solver/main.py +++ b/pigeon_magnet_solver/main.py @@ -5,7 +5,18 @@ from .board import Board def main() -> None: board = Board.default_puzzle + print(board) + print() + board.click(2) # not a button! + print(board) + print() + + board.click(4) + print(board) + print() + + board.click(5) print(board) diff --git a/tests/test_board.py b/tests/test_board.py index 18d52e7..dcdb9ad 100644 --- a/tests/test_board.py +++ b/tests/test_board.py @@ -1,3 +1,5 @@ +import pytest + from pigeon_magnet_solver.board import Board @@ -11,7 +13,6 @@ def test_default(): assert board.binary_repr == (4, 11, 3), "Wrong binary repr" assert board.solution_class == (1, 3, 2), "Wrong solution class" - assert board.is_clickable(3) is False, "Button 3 should be inactive" - assert board.is_clickable(4) is True, "Button 4 should be active" - assert board.is_clickable(5) is True, "Button 5 should be active" - assert board.is_clickable(7) is False, "Button 7 should be inactive" + for idx in (3, 7): + with pytest.raises(AssertionError): + board.click(idx)