def test_1_prince_victory(): """ player1 has a countess, player0 uses a prince to discard himself and get the princess and win. """ game_round = start_round_from_player_cards( [cards.Prince(), cards.Handmaid(), cards.Guard()], [cards.Countess(), cards.Priest()], set_aside=cards.Princess(), first_player=0, ) player0, player1 = game_round.players assert tuple(map(CardType, player0.hand)) == (CardType.PRINCE, CardType.HANDMAID) assert tuple(map(CardType, player1.hand)) == (CardType.COUNTESS, ) assert max(game_round.players, key=lambda p: p.hand.card.value) is player1 (immunity, ) = play_with_choices(player0, CardType.HANDMAID) assert immunity.player is player0 results = play_with_choices(player1, CardType.PRIEST, mv.OpponentChoice.NO_TARGET) assert results == () discarded, dealt = play_with_choices(player0, CardType.PRINCE, player0) assert CardType(discarded.discarded) == CardType.GUARD assert CardType(dealt.dealt) == CardType.PRINCESS end = game_round.state assert end.type == RoundState.Type.ROUND_END assert max(game_round.players, key=lambda p: p.hand.card.value) is player0 assert end.winner is player0
def test_start_emptyDeckUponStart_raises(new_round: Round): new_round.deck = Deck( [cards.Guard() for _ in range(new_round.num_players + 1)], set_aside=cards.Princess(), ) with pytest.raises(valid8.ValidationError): new_round.start()
def start_round_from_player_cards(*player_cards: Sequence[cards.Card], first_player: int, set_aside=None): """ Create a round that will deal to each player the specified sequence of cards. The deck is built in a way so that player i starts with player_cards[i][0] and is dealt the cards in player_cards[i][1:] in order at each successive turn. This assumes that no player is eliminated before the last card in player_cards[i] is dealt to them. :param player_cards: A varargs sequence of card sequences that each player will receive during the round. The first list corresponds to player 0, then player 1, and so on. :param first_player: ID (index) of the first player to play in the round. This is (also) needed to build the deck so that player_cards[i] always corresponds to player i (*not* the i-th player to play). :param set_aside: Which card to set aside in the deck. Default is a new instance of :class:`cards.Princess`. :return: A round with the number of players and deck deduced from ``player_cards``. """ player_cards = player_cards[first_player:] + player_cards[:first_player] stack = list(mitt.roundrobin(*player_cards))[::-1] deck = Deck(stack, set_aside=set_aside or cards.Princess()) round = Round(len(player_cards), deck=deck) round.start(first_player=round.players[first_player]) return round
def test_chancellor_oneCardInDeck_onlyUsesOneCard(started_round: Round): deck_card, set_aside = cards.Spy(), cards.Princess() started_round.deck = Deck([deck_card], set_aside=set_aside) player = started_round.current_player move = play_card(player, cards.Chancellor()) card_choice = next(move) assert len(card_choice.options) == 2 assert set(card_choice.options) == {player.hand.card, deck_card} assert started_round.deck.set_aside is set_aside # cleanup to avoid exception when .close() is called autofill_move(move, start_step=card_choice)
def round_runner(g): game_round = start_round_from_player_cards( [cards.Guard(), cards.Baron()], [cards.King(), cards.Princess()], first_player=0, ) object.__setattr__(g.state, "round", game_round) # work around frozen dataclass player0, player1 = game_round.players play_with_choices(player0, CardType.GUARD, player1, cards.Princess) play_random_move(player1) end = game_round.state assert end.type == RoundState.Type.ROUND_END assert end.winner is player0
def test_3_king_win(): """ player1 draws the Princess but is forced to relinquish it because they have a King. """ game_round = start_round_from_player_cards( [cards.Guard(), cards.Baron()], [cards.King(), cards.Princess()], first_player=0, ) player0, player1 = game_round.players play_with_choices(player0, CardType.GUARD, player1, cards.Princess) play_random_move(player1) end = game_round.state assert end.type == RoundState.Type.ROUND_END assert end.winner is player0
def test_5_baron_suicide(): """ player0 has Baron-Baron and everyone else has higher cards, so they die. """ game_round = start_round_from_player_cards( [cards.Baron(), cards.Baron()], [cards.Countess(), cards.Handmaid(), cards.Guard()], [cards.Handmaid(), cards.Princess(), cards.Guard()], first_player=0, ) player0, player1, player2 = game_round.players play_random_move(player0) assert not game_round.ended assert not player0.alive assert player1.alive assert player2.alive
def test_roundEnd_totalTie_allContendersWin(started_round: Round, loser): losers = {loser} if loser is not None else set() winners = set(started_round.players) - losers started_round.deck.stack.clear() for player in winners: give_card(player, cards.Princess(), replace=True) player.discarded_cards = [cards.Guard()] for loser in losers: give_card(loser, cards.Guard(), replace=True) end: loveletter.round.RoundEnd = force_next_turn(started_round) assert end.type == RoundState.Type.ROUND_END assert end.tie_contenders == winners assert end.winners == winners if len(winners) > 1: with pytest.raises(valid8.ValidationError): # noinspection PyStatementEffect end.winner
def test_advanceTurn_emptyDeck_roundEndsWithLargestCardWinner( started_round: Round, set_aside): started_round.deck = Deck([], set_aside=set_aside) increasing_cards = [ cards.Guard(), cards.Priest(), cards.Baron(), cards.Princess() ] for player, card in zip(started_round.players, increasing_cards): give_card(player, card, replace=True) # noinspection PyUnboundLocalVariable winner = player state: loveletter.round.RoundEnd = force_next_turn(started_round) assert state.type == RoundState.Type.ROUND_END assert state.reason == loveletter.round.RoundEnd.Reason.EMPTY_DECK assert state.winners == frozenset({winner}) assert state.winner is winner
def test_prince_againstPrincess_kills(started_round: Round): player = started_round.current_player victim = started_round.next_player(player) give_card(victim, cards.Princess(), replace=True) victim_card = victim.hand.card deck_before = list(started_round.deck) move = play_card(player, cards.Prince()) target_step = next(move) target_step.choice = victim results = send_gracious(move, target_step) assert tuple(map(type, results)) == ( mv.CardDiscarded, mv.PlayerEliminated, ) assert results[0].target is victim assert results[0].discarded is victim_card assert results[1].eliminated is victim assert not victim.alive assert CardType(victim.discarded_cards[-1]) == CardType.PRINCESS assert list(started_round.deck) == deck_before
def test_4_princess_suicide(): """ player1 holds a Princess but has to eliminate themselves because they draw a Prince and the opponent is immune. """ game_round = start_round_from_player_cards( [cards.Handmaid(), cards.Baron(), cards.Guard()], [cards.Princess(), cards.Prince(), cards.Countess()], first_player=0, ) player0, player1 = game_round.players play_with_choices(player0, CardType.HANDMAID) play_random_move(player1) assert game_round.ended assert game_round.state.winner is player0 assert CardType( game_round.deck.take()) == CardType.GUARD # assert no card dealt
def test_6_guard_win(): """A chain of Guard eliminations that ends in player 3 winning""" game_round = start_round_from_player_cards( [cards.King()], [cards.Countess(), cards.Guard()], [cards.Princess(), cards.Guard()], [cards.Guard(), cards.Guard()], first_player=1, ) player0, player1, player2, player3 = game_round.players play_with_choices(player1, CardType.GUARD, player0, CardType.KING) play_with_choices(player2, CardType.GUARD, player1, CardType.COUNTESS) play_with_choices(player3, CardType.GUARD, player2, CardType.PRINCESS) assert game_round.ended assert not player0.alive assert not player1.alive assert not player2.alive assert player3.alive assert game_round.state.winner is player3
def test_princess_eliminatesSelf(current_player: RoundPlayer): player_mock = mock_player(current_player) play_card(player_mock, cards.Princess()) player_mock.eliminate.assert_called_once() assert not current_player.alive
def test_playType_notPresent_raises(player: RoundPlayer): give_card(player, cards.Guard()) give_card(player, cards.Princess()) with pytest.raises(valid8.ValidationError): send_gracious(player.play_type(CardType.PRINCE), None)
def test_deck_containsSetAside(): deck = Deck([], set_aside=(set_aside := cards.Princess()))