def step(self, dog: List[Card]) -> Tuple[DogPhaseObservation, float, bool, None]: if type(dog) != list: raise FrenchTarotException("Wrong type for 'action'") if len(set(dog)) != len(dog): raise FrenchTarotException("Duplicated cards in dog") if np.any(["king" in card.value for card in dog]): raise FrenchTarotException("There should be no king in dog") if np.any([is_oudler(card) for card in dog]): raise FrenchTarotException("There should be no oudler in dog") if np.any([card not in self.hand for card in dog]): raise FrenchTarotException( "Card in dog not in taking player's hand") if len(dog) != self._n_cards_in_dog: raise FrenchTarotException("Wrong number of cards in dog") n_trumps_in_dog = np.sum(["trump" in card.value for card in dog]) if n_trumps_in_dog > 0: n_trumps_in_taking_player_hand = count_trumps_and_excuse(self.hand) n_kings_in_taking_player_hand = np.sum( ["king" in card.value for card in self.hand]) allowed_trumps_in_dog = self._n_cards_in_dog - ( len(self.hand) - n_trumps_in_taking_player_hand - n_kings_in_taking_player_hand) if n_trumps_in_dog != allowed_trumps_in_dog: raise FrenchTarotException( "There should be no more trumps in dog than needed") index_to_keep_in_hand = [card not in dog for card in self.hand] self.hand = list(np.array(self.hand)[index_to_keep_in_hand]) reward = compute_card_set_points(dog) self.new_dog = dog done = True info = None return self.observation, reward, done, info
def test_play_excuse_first(): environment = setup_environment_for_card_phase()[0] environment.step(Card.EXCUSE) environment.step(Card.HEART_KING) environment.step(Card.HEART_4) observation, reward, done, _ = environment.step(Card.HEART_2) expected_values = [ Card.EXCUSE, Card.HEART_KING, Card.HEART_4, Card.HEART_2 ] assert reward[-1] == compute_card_set_points( expected_values) # last player's team won this round assert not done
def test_play_complete_round_valid_last_player_team_wins(): environment = setup_environment_for_card_phase()[0] environment.step(Card.HEART_1) environment.step(Card.HEART_KING) environment.step(Card.HEART_4) observation, reward, done, _ = environment.step(Card.HEART_2) expected_reward = compute_card_set_points( [Card.HEART_1, Card.HEART_KING, Card.HEART_4, Card.HEART_2]) assert reward[0] == 0 assert reward[1] == expected_reward assert reward[2] == expected_reward assert reward[3] == expected_reward assert not done
def test_play_complete_round_valid_last_player_team_loses(): environment = setup_environment_for_card_phase(taker=1)[0] environment.step(Card.HEART_1) environment.step(Card.HEART_KING) environment.step(Card.HEART_4) observation, reward, done, _ = environment.step(Card.HEART_2) expected_values = [ Card.HEART_KING, Card.HEART_4, Card.HEART_2, Card.HEART_1 ] assert reward[0] == compute_card_set_points(expected_values) assert reward[1] == 0 assert reward[2] == 0 assert reward[3] == 0 assert not done
def _solve_round(self) -> List[float]: starting_player = self.next_player winning_card_index = self._get_winning_card_index( self._played_cards_in_round) play_order = np.arange( starting_player, starting_player + self.n_players) % self.n_players winner = play_order[winning_card_index] reward_for_winner = compute_card_set_points( self._played_cards_in_round) rewards = [] if winner == 0: # if winner is taking player rewards.append(reward_for_winner) rewards.extend([0] * (self.n_players - 1)) self._winners_per_round.append("taker") else: rewards.append(0) rewards.extend([reward_for_winner] * (self.n_players - 1)) self._winners_per_round.append("opponents") won_cards = self._played_cards_in_round.copy() if Card.EXCUSE in self._played_cards_in_round: excuse_owner = play_order[self._played_cards_in_round.index( Card.EXCUSE)] won_cards.remove(Card.EXCUSE) if excuse_owner == 0: self._won_cards_per_teams["taker"].append(Card.EXCUSE) self._bonus_points_per_teams["opponents"] += 0.5 self._bonus_points_per_teams["taker"] -= 0.5 else: self._won_cards_per_teams["opponents"].append(Card.EXCUSE) if winner == 0: self._bonus_points_per_teams["opponents"] -= 0.5 self._bonus_points_per_teams["taker"] += 0.5 if winner == 0: self._won_cards_per_teams["taker"] += won_cards else: self._won_cards_per_teams["opponents"] += won_cards self.current_player_id = winner self._played_cards_in_round = [] return rewards
def test_play_excuse_in_round(): shuffled_deck = list(np.random.RandomState(seed=1988).permutation(CARDS)) shuffled_deck[15] = Card.DIAMOND_KING shuffled_deck[40] = Card.EXCUSE environment, observation_0 = setup_environment_for_card_phase( shuffled_deck=shuffled_deck) observation_1 = environment.step(Card.HEART_1)[0] observation_2 = environment.step(Card.HEART_5)[0] observation_3 = environment.step(Card.EXCUSE)[0] observation_4, reward, done, _ = environment.step(Card.HEART_2) assert observation_0.played_cards_in_round == [] assert observation_1.played_cards_in_round == [Card.HEART_1] assert observation_2.played_cards_in_round == [Card.HEART_1, Card.HEART_5] assert observation_3.played_cards_in_round == [ Card.HEART_1, Card.HEART_5, Card.EXCUSE ] expected_values = [Card.HEART_1, Card.HEART_5, Card.EXCUSE, Card.HEART_2] assert reward[-1] == compute_card_set_points( expected_values) # last player's team won this round assert not done
def test_point_count_card_set(): assert compute_card_set_points(CARDS) == 91
def _compute_win_loss(self, is_petit_played_in_round: bool, is_excuse_played_in_round: bool, is_taker_win_round: bool) -> List[float]: dog = self._made_dog if len(self._made_dog) > 0 else self._original_dog taker_points = compute_card_set_points( self._won_cards_per_teams["taker"] + list(dog)) taker_points += self._bonus_points_per_teams["taker"] opponents_points = compute_card_set_points( self._won_cards_per_teams["opponents"]) opponents_points += self._bonus_points_per_teams["opponents"] if taker_points + opponents_points != 91: raise FrenchTarotException("Invalid score") if taker_points != round(taker_points): raise FrenchTarotException("Score should be integer") n_oudlers_taker = np.sum([ is_oudler(card) for card in list(self._won_cards_per_teams["taker"]) + list(dog) ]) victory_threshold = None if n_oudlers_taker == 3: victory_threshold = 36 elif n_oudlers_taker == 2: victory_threshold = 41 elif n_oudlers_taker == 1: victory_threshold = 51 elif n_oudlers_taker == 0: victory_threshold = 56 else: FrenchTarotException("Invalid number of oudlers") # noinspection PyTypeChecker diff = abs(victory_threshold - taker_points) contract_value = 25 + diff bid_to_multiplier_map = { Bid.PASS: 0, Bid.PETITE: 1, Bid.GARDE: 2, Bid.GARDE_SANS: 4, Bid.GARDE_CONTRE: 6 } multiplier = bid_to_multiplier_map[np.max(self._bid_per_player)] contract_value = int(contract_value * multiplier) if taker_points < victory_threshold: contract_value *= -1 winners_per_round = self._winners_per_round taker_achieved_chelem = self.has_team_achieved_chelem( winners_per_round, is_excuse_played_in_round, "taker") if taker_achieved_chelem: contract_value += 400 if self.chelem_announced else 200 elif self.has_team_achieved_chelem(winners_per_round, is_excuse_played_in_round, "opponents"): contract_value -= 200 elif not taker_achieved_chelem and self.chelem_announced: contract_value -= 200 if is_petit_played_in_round: to_add = (10 if not is_taker_win_round else -10) * multiplier if taker_points > victory_threshold: to_add *= -1 contract_value += to_add rewards = [ 3 * contract_value, -contract_value, -contract_value, -contract_value ] rewards = self._update_rewards_with_poignee(rewards) assert np.sum(rewards) == 0 return rewards