예제 #1
0
 def suffer_damage(self, clearing: Clearing, hits: int, opponent: Player, is_attacker: bool) -> DamageResult:
     removed_pieces = []
     points_awarded = 0
     if hits:
         warriors = clearing.get_warriors_for_player(self)  # TODO: Mercenaries
         amount_of_warriors_removed = min(hits, len(warriors))
         hits -= amount_of_warriors_removed
         for i in range(amount_of_warriors_removed):
             removed_pieces.append(warriors[i])
             points_awarded += warriors[i].get_score_for_removal()
     if hits:
         tokens = clearing.get_tokens_for_player(self)
         random.shuffle(tokens)
         amount_of_tokens_removed = min(hits, len(tokens))
         hits -= amount_of_tokens_removed
         for i in range(amount_of_tokens_removed):
             removed_pieces.append(tokens[i])
             # If the Popularity trait is used, players can't score for sympathy if they already have since last turn
             if (not self.has_trait(TRAIT_POPULARITY) or
                     opponent not in self.players_who_have_removed_sympathy_since_last_turn):
                 points_awarded += tokens[i].get_score_for_removal()
             self.players_who_have_removed_sympathy_since_last_turn.add(opponent)
     if hits:
         buildings = clearing.get_buildings_for_player(self)
         random.shuffle(buildings)
         amount_of_buildings_removed = min(hits, len(buildings))
         hits -= amount_of_buildings_removed
         for i in range(amount_of_buildings_removed):
             removed_pieces.append(buildings[i])
             points_awarded += buildings[i].get_score_for_removal()
     clearing.remove_pieces(self, removed_pieces)
     return DamageResult(removed_pieces=removed_pieces, points_awarded=points_awarded)
예제 #2
0
 def get_bonus_hits(self, clearing: Clearing, opponent: Player, is_attacker: bool = True) -> int:
     bonus_hits = 0
     # Automated Ambush
     if clearing.get_warrior_count_for_player(self) > 0:
         bonus_hits += 1
     elif self.has_trait(TRAIT_INFORMANTS) and clearing.get_token_count_for_player(self) > 0:
         bonus_hits += 1
     return bonus_hits
예제 #3
0
    def test_get_corner_clearings(self):
        mock_game = Mock()
        clearing1 = Clearing(mock_game, Suit.FOX, priority=1, total_building_slots=1, is_corner_clearing=True)
        clearing2 = Clearing(mock_game, Suit.FOX, priority=2, total_building_slots=1, is_corner_clearing=False)
        board_map = BoardMap(mock_game)
        board_map.clearings = [clearing1, clearing2]

        self.assertEqual(board_map.get_corner_clearings(), [clearing1])
예제 #4
0
def sort_players_by_cardboard_in_clearing(
        players: list[Player],
        clearing: Clearing,
        descending: bool = True) -> list[Player]:
    return sorted(players,
                  key=lambda p: (clearing.get_building_count_for_player(p) +
                                 clearing.get_token_count_for_player(p)),
                  reverse=descending)
예제 #5
0
def get_defenseless_enemy_buildings_in_clearing(clearing: Clearing,
                                                acting_player: Player) -> int:
    defenseless_buildings = 0
    for player in clearing.get_all_other_players_in_location(acting_player):
        if player.is_defenseless(clearing):
            defenseless_buildings += clearing.get_building_count_for_player(
                player)
    return defenseless_buildings
예제 #6
0
    def test_get_clearing(self):
        mock_game = Mock()
        clearing1 = Clearing(mock_game, Suit.FOX, priority=1, total_building_slots=1)
        clearing2 = Clearing(mock_game, Suit.FOX, priority=2, total_building_slots=1)
        board_map = BoardMap(mock_game)
        board_map.clearings = [clearing1, clearing2]

        self.assertEqual(board_map.get_clearing(1), clearing1)
        self.assertEqual(board_map.get_clearing(2), clearing2)
예제 #7
0
    def test_get_clearings_of_suit_bird(self):
        mock_game = Mock()
        clearing1 = Clearing(mock_game, Suit.FOX, priority=1, total_building_slots=1)
        clearing2 = Clearing(mock_game, Suit.RABBIT, priority=2, total_building_slots=1)
        clearing3 = Clearing(mock_game, Suit.FOX, priority=3, total_building_slots=1)
        clearing4 = Clearing(mock_game, Suit.MOUSE, priority=4, total_building_slots=1)
        board_map = BoardMap(mock_game)
        board_map.clearings = [clearing1, clearing2, clearing3, clearing4]

        self.assertEqual(board_map.get_clearings_of_suit(Suit.BIRD), [clearing1, clearing2, clearing3, clearing4])
예제 #8
0
 def create_clearings(self, suits: list[Suit], ruins: list[Ruin]) -> None:
     for i in range(12):
         clearing = Clearing(
             self.game,
             suit=suits[i],
             priority=i + 1,
             total_building_slots=
             AUTUMN_MAP_BUILDING_SLOTS_FOR_PRIORITY_CLEARING[i],
             is_corner_clearing=(i < 4))
         if i + 1 in AUTUMN_MAP_RUINS_LOCATIONS and ruins:
             clearing.add_ruin(ruins.pop())
         self.clearings.append(clearing)
예제 #9
0
    def test_get_clearing(self):
        game = Game()
        clearing1 = Clearing(game,
                             Suit.FOX,
                             priority=1,
                             total_building_slots=1)
        clearing2 = Clearing(game,
                             Suit.FOX,
                             priority=2,
                             total_building_slots=1)
        game.board_map.clearings = [clearing1, clearing2]

        self.assertEqual(game.clearings(), [clearing1, clearing2])
예제 #10
0
 def get_warriors_to_move(self, origin_clearing: Clearing,
                          suit: Suit) -> list[Warrior]:
     own_rule_value = self.get_rule_value(origin_clearing)
     max_enemy_rule_value = self.get_max_enemy_rule_value_in_clearing(
         origin_clearing)
     warrior_count_to_move_and_keep_rule = own_rule_value - max_enemy_rule_value
     # Move the minimum between (most you can without losing rule) and (X - #cards in column)
     warrior_count_to_move = min(
         warrior_count_to_move_and_keep_rule,
         (origin_clearing.get_warrior_count_for_player(self) -
          self.decree.get_count_of_suited_cards_in_decree(suit)))
     return origin_clearing.get_warriors_for_player(
         self)[:warrior_count_to_move]
예제 #11
0
def sort_players_by_tokens_in_clearing(
        players: list[Player],
        clearing: Clearing,
        descending: bool = True) -> list[Player]:
    return sorted(players,
                  key=lambda p: clearing.get_token_count_for_player(p),
                  reverse=descending)
예제 #12
0
 def berserker_initiate_battle(self, clearing: Clearing) -> None:
     potential_targets = clearing.get_all_other_players_in_location(self)
     # Sort in reverse order from our tie-breaking priority: Setup order -> most pieces
     potential_targets = sort_players_by_setup_order(potential_targets)
     potential_targets = sort_players_by_pieces_in_clearing(potential_targets, clearing)
     if potential_targets:
         self.battle(clearing, potential_targets[0])
예제 #13
0
 def get_max_enemy_rule_value_in_clearing(self, clearing: Clearing) -> int:
     max_enemy_rule_value = 0
     for other_player in clearing.get_all_other_players_in_location(self):
         rule_value = other_player.get_rule_value(clearing)
         if rule_value > max_enemy_rule_value:
             max_enemy_rule_value = rule_value
     return max_enemy_rule_value
예제 #14
0
def get_lowest_sorted_player_index_clearing(clearing: Clearing,
                                            players: list[Player],
                                            descending: bool = False) -> int:
    for idx, player in players:
        if player in clearing.get_all_players_in_location():
            return idx * (not descending)
    return 100 * (not descending)  # TODO: Implement this better
예제 #15
0
    def test_get_clearings_of_suit_bird(self):
        game = Game()
        clearing1 = Clearing(game,
                             Suit.FOX,
                             priority=1,
                             total_building_slots=1)
        clearing2 = Clearing(game,
                             Suit.FOX,
                             priority=2,
                             total_building_slots=1)
        clearing3 = Clearing(game,
                             Suit.MOUSE,
                             priority=2,
                             total_building_slots=1)
        game.board_map.get_clearings_of_suit.return_value = lambda c: [
            clearing1, clearing2, clearing3
        ]

        self.assertEqual(game.get_clearings_of_suit(Suit.BIRD),
                         [clearing1, clearing2, clearing3])
예제 #16
0
 def does_rule_clearing(self, clearing: Clearing) -> bool:
     all_players_in_clearing = clearing.get_all_other_players_in_location(
         self)
     own_rule_value_in_clearing = self.get_rule_value(clearing)
     if own_rule_value_in_clearing == 0:
         return False
     for player in all_players_in_clearing:
         # LORDS OF THE FOREST: Eyrie Dynasties rule tied clearings
         if player.get_rule_value(clearing) > own_rule_value_in_clearing:
             return False
     return True
 def suffer_damage(self, clearing: Clearing, hits: int, opponent: Player,
                   is_attacker: bool) -> DamageResult:
     removed_pieces = []
     points_awarded = 0
     if hits:
         warriors = clearing.get_warriors_for_player(
             self)  # TODO: Mercenaries
         amount_of_warriors_removed = min(hits, len(warriors))
         hits -= amount_of_warriors_removed
         for i in range(amount_of_warriors_removed):
             removed_pieces.append(warriors[i])
             points_awarded += warriors[i].get_score_for_removal()
     if hits:
         tokens = clearing.get_tokens_for_player(self)
         random.shuffle(tokens)
         amount_of_tokens_removed = min(hits, len(tokens))
         hits -= amount_of_tokens_removed
         for i in range(amount_of_tokens_removed):
             removed_pieces.append(tokens[i])
             points_awarded += tokens[i].get_score_for_removal()
     if hits:
         buildings = clearing.get_buildings_for_player(self)
         random.shuffle(buildings)
         if self.has_trait(TRAIT_FORTIFIED):
             amount_of_buildings_removed = min(hits // 2, len(buildings))
         else:
             amount_of_buildings_removed = min(hits, len(buildings))
         for i in range(amount_of_buildings_removed):
             removed_pieces.append(buildings[i])
             points_awarded += buildings[i].get_score_for_removal()
     clearing.remove_pieces(self, removed_pieces)
     if not is_attacker:
         # Hospitals only works as the defender
         self.apply_field_hospitals(removed_pieces)
     return DamageResult(removed_pieces=removed_pieces,
                         points_awarded=points_awarded)
예제 #18
0
    def find_shortest_legal_paths_to_destination_clearing(
            self,
            player: Player,
            moving_piece: Piece,
            destination: Clearing,
            ignore_move: bool = False) -> list[list[Clearing]]:
        if not destination.can_move_piece_into(player, moving_piece):
            return []

        # TODO: Test and clean
        clearing_paths: deque[list[Clearing]] = deque([[]])
        all_shortest_paths: list[list[Clearing]] = []

        while clearing_paths:
            current_path = clearing_paths.popleft()
            if not current_path:
                current_location = self
            else:
                current_location = current_path[-1]

            for adjacent_clearing in player.get_adjacent_clearings(
                    current_location):
                # Don't double back on yourself - that adds to the path length uselessly
                if adjacent_clearing in current_path:
                    continue
                # Skip impossible moves, unless ignore_move is True
                if not ignore_move and not current_location.can_move_piece(
                        player, moving_piece, adjacent_clearing):
                    continue
                next_path = [c for c in current_path]
                next_path.append(adjacent_clearing)
                if adjacent_clearing == destination:
                    all_shortest_paths.append(
                        [c for c in current_path if isinstance(c, Clearing)])
                # Breadth-first-search: Once we find a path to the destination N clearings away, we know no path to
                # the destination is shorter than N, so don't add any more to the clearing_paths queue
                elif not all_shortest_paths:
                    clearing_paths.append(next_path)

        return all_shortest_paths
 def halves_damage(self, battle_clearing: Clearing) -> bool:
     return (self.has_trait(TRAIT_FORTIFIED)
             and battle_clearing.get_building_count_for_player(self)
             == battle_clearing.get_piece_count_for_player(self))