Worked a little more on decoupling

This commit is contained in:
Lukas Wölfer
2020-03-24 14:45:48 +01:00
parent cd1bc39bad
commit 28546cf5e9
5 changed files with 39 additions and 30 deletions

View File

@@ -80,10 +80,10 @@ class Board:
if card is not None and card.suit == suit: if card is not None and card.suit == suit:
return index return index
else: else:
return self.goal.index(None) return self._goal.index(None)
def setGoal(self, suit: NumberCard.Suit, value: int) -> None: def setGoal(self, suit: NumberCard.Suit, value: int) -> None:
assert len(self.goal) == 3 assert len(self._goal) == 3
assert 0 <= value assert 0 <= value
assert value <= 9 assert value <= 9
if value == 0: if value == 0:
@@ -96,15 +96,21 @@ class Board:
def solved(self) -> bool: def solved(self) -> bool:
"""Returns true if the board is solved""" """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 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 return False
if not self._flower_gone: if not self._flower_gone:
return False return False
assert all(not x for x in self._field) assert all(not x for x in self._field)
return True 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 @property
def state_identifier(self) -> int: def state_identifier(self) -> int:
"""Returns a unique identifier to represent the board state""" """Returns a unique identifier to represent the board state"""
@@ -128,7 +134,7 @@ class Board:
assert len(self._goal) == 3 assert len(self._goal) == 3
suit_sequence = list(NumberCard.Suit) suit_sequence = list(NumberCard.Suit)
for card in self.goal: for card in self._goal:
result <<= 5 result <<= 5
if card is None: if card is None:
result |= len(suit_sequence) * 10 result |= len(suit_sequence) * 10

View File

@@ -225,8 +225,8 @@ def parse_goal(image: np.ndarray, conf: Configuration) -> List[Optional[NumberCa
def parse_board(image: np.ndarray, conf: Configuration) -> Board: def parse_board(image: np.ndarray, conf: Configuration) -> Board:
result = 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.flower_gone = parse_hua(image, conf)
result.bunker = parse_bunker(image, conf) result.bunker = parse_bunker(image, conf)
result.goal = parse_goal(image, conf)
return result return result

View File

@@ -129,15 +129,15 @@ class MoveAction(Action):
"""Shift a card from the field id 'source' to field id 'dest'""" """Shift a card from the field id 'source' to field id 'dest'"""
for stack_offset, card in enumerate(self.cards, start=-len(self.cards)): 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.getField()[source] = action_board.getField()[source][: -len(self.cards)]
action_board.field[dest].extend(self.cards) action_board.getField()[dest].extend(self.cards)
def _apply(self, action_board: board.Board) -> None: def _apply(self, action_board: board.Board) -> None:
"""Do action""" """Do action"""
if action_board.field[self.destination_id]: if action_board.getField()[self.destination_id]:
dest_card = action_board.field[self.destination_id][-1] dest_card = action_board.getField()[self.destination_id][-1]
if not all(isinstance(x, board.NumberCard) for x in self.cards): if not all(isinstance(x, board.NumberCard) for x in self.cards):
raise AssertionError() raise AssertionError()
if not isinstance(dest_card, board.NumberCard): if not isinstance(dest_card, board.NumberCard):

View File

@@ -9,7 +9,7 @@ def possible_huakill_action(
search_board: board.Board, search_board: board.Board,
) -> Iterator[board_actions.HuaKillAction]: ) -> Iterator[board_actions.HuaKillAction]:
"""Check if the flowercard can be eliminated""" """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: if stack and stack[-1] == board.SpecialCard.Hua:
yield board_actions.HuaKillAction( yield board_actions.HuaKillAction(
source_field_id=index, source_field_row_index=len(stack) - 1 source_field_id=index, source_field_row_index=len(stack) - 1
@@ -25,17 +25,17 @@ def possible_dragonkill_actions(
board.SpecialCard.Fa, board.SpecialCard.Fa,
board.SpecialCard.Bai, 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 = [] new_possible_dragons = []
for dragon in 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) new_possible_dragons.append(dragon)
possible_dragons = new_possible_dragons possible_dragons = new_possible_dragons
for dragon in 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 = [ 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: if len(bunker_dragons) + len(field_dragons) != 4:
continue continue
@@ -44,7 +44,7 @@ def possible_dragonkill_actions(
destination_bunker_id = bunker_dragons[0] destination_bunker_id = bunker_dragons[0]
else: else:
destination_bunker_id = [ 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] ][0]
source_stacks = [(board.Position.Bunker, i) for i in bunker_dragons] source_stacks = [(board.Position.Bunker, i) for i in bunker_dragons]
@@ -61,13 +61,13 @@ def possible_bunkerize_actions(
search_board: board.Board, search_board: board.Board,
) -> Iterator[board_actions.BunkerizeAction]: ) -> Iterator[board_actions.BunkerizeAction]:
"""Enumerates all possible card moves from the field to the bunker""" """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: if not open_bunker_list:
return return
open_bunker = open_bunker_list[0] 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: if not stack:
continue continue
yield board_actions.BunkerizeAction( yield board_actions.BunkerizeAction(
@@ -85,11 +85,11 @@ def possible_debunkerize_actions(
"""Enumerates all possible card moves from the bunker to the field""" """Enumerates all possible card moves from the bunker to the field"""
bunker_number_cards = [ bunker_number_cards = [
(i, x) (i, x)
for i, x in enumerate(search_board.bunker) for i, x in enumerate(search_board.getBunker())
if isinstance(x, board.NumberCard) if isinstance(x, board.NumberCard)
] ]
for index, card in bunker_number_cards: 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: if not other_stack:
continue continue
if not isinstance(other_stack[-1], board.NumberCard): 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""" """Enumerates all possible moves from anywhere to the goal"""
field_cards = [ field_cards = [
(board.Position.Field, index, stack[-1]) (board.Position.Field, index, stack[-1])
for index, stack in enumerate(search_board.field) for index, stack in enumerate(search_board.getField())
if stack if stack
] ]
bunker_cards = [ bunker_cards = [
(board.Position.Bunker, index, card) (board.Position.Bunker, index, card)
for index, card in enumerate(search_board.bunker) for index, card in enumerate(search_board.getBunker())
] ]
top_cards = [ top_cards = [
x for x in field_cards + bunker_cards if isinstance(x[2], board.NumberCard) x for x in field_cards + bunker_cards if isinstance(x[2], board.NumberCard)
@@ -129,6 +129,7 @@ def possible_goal_move_actions(
result = [] result = []
for source, index, card in top_cards: for source, index, card in top_cards:
assert isinstance(card, board.NumberCard)
obvious = all( obvious = all(
search_board.getGoal(other_suit) >= card.number - 2 search_board.getGoal(other_suit) >= card.number - 2
for other_suit in set(board.NumberCard.Suit) - {card.suit} for other_suit in set(board.NumberCard.Suit) - {card.suit}
@@ -137,7 +138,7 @@ def possible_goal_move_actions(
board_actions.GoalAction( board_actions.GoalAction(
card=card, card=card,
source_id=index, 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 if source == board.Position.Field
else None, else None,
source_position=source, 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]]: def _get_cardstacks(search_board: board.Board) -> List[List[board.Card]]:
"""Returns all cards on one stack that can be moved at once""" """Returns all cards on one stack that can be moved at once"""
result: List[List[board.Card]] = [] result: List[List[board.Card]] = []
for stack in search_board.field: for stack in search_board.getField():
result.append([]) result.append([])
if not stack: if not stack:
continue continue
@@ -194,13 +195,13 @@ def possible_field_move_actions(
) )
for source_index, source_substack in substacks: 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: if source_index == destination_index:
continue continue
if destination_stack: if destination_stack:
if not _can_stack(destination_stack[-1], source_substack[0]): if not _can_stack(destination_stack[-1], source_substack[0]):
continue continue
elif len(source_substack) == len(search_board.field[source_index]): elif len(source_substack) == len(search_board.getField()[source_index]):
continue continue
elif first_empty_field_id == -1: elif first_empty_field_id == -1:
first_empty_field_id = destination_index first_empty_field_id = destination_index
@@ -209,7 +210,7 @@ def possible_field_move_actions(
yield board_actions.MoveAction( yield board_actions.MoveAction(
cards=source_substack, cards=source_substack,
source_id=source_index, 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), - len(source_substack),
destination_id=destination_index, destination_id=destination_index,
destination_row_index=len(destination_stack), destination_row_index=len(destination_stack),

View File

@@ -23,7 +23,9 @@ class CardDetectionTest(unittest.TestCase):
loaded_config = configuration.load("test_config.zip") loaded_config = configuration.load("test_config.zip")
my_board = board_parser.parse_board(image, loaded_config) 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) self.assertListEqual(correct_row, my_row)
def test_hua_detection(self) -> None: def test_hua_detection(self) -> None: