Пример #1
0
    def makeDecision(self, s: State, response: DecisionResponse):
        d: DecisionState = s.decision
        player: int = d.controlling_player
        if d.type != DecisionType.DecisionSelectCards and d.type != DecisionType.DecisionDiscreteChoice:
            logging.error('Invalid decision type')
        if not d.active_card:
            self.makePhaseDecision(s, response)
        elif s.events:
            event = s.events[-1]
            if isinstance(event, PutOnDeckDownToN):
                self.heuristic.makePutDownOnDeckDecision(s, response)
            elif isinstance(event, DiscardDownToN):
                self.heuristic.makeDiscardDownDecision(s, response)
            elif isinstance(event, RemodelExpand):
                if not event.trashed_card:

                    def scoringFunction(card: Card):
                        if isinstance(card, Curse):
                            return 19
                        elif isinstance(card, Estate):
                            return 18
                        elif isinstance(card, VictoryCard):
                            return -200 + card.get_coin_cost()
                        return -card.get_coin_cost()

                    response.cards = heuristic_select_cards(
                        d.card_choices, d.min_cards, scoringFunction)
                else:
                    response.cards.append(
                        self.heuristic.agenda.forceBuy(s, player,
                                                       d.card_choices))
        else:
            self.heuristic.makeBaseDecision(s, response)
Пример #2
0
    def makeCopyDecision(self, s: State, response: DecisionResponse):
        d: DecisionState = s.decision

        def scoringFunction(card: Card):
            return card.get_coin_cost()

        response.cards = heuristic_select_cards(d.card_choices, d.min_cards, scoringFunction)
Пример #3
0
    def makeDiscardDownDecision(self, s: State, response: DecisionResponse):
        d: DecisionState = s.decision

        def scoringFunction(card: Card):
            if isinstance(card, VictoryCard):
                return 20
            elif isinstance(card, Curse):
                return 19
            elif isinstance(card, Copper):
                return 18
            return -card.get_coin_cost()

        response.cards = heuristic_select_cards(d.card_choices, d.min_cards, scoringFunction)
Пример #4
0
    def makeGreedyActionDecision(self, s: State, response: DecisionResponse):
        d: DecisionState = s.decision
        assert d.min_cards == 0 and d.max_cards == 1, 'Invalid decision parameters'

        def scoringFunction(card: Card):
            '''Play all cantrips first, then greedily'''
            cantrip_bonus = 7
            score = min(card.get_coin_cost(), 6)

            if is_cantrip(card):
                score += cantrip_bonus

            return score

        cards = heuristic_select_cards(d.card_choices, d.min_cards, scoringFunction)
        response.cards = cards
Пример #5
0
    def makePutDownOnDeckDecision(self, s: State, response: DecisionResponse):
        d: DecisionState = s.decision

        def scoringFunction(card: Card):
            if has_excess_actions(s.decision.card_choices):
                if isinstance(card, ActionCard):
                    return 100 - card.get_plus_actions()
                return -card.get_coin_cost()
            elif has_treasure_cards(s.decision.choices):
                if isinstance(card, TreasureCard):
                    return 100 - card.get_treasure()
                return -card.get_coin_cost()
            else:
                return -card.get_coin_cost()

        response.cards = heuristic_select_cards(d.card_choices, d.min_cards, scoringFunction)
Пример #6
0
    def test_event_sentry(self) -> None:
        self.game.new_game()

        # Inject Sentry in player's hand
        sentry = Sentry()

        self.game.state.inject(0, sentry)

        self.game.state.advance_next_decision()

        # Action Phase Decision
        r = DecisionResponse([])
        r.cards = [sentry]
        self.game.state.process_decision(r)
        self.game.state.advance_next_decision()

        # Choose to trash one card
        d = self.game.state.decision
        trashed = d.card_choices[0]
        r = DecisionResponse([trashed])
        self.game.state.process_decision(r)
        # Trash card
        self.game.state.advance_next_decision()

        self.assertEqual(self.game.state.trash, [trashed])

        # Choose to discard one card
        d = self.game.state.decision
        discarded = d.card_choices[0]
        r = DecisionResponse([discarded])
        self.game.state.process_decision(r)
        # Discard card
        self.game.state.advance_next_decision()

        d = self.game.state.decision
        p_state: PlayerState = self.game.state.player_states[0]
        self.assertEqual(p_state._discard, [discarded])
        self.assertIsNone(d.active_card)
Пример #7
0
    def makeDecision(self, s: State, response: DecisionResponse):
        d: DecisionState = s.decision

        # Do not allow RandomPlayer to purchase curses
        if s.phase == Phase.BuyPhase and not self.train:
            remove_first_card(Curse(), d.card_choices)

        # Ensure random player plays all treasures
        if s.phase == Phase.TreasurePhase:
            response.single_card = d.card_choices[0]
            return

        if d.type == DecisionType.DecisionSelectCards:
            cards_to_pick = d.min_cards
            if d.max_cards > d.min_cards:
                cards_to_pick = random.randint(d.min_cards, d.max_cards)

            response.cards = random.sample(d.card_choices,
                                           k=min(cards_to_pick,
                                                 len(d.card_choices)))
        elif d.type == DecisionType.DecisionDiscreteChoice:
            response.choice = random.randint(0, d.min_cards)
        else:
            logging.error('Invalid decision type')
Пример #8
0
    def test_moat_reveal(self) -> None:
        self.game.new_game()

        # Inject necessary cards into players' hands
        attack_card = Militia()
        moat_card = Moat()
        self.game.state.inject(0, attack_card)
        self.game.state.inject(1, moat_card)

        self.game.state.advance_next_decision()

        # Action Phase decision
        r = DecisionResponse([])
        r.cards = [attack_card]
        self.game.state.process_decision(r)
        self.game.state.advance_next_decision()

        # MoatReveal reaction
        r = DecisionResponse([])
        r.choice = 0
        self.game.state.process_decision(r)
        self.game.state.advance_next_decision()

        self.assertEqual(self.game.state.events, [])
Пример #9
0
 def makeBaseDecision(self, s: State, response: DecisionResponse):
     d: DecisionState = s.decision
     card = d.active_card
     player = s.decision.controlling_player
     p_state: PlayerState = s.player_states[player]
     if isinstance(card, Cellar):
         num_discarded = 0
         for c in d.card_choices:
             if isinstance(c, VictoryCard) or c.get_coin_cost() < 2:
                 response.cards.append(c)
     elif isinstance(card, Chapel):
         treasureValue = s.get_total_coin_count(player)
         trashCoppers = (treasureValue > 3)
         num_discarded = 0
         for c in d.card_choices:
             trashCoppers = (treasureValue > 3)
             if num_discarded == 4:
                 break
             if isinstance(c, Curse):
                 response.cards.append(c)
                 num_discarded += 1
             elif isinstance(c, Copper) and trashCoppers:
                 response.cards.append(c)
                 num_discarded += 1
                 treasureValue -= 1
             elif isinstance(c, Estate):
                 response.cards.append(c)
                 num_discarded += 1
             elif isinstance(c, Chapel):
                 response.cards.append(c)
                 num_discarded += 1
     elif isinstance(card, Moat):
         response.choice = 0
     elif isinstance(card, Bureaucrat):
         response.cards.append(d.card_choices[0])
     elif isinstance(card, Militia):
         self.makeDiscardDownDecision(s, response)
     elif isinstance(card, ThroneRoom):
         self.makeCopyDecision(s, response)
     elif isinstance(card, Library):
         if s.player_states[s.player].actions == 0:
             response.choice = 0
         else:
             response.choice = 1
     elif isinstance(card, Mine):
         event = s.events[-1]
         if not event.trashed_card:
             def scoringFunction(card: Card):
                 if isinstance(card, Gold) and s.supply[Gold] > 0:
                     return 20
                 if isinstance(card, Silver) and s.supply[Silver] > 0:
                     return 19
                 if isinstance(card, Copper) and s.supply[Copper] > 0:
                     return 18
                 return -card.get_coin_cost()
             response.cards = heuristic_select_cards(d.card_choices, d.min_cards, scoringFunction)
         else:
             response.cards.append(self.agenda.forceBuy(s, player, d.card_choices))
     elif isinstance(card, Harbinger):
         def scoringFunction(card: Card):
             if has_excess_actions(p_state.hand):
                 if isinstance(card, ActionCard):
                     return 100 + card.get_coin_cost()
                 else:
                     return card.get_coin_cost()
             else:
                 return card.get_coin_cost()
         response.cards = heuristic_select_cards(d.card_choices, d.min_cards, scoringFunction)
     elif isinstance(card, Artisan):
         event = s.events[-1]
         if not event.gained_card:
             response.cards.append(self.agenda.forceBuy(s, player, d.card_choices))
         else:
             self.makePutDownOnDeckDecision(s, response)
     elif isinstance(card, Poacher):
         self.makeDiscardDownDecision(s, response)
     else:
         logging.error('Unexpected decision')