Implemented actions

This commit is contained in:
Lukas Wölfer
2019-04-08 19:54:16 +02:00
parent a4d98e415c
commit 208c2c83a4
3 changed files with 144 additions and 37 deletions

View File

@@ -1,6 +1,6 @@
"""Contains board class""" """Contains board class"""
import enum import enum
from typing import Union, Tuple, List from typing import Union, List, Dict, Optional, NewType
from dataclasses import dataclass from dataclasses import dataclass
@@ -34,19 +34,14 @@ class Position(enum.Enum):
Goal = enum.auto() Goal = enum.auto()
class BunkerStatus(enum.Enum): KilledDragon = NewType('KilledDragon', SpecialCard)
"""States a bunker can be in, if it not holding a card"""
Empty = enum.auto()
Dragon = enum.auto()
@dataclass @dataclass
class Board: class Board:
"""Solitaire board""" """Solitaire board"""
field: List[List[Card]] = [] field: List[List[Card]] = [[]] * 8
bunker: Tuple[Union[BunkerStatus, Card], bunker: List[Union[KilledDragon, Optional[Card]]] = [None] * 3
Union[BunkerStatus, Card], goal: Dict[NumberCard.Suit, int] = {NumberCard.Suit.Red: 0,
Union[BunkerStatus, Card]] = (BunkerStatus.Empty, NumberCard.Suit.Green: 0,
BunkerStatus.Empty, BunkerStatus.Empty,) NumberCard.Suit.Black: 0}
goal: List[Tuple[NumberCard.Suit, int]] = []
flowerGone: bool = False flowerGone: bool = False

View File

@@ -5,14 +5,72 @@ import board
@dataclass @dataclass
class MoveAction: class GoalAction:
"""Moving a card from one stack to another""" """Move card from field to goal"""
card: board.Card card: board.NumberCard
source_position: board.Position source_id: int
source_position: board.Position
def apply(self, action_board: board.Board) -> None:
"""Do action"""
if self.source_position == board.Position.Field:
assert action_board.field[self.source_id][-1] == self.card
assert action_board.goal[self.card.suit] + 1 == self.card.number
action_board.field[self.source_id].pop()
action_board.goal[self.card.suit] += 1
elif self.source_position == board.Position.Bunker:
assert action_board.bunker[self.source_id] == self.card
assert action_board.goal[self.card.suit] + 1 == self.card.number
action_board.bunker[self.source_id] = None
action_board.goal[self.card.suit] += 1
else:
raise RuntimeError("Unknown position")
def undo(self, action_board: board.Board) -> None:
"""Undo action"""
assert action_board.goal[self.card.suit] == self.card.number
if self.source_position == board.Position.Field:
action_board.field[self.source_id].append(self.card)
elif self.source_position == board.Position.Bunker:
assert action_board.bunker[self.source_id] is None
action_board.bunker[self.source_id] = self.card
else:
raise RuntimeError("Unknown position")
action_board.goal[self.card.suit] -= 1
@dataclass
class RestoreAction:
"""Move card from bunker to field"""
card: board.Card
source_id: int source_id: int
destination_position: board.Position
destination_id: int destination_id: int
def apply(self, action_board: board.Board) -> None:
"""Do action"""
assert action_board.bunker[self.source_id] == self.card
action_board.bunker[self.source_id] = None
@dataclass
class StoreAction:
"""Move card from field to bunker"""
card: board.Card
source_id: int
destination_id: int
@dataclass
class MoveAction:
"""Moving a card from one field stack to another"""
card: board.Card
source_id: int
destination_id: int
def apply(self, action_board: board.Board) -> None:
"""Do action"""
@dataclass @dataclass
class DragonKillAction: class DragonKillAction:
@@ -21,11 +79,57 @@ class DragonKillAction:
source_stacks: List[Tuple[board.Position, int]] source_stacks: List[Tuple[board.Position, int]]
destination_bunker_id: int destination_bunker_id: int
def apply(self, action_board: board.Board) -> None:
"""Do action"""
assert (action_board.bunker[self.destination_bunker_id] is None or
action_board.bunker[self.destination_bunker_id] == self.dragon)
assert len(self.source_stacks) == 4
for position, index in self.source_stacks:
if position == board.Position.Field:
assert action_board.field[index]
assert action_board.field[index][-1] == self.dragon
action_board.field[index].pop()
elif position == board.Position.Bunker:
assert action_board.bunker[index] == self.dragon
action_board.bunker[index] = None
else:
raise RuntimeError("Can only kill dragons in field and bunker")
action_board.bunker[self.destination_bunker_id] = board.KilledDragon(
self.dragon)
def undo(self, action_board: board.Board) -> None:
"""Undo action"""
assert action_board.bunker[self.destination_bunker_id] == board.KilledDragon(
self.dragon)
assert len(self.source_stacks) == 4
for position, index in self.source_stacks:
if position == board.Position.Field:
action_board.field[index].append(self.dragon)
elif position == board.Position.Bunker:
action_board.bunker[index] = self.dragon
else:
raise RuntimeError("Can only kill dragons in field and bunker")
action_board.bunker[self.destination_bunker_id] = None
@dataclass @dataclass
class HuaKillAction: class HuaKillAction:
"""Remove the flower card""" """Remove the flower card"""
source_field_id: int source_field_id: int
def apply(self, action_board: board.Board) -> None:
"""Do action"""
assert not action_board.flowerGone
assert action_board.field[self.source_field_id] == board.SpecialCard.Hua
action_board.field[self.source_field_id].pop()
action_board.flowerGone = True
Action = Union[MoveAction, DragonKillAction, HuaKillAction] def undo(self, action_board: board.Board) -> None:
"""Undo action"""
assert action_board.flowerGone
action_board.field[self.source_field_id].append(board.SpecialCard.Hua)
action_board.flowerGone = False
Action = Union[MoveAction, DragonKillAction,
HuaKillAction, StoreAction, RestoreAction, GoalAction]

View File

@@ -16,7 +16,7 @@ def possible_dragonkill_actions(
"""Enumerate all possible dragon kills""" """Enumerate all possible dragon kills"""
possible_dragons = [board.SpecialCard.Zhong, possible_dragons = [board.SpecialCard.Zhong,
board.SpecialCard.Fa, board.SpecialCard.Bai] board.SpecialCard.Fa, board.SpecialCard.Bai]
if not any(x == board.BunkerStatus.Empty for x in search_board.bunker): if not any(x is None for x in search_board.bunker):
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.bunker):
@@ -35,7 +35,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 == board.BunkerStatus.Empty][0] i for i, x in enumerate(search_board.bunker) if x is None][0]
source_stacks = [(board.Position.Bunker, i) for i in bunker_dragons] source_stacks = [(board.Position.Bunker, i) for i in bunker_dragons]
source_stacks.extend([(board.Position.Field, i) source_stacks.extend([(board.Position.Field, i)
@@ -45,10 +45,10 @@ def possible_dragonkill_actions(
destination_bunker_id=destination_bunker_id) destination_bunker_id=destination_bunker_id)
def possible_bunkerize_actions(search_board: board.Board) -> Iterator[board_actions.MoveAction]: def possible_bunkerize_actions(search_board: board.Board) -> Iterator[board_actions.StoreAction]:
"""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( open_bunker_list = [i for i, x in enumerate(
search_board.bunker) if x == board.BunkerStatus.Empty] search_board.bunker) if x is None]
if not open_bunker_list: if not open_bunker_list:
return return
@@ -57,14 +57,13 @@ def possible_bunkerize_actions(search_board: board.Board) -> Iterator[board_acti
for index, stack in enumerate(search_board.field): for index, stack in enumerate(search_board.field):
if not stack: if not stack:
continue continue
yield board_actions.MoveAction(card=stack[-1], yield board_actions.StoreAction(card=stack[-1],
source_position=board.Position.Field,
source_id=index, source_id=index,
destination_position=board.Position.Bunker,
destination_id=open_bunker) destination_id=open_bunker)
def possible_debunkerize_actions(search_board: board.Board) -> Iterator[board_actions.MoveAction]: def possible_debunkerize_actions(
search_board: board.Board) -> Iterator[board_actions.RestoreAction]:
"""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 = [(i, x) for i, x in enumerate( bunker_number_cards = [(i, x) for i, x in enumerate(
search_board.bunker) if isinstance(x, board.NumberCard)] search_board.bunker) if isinstance(x, board.NumberCard)]
@@ -78,16 +77,26 @@ def possible_debunkerize_actions(search_board: board.Board) -> Iterator[board_ac
continue continue
if other_stack[-1].number != card.number + 1: if other_stack[-1].number != card.number + 1:
continue continue
yield board_actions.MoveAction(card=card, yield board_actions.RestoreAction(card=card,
source_position=board.Position.Bunker,
source_id=index, source_id=index,
destination_position=board.Position.Field,
destination_id=other_index) destination_id=other_index)
def possible_goal_move_actions(search_board: board.Board) -> Iterator[board_actions.MoveAction]: def possible_goal_move_actions(search_board: board.Board) -> Iterator[board_actions.GoalAction]:
"""Enumerates all possible moves from anywhere to the goal""" """Enumerates all possible moves from anywhere to the goal"""
#TODO field_cards = [(board.Position.Field, index, stack[-1]) for index, stack in enumerate(
search_board.field) if stack if isinstance(stack[-1], board.NumberCard)]
bunker_cards = [(board.Position.Bunker, index, stack)
for index, stack in enumerate(search_board.bunker)
if isinstance(stack, board.NumberCard)]
top_cards = field_cards + bunker_cards
for suit, number in search_board.goal.items():
for source, index, stack in top_cards:
if not (stack.suit == suit and stack.number == number + 1):
continue
yield board_actions.GoalAction(card=stack, source_id=index, source_position=source)
break
def possible_field_move_actions(search_board: board.Board) -> Iterator[board_actions.MoveAction]: def possible_field_move_actions(search_board: board.Board) -> Iterator[board_actions.MoveAction]:
@@ -107,9 +116,7 @@ def possible_field_move_actions(search_board: board.Board) -> Iterator[board_act
if other_stack[-1].number != stack[-1].number + 1: if other_stack[-1].number != stack[-1].number + 1:
continue continue
yield board_actions.MoveAction(card=stack[-1], yield board_actions.MoveAction(card=stack[-1],
source_position=board.Position.Field,
source_id=index, source_id=index,
destination_position=board.Position.Field,
destination_id=other_index) destination_id=other_index)
@@ -117,6 +124,7 @@ def possible_actions(search_board: board.Board) -> Iterator[board_actions.Action
"""Enumerate all possible actions on the current search_board""" """Enumerate all possible actions on the current search_board"""
yield from possible_huakill_action(search_board) yield from possible_huakill_action(search_board)
yield from possible_dragonkill_actions(search_board) yield from possible_dragonkill_actions(search_board)
yield from possible_goal_move_actions(search_board)
yield from possible_debunkerize_actions(search_board) yield from possible_debunkerize_actions(search_board)
yield from possible_field_move_actions(search_board) yield from possible_field_move_actions(search_board)
yield from possible_bunkerize_actions(search_board) yield from possible_bunkerize_actions(search_board)