def check(self, played_on=False, has_cards=None, is_combination=False, not_pass=False, is_bomb=False): """ Checks the following properties when the argument is not False: :param played_on: Combination, whether the action can be played on the combination :param has_cards: Player, whether the player has the cards to play this action :param not_pass: bool, whether the action can be pass or not. (not_pass = True, -> action must not be pass action) :param is_bomb: bool, whether the action must be a bomb or not. :return: True if all checks succeed, False otherwise """ from .tichuplayers import TichuPlayer if isinstance(played_on, Combination): check_true(self.can_be_played_on_combination(played_on), ex=IllegalActionException, msg=f"{self} can't be played on {played_on}") if isinstance(has_cards, TichuPlayer): check_true(self.does_player_have_cards(has_cards), ex=IllegalActionException, msg=f"{has_cards} does not have the cards for {self}") if not_pass: check_true(not isinstance(self, PassAction), ex=IllegalActionException, msg=f"Action must not be Pass, but was {self}") if is_combination: check_true(isinstance(self, CombinationAction), ex=IllegalActionException, msg=f"Action must be a CombinationAction, but was {self}") if is_bomb: check_true(self.is_bomb(), ex=IllegalActionException, msg=f"Action must be Bomb, but was {self}") return True
def _announce_tichu(self, player_pos): check_true( player_pos not in self._announced_grand_tichus, ex=IllegalActionException, msg= f"Player({player_pos}) can't announce normal Tichu when already announced grand Tichu." ) self._announced_tichus.add(player_pos)
def __init__(self, straight): check_isinstance(straight, Straight) check_true(len({ c.suit for c in straight }) == 1) # only one suit (takes also care of the phoenix) super().__init__(straight.cards) self._height = straight.height + 1000 # 1000 to make sure it is higher than any other non straightbomb
def from_cards(cls, cards): check_param(len(cards) >= 4 and len(cards) % 2 == 0) check_param(Card.PHOENIX not in cards, "can't make pairstep from cards when Phoenix is present") pairs = [] for cs in ImmutableCards(cards).value_dict().values(): if len(cs) == 2: pairs.append(Pair(*cs)) check_true(len(cs) == 0, ex=ValueError, msg="Not a pairstep") return cls(pairs)
def __lt__(self, other): if isinstance(other, Bomb): return True check_isinstance(other, Single) check_true(self.card is not Card.DOG and other.card is not Card.DOG, ex=TypeError, msg="Can't compare") # dog can't be compared if self.card is Card.DRAGON: return False # dragon is the highest single card if other.is_phoenix() and other.height == Card.PHOENIX.card_height: return True # if the phoenix is on the right hand side of '<' and its value has not been changed, return True return self.height < other.height
def swap_cards(self): """ Called by the the tichu manager to ask for the 3 cards to be swapped :return a set (of length 3) of SwapCardAction instance. """ self._update_agent_handcards() swap_cards = self._agent.swap_cards() check_true(len(swap_cards) == 3 and len({sw.player_pos for sw in swap_cards}) == 1 and next(iter(swap_cards)).player_pos == self._position and len({sw.to for sw in swap_cards}) == 3, ex=IllegalActionException, msg="swap card actions were not correct") for sw in swap_cards: self._hand_cards.remove(sw.card) self._update_agent_handcards() return swap_cards
def from_cards(cls, cards): check_param(len(set(cards)) == 5) # 5 different cards check_param(Card.PHOENIX not in cards, "can't make from cards when Phoenix is present") pair = None trio = None for cs in ImmutableCards(cards).value_dict().values(): if len(cs) == 2: pair = Pair(*cs) elif len(cs) == 3: trio = Trio(*cs) else: check_true( len(cs) == 0, ex=ValueError, msg="there is no fullhouse in the cards (cards: {})". format(cards) ) # if this fails, then there is no fullhouse in the cards return cls(pair, trio)
def play_combination(self, game_history, wish): """ Called by the the tichu manager to request a move. :param game_history: The history of the tichu game so far. :param wish: The CardValue beeing wished, None if no wish is present :return: pass, or the combination the players wants to play as CombinationAction or PassAction. """ assert len(self._hand_cards) > 0 action = self._agent.play_combination(wish=wish, round_history=game_history.current_round.build()) check_isinstance(action, (CombinationAction, PassAction)) check_true(action.player_pos == self._position) with ignored(AttributeError, ValueError): action.combination.set_phoenix_height(game_history.current_round.last_combination.height + 0.5) action.check(played_on=game_history.current_round.last_combination, has_cards=self) TichuPlayer._check_wish(game_history.current_round.last_combination, action, self.hand_cards, wish) if isinstance(action, CombinationAction): self._hand_cards.remove_all(action.combination.cards) self._update_agent_handcards() return action
def _add_swap_actions(self, event): self._swap_actions.add(event) check_true( len({(sw.player_pos, sw.to) for sw in self._swap_actions}) == len(self._swap_actions))
def __init__(self, cards): check_param(len(cards) > 0, cards) check_all_isinstance(cards, Card) self._cards = ImmutableCards(cards) check_true(len(self._cards) == len(cards))
def __lt__(self, other): if isinstance(other, Bomb): return True check_isinstance(other, Straight) check_true(len(other) == len(self), ex=TypeError, msg="Can't compare") return self.height < other.height