Example #1
0
 def test_play_poacher_with_empty_supply_piles(self):
     for num_empty_supply_piles in (1, 2, 3):
         cards_in_supply = [CopperCard, SilverCard, GoldCard]
         starting_deck = [CopperCard] * 20
         game_state = self.create_game_state(
             starting_deck, supply=UnorderedCardStack(cards_in_supply))
         p1_agent = TestAgent('p1')
         p2_agent = TestAgent('p2')
         game_state.set_agents([p1_agent, p2_agent])
         supply = game_state.get_location(
             Location(None, LocationName.SUPPLY))
         # empty supply piles
         for i in range(num_empty_supply_piles):
             supply.extract([cards_in_supply[i]])
         player = game_state.get_current_player_name()
         start_hand_size = 5
         game_state.draw(start_hand_size)
         PoacherCard.play(game_state)
         hand = game_state.get_location(Location(player, LocationName.HAND))
         self.assertEqual(
             hand.size(), start_hand_size + 1 - num_empty_supply_piles,
             'Player should draw 1 card and then discard one for each empty supply pile.'
         )
         discard = game_state.get_location(
             Location(player, LocationName.DISCARD))
         self.assertEqual(
             discard.size(), num_empty_supply_piles,
             'Player should have discarded 1 card for each empty supply pile.'
         )
         self.assertEqual(
             game_state.get_counter(CounterId(None, CounterName.COINS)), 1,
             'Poacher should give the player one extra coin.')
         self.assertEqual(
             game_state.get_counter(CounterId(None, CounterName.ACTIONS)),
             1, 'Poacher should give the player one extra action.')
Example #2
0
    def play(cls, game_state):
        """
        +1 card
        +1 action
        Look through your discard pile. You may put that card on top of your deck
        """
        game_state.draw(1)
        game_state.update_counter(counter_id=CounterId(None,
                                                       CounterName.ACTIONS),
                                  delta=1)

        decision = HarbingerDecision(game_state)
        agent = game_state.get_agent(game_state.get_current_player_name())
        chosen_cards = agent.make_decision(decision)
        assert decision.is_valid(chosen_cards)
        if chosen_cards:
            game_state.move(cards=chosen_cards,
                            number=None,
                            from_location=Location(agent.name(),
                                                   LocationName.DISCARD),
                            from_position=None,
                            to_location=Location(agent.name(),
                                                 LocationName.DRAW_PILE),
                            to_position=StackPosition.TOP,
                            event_type=CardEventType.MOVE)
Example #3
0
 def test_no_cards_in_deck_or_discard(self):
     game_state = self.create_game_state([])
     player = game_state.get_current_player_name()
     VassalCard.play(game_state)
     discard = game_state.get_location(
         Location(player, LocationName.DISCARD))
     draw_pile = game_state.get_location(
         Location(player, LocationName.DRAW_PILE))
     self.assertEqual(draw_pile.size(), 0)
     self.assertEqual(discard.size(), 0)
Example #4
0
 def test_top_card_is_action_choose_not_to_play_it(self):
     game_state = self.create_game_state([VassalCard, CopperCard])
     game_state.set_agents([NeverVassalAgent('p1'), NeverVassalAgent('p2')])
     player = game_state.get_current_player_name()
     VassalCard.play(game_state)
     discard = game_state.get_location(
         Location(player, LocationName.DISCARD))
     draw_pile = game_state.get_location(
         Location(player, LocationName.DRAW_PILE))
     self.assertEqual(discard.peek(), VassalCard)
     self.assertEqual(draw_pile.peek(), CopperCard)
Example #5
0
 def buy(self, card):
     """
     Causes the current player to buy the card.
     """
     player = self.get_current_player_name()
     self.move(cards=[card],
               number=None,
               from_location=Location(None, LocationName.SUPPLY),
               from_position=None,
               to_location=Location(player, LocationName.DISCARD),
               to_position=None,
               event_type=CardEventType.BUY)
Example #6
0
 def gain_to_top_of_deck(self, card, player=None):
     """
     Causes the player to gain the card to the top of their draw pile
     """
     player = player or self.get_current_player_name()
     self.move(cards=[card],
               number=None,
               from_location=Location(None, LocationName.SUPPLY),
               from_position=None,
               to_location=Location(player, LocationName.DRAW_PILE),
               to_position=StackPosition.TOP,
               event_type=CardEventType.GAIN)
Example #7
0
 def test_play(self):
     game_state = self.create_default_game_state()
     current_player = game_state.get_current_player_name()
     hand_location = Location(current_player, LocationName.HAND)
     hand = game_state.get_location(hand_location)
     hand.add(1)
     game_state.play(1)
     in_play = game_state.get_location(Location(current_player, LocationName.IN_PLAY))
     self.assertEqual(in_play.size(), 1)
     self.assertEqual(hand.size(), 0)
     game_state.discard_location(Location(current_player, LocationName.IN_PLAY))
     self.assertEqual(in_play.size(), 0)
Example #8
0
 def trash(self, card, player=None):
     """
     Causes the player to trash the card.
     """
     player = player or self.get_current_player_name()
     self.move(cards=[card],
               number=None,
               from_location=Location(player, LocationName.HAND),
               from_position=None,
               to_location=Location(None, LocationName.TRASH),
               to_position=None,
               event_type=CardEventType.TRASH)
Example #9
0
 def test_no_cards_in_deck_some_in_discard(self):
     game_state = self.create_game_state([])
     player = game_state.get_current_player_name()
     discard = game_state.get_location(
         Location(player, LocationName.DISCARD))
     discard.add([CopperCard, CopperCard])
     VassalCard.play(game_state)
     discard = game_state.get_location(
         Location(player, LocationName.DISCARD))
     self.assertEqual(discard.peek(), CopperCard)
     draw_pile = game_state.get_location(
         Location(player, LocationName.DRAW_PILE))
     self.assertEqual(draw_pile.peek(), CopperCard)
Example #10
0
 def gain(self, card, player=None, to_location=None, to_position=None):
     """
     Causes the player to gain the card.
     """
     player = player or self.get_current_player_name()
     to_location = to_location or Location(player, LocationName.DISCARD)
     self.move(cards=[card],
               number=None,
               from_location=Location(None, LocationName.SUPPLY),
               from_position=None,
               to_location=to_location,
               to_position=to_position,
               event_type=CardEventType.GAIN)
Example #11
0
 def _create_locations(self, player_names):
     """
     Create a dict of `Location` -> CardStack for all locations
     in a starting game state given the list of player names.
     """
     locations = {}
     for loc_name, stack_class in STACK_CLASS_BY_LOCATION_NAME.items():
         stack_class = STACK_CLASS_BY_LOCATION_NAME[loc_name]
         if loc_name in GLOBAL_LOCATIONS:
             locations[Location(None, loc_name)] = stack_class()
         else:
             for player in player_names:
                 locations[Location(player, loc_name)] = stack_class()
     return locations
Example #12
0
 def play(self, card, player=None, from_location=None):
     """
     Causes the player to play the card. This just moves the card to play
     from the player's hand it does not trigger the cards logic to be executed.
     """
     player = player or self.get_current_player_name()
     from_location = from_location or Location(player, LocationName.HAND)
     self.move(cards=[card],
               number=None,
               from_location=from_location,
               from_position=None,
               to_location=Location(player, LocationName.IN_PLAY),
               to_position=None,
               event_type=CardEventType.PLAY)
Example #13
0
 def test_create_game_state(self):
     supply = UnorderedCardStack()
     supply.add(cards=[1])
     supply.add(cards=[2, 2])
     names = ['p1', 'p2']
     logger = TestLogger()
     game_state = GameState(
         player_names=names, supply=supply, starting_deck=[], logger=logger
     )
     # Check trash exists
     trash = game_state.get_location(Location(None, LocationName.TRASH))
     self.assertEqual(type(trash), UnorderedCardStack)
     # Check player hands exist
     for name in names:
         hand = game_state.get_location(Location(name, LocationName.HAND))
         self.assertEqual(type(trash), UnorderedCardStack)
Example #14
0
 def discard(self, cards, player=None, location=None):
     """
     Causes the player to discard the cards. The first card in the list will be the one
     on top of the discard pile after discarding them.
     """
     if not cards:
         return
     player = player or self.get_current_player_name()
     location = location or Location(player, LocationName.HAND)
     self.move(cards=cards,
               number=None,
               from_location=location,
               from_position=None,
               to_location=Location(player, LocationName.DISCARD),
               to_position=None,
               event_type=CardEventType.DISCARD)
Example #15
0
 def test_top_card_not_action(self):
     game_state = self.create_game_state([CopperCard, CopperCard])
     player = game_state.get_current_player_name()
     VassalCard.play(game_state)
     discard = game_state.get_location(
         Location(player, LocationName.DISCARD))
     self.assertEqual(discard.peek(), CopperCard)
Example #16
0
 def __init__(self, game_state):
     player = game_state.get_current_player_name()
     cards = list(
         game_state.get_location(Location(player, LocationName.HAND)))
     self.options = cards
     self.min = 0
     self.max = len(cards)
Example #17
0
 def test_upgrade_treasure(self):
     game_state = self.create_game_state(
         [MineCard, CopperCard, CopperCard, SilverCard])
     p1_agent = MineUpgradeAgent('p1')
     p2_agent = MineUpgradeAgent('p2')
     game_state.set_agents([p1_agent, p2_agent])
     game_state.draw(4)
     player = game_state.get_current_player_name()
     MineCard.play(game_state)
     self.assertEqual(p1_agent.get_decision_count(MineTrashDecision), 1)
     self.assertEqual(p1_agent.get_decision_count(MineGainDecision), 1)
     hand = game_state.get_location(Location(player, LocationName.HAND))
     self.assertEqual(hand.size(), 4)
     self.assertTrue(GoldCard in list(hand))
     trash = game_state.get_location(Location(None, LocationName.TRASH))
     self.assertTrue(SilverCard in list(trash))
Example #18
0
 def __init__(self, game_state):
     hand = game_state.get_location(
         Location(game_state.get_current_player_name(), LocationName.HAND))
     self.options = []
     if CopperCard in hand:
         self.options = [CopperCard]
     self.min = 0
     self.max = 1
Example #19
0
 def __init__(self, player_names, supply, starting_deck, logger):
     """
     Parameters:
         player_names (list of str): List of the names of players in the order of turns.
         supply (`UnorderedCardStack`): Starting supply for the game.
         starting_deck (`UnorderedCardStack`): Cards each player will start with.
         logger (`GameLogger`): All changes to game state will be logged here.
     """
     self.logger = logger
     self.player_names = player_names
     self._counters = self._create_counters(player_names)
     self._locations = self._create_locations(player_names)
     for player in player_names:
         stack = self.get_location(Location(player, LocationName.DRAW_PILE))
         stack.add(list(starting_deck))
     self._locations[Location(None, LocationName.SUPPLY)] = supply
     self._current_player_index = 0
Example #20
0
 def game_over(self):
     supply = self.game_state.get_location(
         Location(None, LocationName.SUPPLY))
     if supply.distribution.count(ProvinceCard) == 0:
         return True
     cards_to_counts = supply.distribution.cards_to_counts()
     if list(cards_to_counts.values()).count(0) >= 3:
         return True
     return False
Example #21
0
 def draw(self, number, player=None):
     """
     Draws `number` cards to the given player's hand.
     """
     player = player or self.get_current_player_name()
     self.shuffle_discard_in_if_insufficient_cards(number, player)
     draw_stack = self.get_location(Location(player,
                                             LocationName.DRAW_PILE))
     number_to_draw = min(number, draw_stack.size())
     if number_to_draw == 0:
         return
     self.move(cards=None,
               number=number_to_draw,
               from_location=Location(player, LocationName.DRAW_PILE),
               from_position=StackPosition.TOP,
               to_location=Location(player, LocationName.HAND),
               to_position=None,
               event_type=CardEventType.DRAW)
Example #22
0
 def __init__(self, game_state):
     player = game_state.get_current_player_name()
     cards = set(
         game_state.get_location(Location(player, LocationName.HAND)))
     treasure_cards = [
         card for card in cards if issubclass(card, TreasureCard)
     ]
     self.options = treasure_cards
     self.min = 0
     self.max = 1
Example #23
0
 def __init__(self, game_state):
     supply = game_state.get_location(Location(None, LocationName.SUPPLY))
     options = []
     for card, count in supply.distribution.cards_to_counts().items():
         if count > 0 and card.cost(game_state) <= 4:
             options.append(card)
     self.options = options
     # Player must gain something if possible
     self.min = 1 if options else 0
     self.max = 1
Example #24
0
 def _shuffle_discard_into_draw(self, player):
     """
     Shuffle the discard pile of the player and put it under their draw pile.
     """
     discard_location = Location(player, LocationName.DISCARD)
     number = self.get_location(discard_location).size()
     discard_is_empty_so_no_action_required = (number == 0)
     if discard_is_empty_so_no_action_required:
         return
     self.shuffle(discard_location)
     self.move(
         cards=None,
         number=number,
         from_location=Location(player, LocationName.DISCARD),
         from_position=StackPosition.TOP,
         to_location=Location(player, LocationName.DRAW_PILE),
         to_position=StackPosition.BOTTOM,
         event_type=CardEventType.MOVE,
     )
Example #25
0
 def _print_location(self, known_state, location):
     if known_state is None:
         print('%s contents not known.' % location.name)
         return
     location = Location(known_state.viewing_player, location)
     info = known_state.get_location_info(location)
     if info.stack:
         print(','.join([str(card) for card in info.stack]))
     else:
         print('%s is empty.' % location.name.name)
Example #26
0
 def shuffle_discard_in_if_insufficient_cards(self, number, player=None):
     """
     Prepare the player's draw pile for taking number cards from it by shuffling in the
     discard pile if needed.
     """
     player = player or self.get_current_player_name()
     draw_stack = self.get_location(Location(player,
                                             LocationName.DRAW_PILE))
     if draw_stack.size() < number:
         self._shuffle_discard_into_draw(player)
Example #27
0
 def __init__(self, game_state, max_cost):
     player = game_state.get_current_player_name()
     cards = set(
         game_state.get_location(Location(None, LocationName.SUPPLY)))
     treasure_cards_meeting_cost_constraint = [
         card for card in cards if issubclass(card, TreasureCard)
         and card.cost(game_state) <= max_cost
     ]
     self.options = treasure_cards_meeting_cost_constraint
     self.min = 1
     self.max = 1
Example #28
0
 def test_top_cards_are_actions_choose_to_play_them(self):
     game_state = self.create_game_state(
         [VassalCard, VassalCard, CopperCard, CopperCard])
     game_state.set_agents(
         [AlwaysVassalAgent('p1'),
          AlwaysVassalAgent('p2')])
     player = game_state.get_current_player_name()
     VassalCard.play(game_state)
     discard = game_state.get_location(
         Location(player, LocationName.DISCARD))
     in_play = game_state.get_location(
         Location(player, LocationName.IN_PLAY))
     draw_pile = game_state.get_location(
         Location(player, LocationName.DRAW_PILE))
     self.assertEqual(in_play.size(),
                      2)  # Doesn't include the artificially played one
     self.assertEqual(discard.size(), 1)
     self.assertEqual(draw_pile.size(), 1)
     self.assertEqual(discard.peek(), CopperCard)
     self.assertEqual(draw_pile.peek(), CopperCard)
Example #29
0
 def get_deck(self, player):
     """
     Returns a list of Cards in the players deck. "Deck" refers to all cards belonging
     to the player including the ones in their hand, discard, in play, and set aside.
     """
     cards = []
     for loc_name in STACK_CLASS_BY_LOCATION_NAME:
         if loc_name in GLOBAL_LOCATIONS:
             continue
         cards += list(self.get_location(Location(player, loc_name)))
     return cards
Example #30
0
 def test_draw_when_enough_cards_in_draw_pile(self):
     game_state = self.create_default_game_state()
     current_player = game_state.get_current_player_name()
     draw_pile_location = Location(current_player, LocationName.DRAW_PILE)
     draw_pile = game_state.get_location(draw_pile_location)
     for i in range(10):
         draw_pile.add(i)
     game_state.draw(5)
     self.assertEqual(draw_pile.size(), 5)
     hand_location = Location(current_player, LocationName.HAND)
     hand = game_state.get_location(hand_location)
     self.assertEqual(hand.size(), 5)
     event = (
         CardMoveEvent(
             [9, 8, 7, 6, 5], draw_pile_location, StackPosition.TOP,
             hand_location, None, CardEventType.DRAW
         )
     )
     self.assertEqual(
         game_state.logger.get_log(), [event]
     )