From 28546cf5e9ab56763fafd1fa34030df86f0c28bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20W=C3=B6lfer?= Date: Tue, 24 Mar 2020 14:45:48 +0100 Subject: [PATCH] Worked a little more on decoupling --- shenzhen_solitaire/board.py | 16 ++++++--- .../card_detection/board_parser.py | 4 +-- shenzhen_solitaire/solver/board_actions.py | 10 +++--- .../solver/board_possibilities.py | 35 ++++++++++--------- test/test_cv.py | 4 ++- 5 files changed, 39 insertions(+), 30 deletions(-) diff --git a/shenzhen_solitaire/board.py b/shenzhen_solitaire/board.py index e55dee3..804ced1 100644 --- a/shenzhen_solitaire/board.py +++ b/shenzhen_solitaire/board.py @@ -80,10 +80,10 @@ class Board: if card is not None and card.suit == suit: return index else: - return self.goal.index(None) + return self._goal.index(None) def setGoal(self, suit: NumberCard.Suit, value: int) -> None: - assert len(self.goal) == 3 + assert len(self._goal) == 3 assert 0 <= value assert value <= 9 if value == 0: @@ -96,15 +96,21 @@ class Board: def solved(self) -> bool: """Returns true if the board is solved""" - if any(x.number != 9 for x in self.goal if x is not None): + if any(x.number != 9 for x in self._goal if x is not None): return False - if any(not isinstance(x, tuple) for x in self.bunker): + if any(not isinstance(x, tuple) for x in self._bunker): return False if not self._flower_gone: return False assert all(not x for x in self._field) return True + def getField(self) -> List[List[Card]]: + return self._field + + def getBunker(self) -> List[Union[Tuple[SpecialCard, int], Optional[Card]]]: + return self._bunker + @property def state_identifier(self) -> int: """Returns a unique identifier to represent the board state""" @@ -128,7 +134,7 @@ class Board: assert len(self._goal) == 3 suit_sequence = list(NumberCard.Suit) - for card in self.goal: + for card in self._goal: result <<= 5 if card is None: result |= len(suit_sequence) * 10 diff --git a/shenzhen_solitaire/card_detection/board_parser.py b/shenzhen_solitaire/card_detection/board_parser.py index b859637..36df671 100644 --- a/shenzhen_solitaire/card_detection/board_parser.py +++ b/shenzhen_solitaire/card_detection/board_parser.py @@ -225,8 +225,8 @@ def parse_goal(image: np.ndarray, conf: Configuration) -> List[Optional[NumberCa def parse_board(image: np.ndarray, conf: Configuration) -> Board: result = Board() - result.field = parse_field(image, conf) + result.setField(parse_field(image, conf)) + result.setGoal(parse_goal(image, conf)) result.flower_gone = parse_hua(image, conf) result.bunker = parse_bunker(image, conf) - result.goal = parse_goal(image, conf) return result diff --git a/shenzhen_solitaire/solver/board_actions.py b/shenzhen_solitaire/solver/board_actions.py index d6e0e5b..39ac10c 100644 --- a/shenzhen_solitaire/solver/board_actions.py +++ b/shenzhen_solitaire/solver/board_actions.py @@ -129,15 +129,15 @@ class MoveAction(Action): """Shift a card from the field id 'source' to field id 'dest'""" for stack_offset, card in enumerate(self.cards, start=-len(self.cards)): - assert action_board.field[source][stack_offset] == card + assert action_board.getField()[source][stack_offset] == card - action_board.field[source] = action_board.field[source][: -len(self.cards)] - action_board.field[dest].extend(self.cards) + action_board.getField()[source] = action_board.getField()[source][: -len(self.cards)] + action_board.getField()[dest].extend(self.cards) def _apply(self, action_board: board.Board) -> None: """Do action""" - if action_board.field[self.destination_id]: - dest_card = action_board.field[self.destination_id][-1] + if action_board.getField()[self.destination_id]: + dest_card = action_board.getField()[self.destination_id][-1] if not all(isinstance(x, board.NumberCard) for x in self.cards): raise AssertionError() if not isinstance(dest_card, board.NumberCard): diff --git a/shenzhen_solitaire/solver/board_possibilities.py b/shenzhen_solitaire/solver/board_possibilities.py index 0e838ea..8f2efbb 100644 --- a/shenzhen_solitaire/solver/board_possibilities.py +++ b/shenzhen_solitaire/solver/board_possibilities.py @@ -9,7 +9,7 @@ def possible_huakill_action( search_board: board.Board, ) -> Iterator[board_actions.HuaKillAction]: """Check if the flowercard can be eliminated""" - for index, stack in enumerate(search_board.field): + for index, stack in enumerate(search_board.getField()): if stack and stack[-1] == board.SpecialCard.Hua: yield board_actions.HuaKillAction( source_field_id=index, source_field_row_index=len(stack) - 1 @@ -25,17 +25,17 @@ def possible_dragonkill_actions( board.SpecialCard.Fa, board.SpecialCard.Bai, ] - if not any(x is None for x in search_board.bunker): + if not any(x is None for x in search_board.getBunker()): new_possible_dragons = [] for dragon in possible_dragons: - if any(x == dragon for x in search_board.bunker): + if any(x == dragon for x in search_board.getBunker()): new_possible_dragons.append(dragon) possible_dragons = new_possible_dragons for dragon in possible_dragons: - bunker_dragons = [i for i, d in enumerate(search_board.bunker) if d == dragon] + bunker_dragons = [i for i, d in enumerate(search_board.getBunker()) if d == dragon] field_dragons = [ - i for i, f in enumerate(search_board.field) if f if f[-1] == dragon + i for i, f in enumerate(search_board.getField()) if f if f[-1] == dragon ] if len(bunker_dragons) + len(field_dragons) != 4: continue @@ -44,7 +44,7 @@ def possible_dragonkill_actions( destination_bunker_id = bunker_dragons[0] else: destination_bunker_id = [ - i for i, x in enumerate(search_board.bunker) if x is None + i for i, x in enumerate(search_board.getBunker()) if x is None ][0] source_stacks = [(board.Position.Bunker, i) for i in bunker_dragons] @@ -61,13 +61,13 @@ def possible_bunkerize_actions( search_board: board.Board, ) -> Iterator[board_actions.BunkerizeAction]: """Enumerates all possible card moves from the field to the bunker""" - open_bunker_list = [i for i, x in enumerate(search_board.bunker) if x is None] + open_bunker_list = [i for i, x in enumerate(search_board.getBunker()) if x is None] if not open_bunker_list: return open_bunker = open_bunker_list[0] - for index, stack in enumerate(search_board.field): + for index, stack in enumerate(search_board.getField()): if not stack: continue yield board_actions.BunkerizeAction( @@ -85,11 +85,11 @@ def possible_debunkerize_actions( """Enumerates all possible card moves from the bunker to the field""" bunker_number_cards = [ (i, x) - for i, x in enumerate(search_board.bunker) + for i, x in enumerate(search_board.getBunker()) if isinstance(x, board.NumberCard) ] for index, card in bunker_number_cards: - for other_index, other_stack in enumerate(search_board.field): + for other_index, other_stack in enumerate(search_board.getField()): if not other_stack: continue if not isinstance(other_stack[-1], board.NumberCard): @@ -113,12 +113,12 @@ def possible_goal_move_actions( """Enumerates all possible moves from anywhere to the goal""" field_cards = [ (board.Position.Field, index, stack[-1]) - for index, stack in enumerate(search_board.field) + for index, stack in enumerate(search_board.getField()) if stack ] bunker_cards = [ (board.Position.Bunker, index, card) - for index, card in enumerate(search_board.bunker) + for index, card in enumerate(search_board.getBunker()) ] top_cards = [ x for x in field_cards + bunker_cards if isinstance(x[2], board.NumberCard) @@ -129,6 +129,7 @@ def possible_goal_move_actions( result = [] for source, index, card in top_cards: + assert isinstance(card, board.NumberCard) obvious = all( search_board.getGoal(other_suit) >= card.number - 2 for other_suit in set(board.NumberCard.Suit) - {card.suit} @@ -137,7 +138,7 @@ def possible_goal_move_actions( board_actions.GoalAction( card=card, source_id=index, - source_row_index=len(search_board.field[index]) - 1 + source_row_index=len(search_board.getField()[index]) - 1 if source == board.Position.Field else None, source_position=source, @@ -164,7 +165,7 @@ def _can_stack(bottom: board.Card, top: board.Card) -> bool: def _get_cardstacks(search_board: board.Board) -> List[List[board.Card]]: """Returns all cards on one stack that can be moved at once""" result: List[List[board.Card]] = [] - for stack in search_board.field: + for stack in search_board.getField(): result.append([]) if not stack: continue @@ -194,13 +195,13 @@ def possible_field_move_actions( ) for source_index, source_substack in substacks: - for destination_index, destination_stack in enumerate(search_board.field): + for destination_index, destination_stack in enumerate(search_board.getField()): if source_index == destination_index: continue if destination_stack: if not _can_stack(destination_stack[-1], source_substack[0]): continue - elif len(source_substack) == len(search_board.field[source_index]): + elif len(source_substack) == len(search_board.getField()[source_index]): continue elif first_empty_field_id == -1: first_empty_field_id = destination_index @@ -209,7 +210,7 @@ def possible_field_move_actions( yield board_actions.MoveAction( cards=source_substack, source_id=source_index, - source_row_index=len(search_board.field[source_index]) + source_row_index=len(search_board.getField()[source_index]) - len(source_substack), destination_id=destination_index, destination_row_index=len(destination_stack), diff --git a/test/test_cv.py b/test/test_cv.py index 74930bb..7aaf71e 100644 --- a/test/test_cv.py +++ b/test/test_cv.py @@ -23,7 +23,9 @@ class CardDetectionTest(unittest.TestCase): loaded_config = configuration.load("test_config.zip") my_board = board_parser.parse_board(image, loaded_config) - for correct_row, my_row in zip(boards.B20190809172206_1.field, my_board.field): + for correct_row, my_row in zip(boards.B20190809172206_1.getField(), my_board.getField()): + print(correct_row) + print(my_row) self.assertListEqual(correct_row, my_row) def test_hua_detection(self) -> None: