Beispiel #1
0
    def get_next_moves(self):
        """computes the next moves available from the current state
        Returns:
            List of AbstractMove: a list of the next moves
        """
        if self.is_initialisation_phase():
            return self._get_initialisation_moves()

        if self.current_dice_number != 7:
            empty_move = CatanMove(self.board.get_robber_land())
            moves = [empty_move]
        else:
            moves = [
                CatanMove(land)
                for land in self.board.get_lands_to_place_robber_on()
            ]
        moves = self._get_all_possible_development_cards_exposure_moves(moves)
        # _get_all_possible_trade_moves is assuming it's after dev_cards moves and nothing else
        moves = self._get_all_possible_trade_moves(moves)
        moves = self._get_all_possible_paths_moves(moves)
        moves = self._get_all_possible_settlements_moves(moves)
        moves = self._get_all_possible_cities_moves(moves)
        moves = self._get_all_possible_development_cards_purchase_count_moves(
            moves)
        return moves
Beispiel #2
0
    def test_largest_army_is_updated(self):
        for i in range(6):
            if i % 2 == 1:
                # on player2 turn, don't do anything
                self.state.make_move(
                    CatanMove(self.state.board.get_robber_land()))
                continue

            # assert no-one has largest army yet
            player, threshold = self.state._get_largest_army_player_and_size()
            self.assertEqual(player, None)
            self.assertEqual(threshold, 2)

            # add knight dev-card
            self.players[0].add_unexposed_development_card(
                DevelopmentCard.Knight)

            # expose the knight card
            move = CatanMove(self.state.board.get_robber_land())
            move.development_card_to_be_exposed = DevelopmentCard.Knight
            self.state.make_move(move)

        player, threshold = self.state._get_largest_army_player_and_size()
        self.assertEqual(player, self.players[0])
        self.assertEqual(threshold, 3)
Beispiel #3
0
 def test_get_current_player(self):
     self.assertEqual(self.state.get_current_player(), self.players[0])
     self.state.make_move(CatanMove(self.state.board.get_robber_land()))
     self.state.make_random_move()
     self.assertEqual(self.state.get_current_player(), self.players[1])
     self.state.make_move(CatanMove(self.state.board.get_robber_land()))
     self.state.make_random_move()
     self.assertEqual(self.state.get_current_player(), self.players[0])
Beispiel #4
0
    def test_get_all_possible_path_moves(self):
        self.state.board.set_location(self.players[0], 0, Colony.Settlement)
        self.state.board.set_location(self.players[0], 7, Colony.Settlement)
        self.state.board.set_path(self.players[0], (3, 0), Road.Paved)
        self.state.board.set_path(self.players[0], (3, 7), Road.Paved)
        self.state.board.set_location(self.players[1], 39, Colony.Settlement)
        self.state.board.set_location(self.players[1], 40, Colony.Settlement)
        self.state.board.set_path(self.players[1], (39, 44), Road.Paved)
        self.state.board.set_path(self.players[1], (40, 44), Road.Paved)
        self.state.turns_count = 4

        empty_move = CatanMove(self.state.board.get_robber_land())
        moves = [empty_move]
        moves = self.state._get_all_possible_paths_moves(moves)
        self.assertEqual(moves, [empty_move])
        self.players[0].add_resource(Resource.Lumber)
        self.players[0].add_resource(Resource.Brick)

        # First player
        moves = [empty_move]
        moves = self.state._get_all_possible_paths_moves(moves)
        self.assertEqual(len(moves), 4)

        # move to next player
        self.state.make_move(empty_move)
        self.state.make_random_move(RandomMove(2, 0.1, self.state))

        self.players[1].add_resource(Resource.Lumber)
        self.players[1].add_resource(Resource.Brick)

        # Second player
        moves = [empty_move]
        moves = self.state._get_all_possible_paths_moves(moves)
        self.assertEqual(len(moves), 6)
Beispiel #5
0
    def get_random_move(self):
        if self.current_dice_number != 7:
            move = CatanMove(self.board.get_robber_land())
        else:
            moves = [
                CatanMove(land)
                for land in self.board.get_lands_to_place_robber_on()
            ]
            move = moves[np.random.randint(len(moves))]

        player = self.get_current_player()
        if player.has_unexposed_development_card():
            move = self._get_random_dev_card_exposure_move(move, player)
        move = self._get_random_trade_move(move, player)
        move = self._get_random_paths_move(move, player)
        move = self._get_random_settlements_move(move, player)
        move = self._get_random_cities_move(move, player)
        move = self._get_random_card_purchases_count_move(move, player)
        return move
Beispiel #6
0
 def test_get_all_possible_trade_moves_empty_move_not_enough_resources(
         self):
     empty_move = CatanMove(self.state.board.get_robber_land())
     moves = [empty_move]
     moves = self.state._get_all_possible_trade_moves(moves)
     assert moves == [empty_move]
     for _ in range(3):
         for resource in Resource:
             self.players[0].add_resource(resource)
         moves = self.state._get_all_possible_trade_moves(moves)
         assert moves == [empty_move]
Beispiel #7
0
    def test_unmake_move(self):
        self.players[0].add_resources_and_piece_for_settlement()
        move = CatanMove(self.state.board.get_robber_land())
        move.locations_to_be_set_to_settlements.append(0)
        self.state.make_move(move)

        self.assertListEqual(
            self.state.board.get_locations_colonised_by_player(
                self.players[0]), [0])

        self.state.unmake_move(move)
Beispiel #8
0
 def _pretend_to_make_a_move(self, move: CatanMove):
     player = self.get_current_player()
     player.update_resources(move.resources_updates,
                             AbstractPlayer.add_resource)
     previous_robber_land_placement = self.board.get_robber_land()
     self.board.set_robber_land(move.robber_placement_land)
     move.robber_placement_land = previous_robber_land_placement
     if move.development_card_to_be_exposed == DevelopmentCard.RoadBuilding:
         self._apply_road_building_dev_card_side_effect(1)
     elif move.development_card_to_be_exposed == DevelopmentCard.Monopoly:
         assert move.monopoly_card is not None
         for other_player in self.players:
             if other_player is player:
                 continue
             resource = move.monopoly_card
             resource_count = other_player.get_resource_count(resource)
             move.monopoly_card_debt[other_player] = resource_count
             other_player.remove_resource(resource, resource_count)
             player.add_resource(resource, resource_count)
     if move.development_card_to_be_exposed is not None:
         player.expose_development_card(move.development_card_to_be_exposed)
         self._unexposed_dev_cards_counters[
             move.development_card_to_be_exposed] -= 1
         assert self._unexposed_dev_cards_counters[
             move.development_card_to_be_exposed] >= 0
     for exchange in move.resources_exchanges:
         player.trade_resources(
             exchange.source_resource, exchange.target_resource,
             exchange.count,
             self._calc_curr_player_trade_ratio(exchange.source_resource))
     for path in move.paths_to_be_paved:
         self.board.set_path(player, path, Road.Paved)
         player.remove_resources_and_piece_for_road()
     for loc1 in move.locations_to_be_set_to_settlements:
         self.board.set_location(player, loc1, Colony.Settlement)
         player.remove_resources_and_piece_for_settlement()
     for loc2 in move.locations_to_be_set_to_cities:
         self.board.set_location(player, loc2, Colony.City)
         player.remove_resources_and_piece_for_city()
     for count in range(0, move.development_cards_to_be_purchased_count):
         player.remove_resources_for_development_card()
Beispiel #9
0
    def _update_largest_army(self, move: CatanMove):
        if move.development_card_to_be_exposed != DevelopmentCard.Knight:
            return

        player_with_largest_army, size_threshold = self._get_largest_army_player_and_size(
        )
        army_size = self.get_current_player().get_exposed_knights_count()

        if army_size > size_threshold:
            self._player_with_largest_army.append(
                (self.get_current_player(), army_size))
            move.did_get_largest_army_card = True
Beispiel #10
0
 def test_get_all_possible_trade_moves_single_trade(self):
     empty_move = CatanMove(self.state.board.get_robber_land())
     moves = [empty_move]
     moves = self.state._get_all_possible_trade_moves(moves)
     assert moves == [empty_move]
     self.players[0].add_resource(Resource.Lumber, 4)
     moves = self.state._get_all_possible_trade_moves(moves)
     assert moves[0] == empty_move
     assert len(moves[1].resources_exchanges) == 1
     assert len(moves[2].resources_exchanges) == 1
     assert len(moves[3].resources_exchanges) == 1
     assert len(moves[4].resources_exchanges) == 1
     assert len(moves) == 5
Beispiel #11
0
    def _update_longest_road(self, move: CatanMove):
        if len(move.paths_to_be_paved) == 0:
            return

        player_with_longest_road, length_threshold = self._get_longest_road_player_and_length(
        )
        longest_road_length = self.board.get_longest_road_length_of_player(
            self.get_current_player())

        if longest_road_length > length_threshold:
            self._player_with_longest_road.append(
                (self.get_current_player(), longest_road_length))
            move.did_get_longest_road_card = True
Beispiel #12
0
    def _get_random_cities_move(self, move: CatanMove, player):
        self._pretend_to_make_a_move(move)
        locations = self.board.get_settlements_by_player(player)
        num_cities = min(len(locations), player.amount_of_cities_can_afford())
        new_cities_locations = []
        if num_cities > 0:
            num_cities = np.random.randint(num_cities)

            for i in range(num_cities):
                j = np.random.randint(len(locations))
                new_cities_locations.append(locations.pop(j))
        self._unpretend_to_make_a_move(move)
        move.locations_to_be_set_to_cities = new_cities_locations
        return move
Beispiel #13
0
    def test_get_all_possible_development_cards_exposure_moves(self):
        self.state.board.set_location(self.players[0], 0, Colony.Settlement)
        self.state.board.set_location(self.players[0], 7, Colony.Settlement)
        self.state.board.set_path(self.players[0], (3, 0), Road.Paved)
        self.state.board.set_path(self.players[0], (3, 7), Road.Paved)
        self.state.board.set_location(self.players[1], 39, Colony.Settlement)
        self.state.board.set_location(self.players[1], 40, Colony.Settlement)
        self.state.board.set_path(self.players[1], (39, 44), Road.Paved)
        self.state.board.set_path(self.players[1], (40, 44), Road.Paved)
        self.state.turns_count = 4

        empty_move = CatanMove(self.state.board.get_robber_land())
        moves = [empty_move]
        moves = self.state._get_all_possible_development_cards_exposure_moves(
            moves)
        self.assertEqual(moves, [empty_move])
        self.players[0].add_unexposed_development_card(
            DevelopmentCard.RoadBuilding)
        self.players[0].add_unexposed_development_card(
            DevelopmentCard.YearOfPlenty)
        self.players[0].add_unexposed_development_card(
            DevelopmentCard.Monopoly)
        self.players[0].add_unexposed_development_card(DevelopmentCard.Knight)
        self.players[0].add_unexposed_development_card(
            DevelopmentCard.VictoryPoint)
        moves = self.state._get_all_possible_development_cards_exposure_moves(
            moves)
        self.assertEqual(moves[0], empty_move)
        all_dev_cards = [move.development_card_to_be_exposed for move in moves]
        for dev_card_type in DevelopmentCard:
            assert dev_card_type in all_dev_cards
        self.assertEqual(len(moves), 41)
        knight_dev_applied_moves = [
            move for move in moves
            if move.development_card_to_be_exposed == DevelopmentCard.Knight
        ]
        self.assertEqual(len(knight_dev_applied_moves), 18)
        y_o_p_dev_applied_moves = [
            move for move in moves if move.development_card_to_be_exposed ==
            DevelopmentCard.YearOfPlenty
        ]
        self.assertEqual(len(y_o_p_dev_applied_moves), 15)
        monopoly_dev_applied_moves = [
            move for move in moves
            if move.development_card_to_be_exposed == DevelopmentCard.Monopoly
        ]
        self.assertEqual(len(monopoly_dev_applied_moves), 5)
Beispiel #14
0
 def _get_random_paths_move(self, move: CatanMove, player):
     min_paths = 0
     paving_option = {}
     if move.development_card_to_be_exposed == DevelopmentCard.RoadBuilding:
         min_paths = 2
     self._pretend_to_make_a_move(move)
     if player.can_pave_road():
         max_paths = player.amount_of_roads_can_afford()
         if min_paths < max_paths:
             num_roads_to_pave = np.random.randint(min_paths, max_paths)
         else:
             num_roads_to_pave = np.random.randint(max_paths)
         paving_option = frozenset(
             self._get_random_paving_option(num_roads_to_pave, player))
     self._unpretend_to_make_a_move(move)
     move.paths_to_be_paved = paving_option
     return move
Beispiel #15
0
 def _add_settlements_to_initialisation_moves(self):
     empty_move = CatanMove(self.board.get_robber_land())
     moves = [empty_move]
     moves = self._get_all_possible_settlements_moves(moves)
     moves.remove(empty_move)
     for move in moves:
         assert len(move.resources_exchanges) == 0
         assert move.development_card_to_be_exposed is None
         assert len(move.paths_to_be_paved) == 0
         assert len(move.locations_to_be_set_to_settlements) == 1
         assert len(move.locations_to_be_set_to_cities) == 0
         assert move.development_cards_to_be_purchased_count == 0
         assert not move.did_get_largest_army_card
         assert not move.did_get_longest_road_card
         assert (move.robber_placement_land == self.board.get_robber_land()
                 or move.robber_placement_land is None)
     return moves
Beispiel #16
0
 def test_get_all_possible_trade_moves_different_ratio_non_generic(self):
     empty_move = CatanMove(self.state.board.get_robber_land())
     moves = [empty_move]
     moves = self.state._get_all_possible_trade_moves(moves)
     assert moves == [empty_move]
     self.players[0].add_resource(Resource.Lumber, 1)
     moves = self.state._get_all_possible_trade_moves(moves)
     assert moves == [empty_move]
     self.players[0].add_resource(Resource.Lumber, 1)
     self.state.board._locations_by_harbors[Harbor.HarborLumber].append(0)
     self.state.board.set_location(self.players[0], 0, Colony.Settlement)
     moves = self.state._get_all_possible_trade_moves(moves)
     assert moves[0] == empty_move
     assert len(moves[1].resources_exchanges) == 1
     assert len(moves[2].resources_exchanges) == 1
     assert len(moves[3].resources_exchanges) == 1
     assert len(moves[4].resources_exchanges) == 1
     assert len(moves) == 5
Beispiel #17
0
 def _unpretend_to_make_a_move(self, move: CatanMove):
     player = self.get_current_player()
     for count in range(0, move.development_cards_to_be_purchased_count):
         player.add_resources_for_development_card()
     for loc2 in move.locations_to_be_set_to_cities:
         self.board.set_location(player, loc2, Colony.Settlement)
         player.add_resources_and_piece_for_city()
     for loc1 in move.locations_to_be_set_to_settlements:
         self.board.set_location(player, loc1, Colony.Uncolonised)
         player.add_resources_and_piece_for_settlement()
     for path in move.paths_to_be_paved:
         self.board.set_path(player, path, Road.Unpaved)
         player.add_resources_and_piece_for_road()
     for exchange in move.resources_exchanges:
         player.un_trade_resources(
             exchange.source_resource, exchange.target_resource,
             exchange.count,
             self._calc_curr_player_trade_ratio(exchange.source_resource))
     if move.development_card_to_be_exposed is not None:
         player.un_expose_development_card(
             move.development_card_to_be_exposed)
         self._unexposed_dev_cards_counters[
             move.development_card_to_be_exposed] += 1
     if move.development_card_to_be_exposed == DevelopmentCard.RoadBuilding:
         self._revert_road_building_dev_card_side_effect(1)
     elif move.development_card_to_be_exposed == DevelopmentCard.Monopoly:
         assert move.monopoly_card is not None
         for other_player in self.players:
             if other_player is player:
                 continue
             resource = move.monopoly_card
             resource_count = move.monopoly_card_debt[other_player]
             other_player.add_resource(resource, resource_count)
             player.remove_resource(resource, resource_count)
     robber_land_placement_to_undo = self.board.get_robber_land(
     )  # this is done just in case, probably redundant
     self.board.set_robber_land(move.robber_placement_land)
     move.robber_placement_land = robber_land_placement_to_undo  # this is done just in case, probably redundant
     player.update_resources(move.resources_updates,
                             AbstractPlayer.remove_resource)
Beispiel #18
0
 def _get_random_dev_card_exposure_move(self, move: CatanMove,
                                        player) -> CatanMove:
     cards = [None]
     for card, a in player.unexposed_development_cards.items():
         if card != DevelopmentCard.VictoryPoint and a > 0:
             cards.append(card)
     dev_card = np.random.choice(cards)
     if dev_card == DevelopmentCard.Knight and move.robber_placement_land == self.board.get_robber_land(
     ):
         lands = self.board.get_lands_to_place_robber_on()
         land = lands[np.random.randint(len(lands))]
         move.robber_placement_land = land
     elif dev_card == DevelopmentCard.Monopoly:
         num = np.random.randint(5)
         if num == 0:
             chosen_resource = Resource.Brick
         elif num == 1:
             chosen_resource = Resource.Lumber
         elif num == 2:
             chosen_resource = Resource.Wool
         elif num == 3:
             chosen_resource = Resource.Grain
         else:
             chosen_resource = Resource.Ore
         move.monopoly_card = chosen_resource
     elif dev_card == DevelopmentCard.YearOfPlenty:
         chosen_resources = []
         for i in range(2):
             r = np.random.randint(5)
             if r == 0:
                 chosen_resources.append(Resource.Brick)
             elif r == 1:
                 chosen_resources.append(Resource.Lumber)
             elif r == 2:
                 chosen_resources.append(Resource.Wool)
             elif r == 3:
                 chosen_resources.append(Resource.Grain)
             else:
                 chosen_resources.append(Resource.Ore)
         if chosen_resources[0] != chosen_resources[
                 1]:  # two different cards
             move.resources_updates[chosen_resources[0]] = 1
             move.resources_updates[chosen_resources[1]] = 1
         else:  # same card twice
             move.resources_updates[chosen_resources[0]] = 2
     move.development_card_to_be_exposed = dev_card
     return move
Beispiel #19
0
 def test_get_all_possible_trade_moves_empty_move_no_resources(self):
     empty_move = CatanMove(self.state.board.get_robber_land())
     moves = [empty_move]
     moves = self.state._get_all_possible_trade_moves(moves)
     assert moves == [empty_move]
Beispiel #20
0
    def test_probability_calculation_given_card_used(self):
        # given this board
        self.state.board.set_location(self.players[0], 0, Colony.Settlement)
        self.state.board.set_location(self.players[0], 7, Colony.Settlement)
        self.state.board.set_path(self.players[0], (3, 0), Road.Paved)
        self.state.board.set_path(self.players[0], (3, 7), Road.Paved)
        self.state.board.set_location(self.players[1], 39, Colony.Settlement)
        self.state.board.set_location(self.players[1], 40, Colony.Settlement)
        self.state.board.set_path(self.players[1], (39, 44), Road.Paved)
        self.state.board.set_path(self.players[1], (40, 44), Road.Paved)
        self.state.turns_count = 4

        # buy two knight cards
        self.state.make_move(CatanMove(self.state.board.get_robber_land()))
        purchase_count = 2
        two_knight_cards_expected_probability = (15 / 26) * (14 / 25)
        two_knights_counters = {
            card: purchase_count if card is DevelopmentCard.Knight else 0
            for card in DevelopmentCard
        }
        self.state.make_random_move(
            RandomMove(
                2, two_knight_cards_expected_probability *
                self.state.probabilities_by_dice_values[2], self.state,
                two_knights_counters))

        # make empty move
        self.state.make_move(CatanMove(self.state.board.get_robber_land()))
        self.state.make_random_move(
            RandomMove(2, self.state.probabilities_by_dice_values[2],
                       self.state))

        # expose one knight
        move = CatanMove(self.state.board._lands[0])
        move.development_card_to_be_exposed = DevelopmentCard.Knight
        self.state.make_move(move)
        self.state.make_random_move(
            RandomMove(2, self.state.probabilities_by_dice_values[2],
                       self.state))

        # get all purchase options of two cards
        options = self.state._get_all_possible_development_cards_purchase_options(
            purchase_count)

        # assert the number of options is (25 choose 2) (because there are 25 unexposed cards)
        number_of_cards_combinations = sum(
            1 for _ in combinations_with_replacement(DevelopmentCard,
                                                     purchase_count))
        self.assertEqual(len(options), number_of_cards_combinations)

        # assert all options are different
        for option1, option2 in combinations(options, 2):
            self.assertNotEqual(option1, option2)
            self.assertNotEqual(option1.purchased_cards_counters,
                                option2.purchased_cards_counters)

        # assert all probabilities are valid probabilities, and there are no moves where probability = 0
        for option in options:
            self.assertLess(option.probability, 1)
            self.assertGreater(option.probability, 0)

        # this assertion is just to make sure I'm testing the probability of the right options
        assert options[0].purchased_cards_counters == two_knights_counters

        # assert the probability is right, given one knight was exposed
        two_knight_cards_expected_probability = (14 / 25) * (13 / 24)
        two_knight_cards_actual_probability = options[0].probability
        self.assertAlmostEqual(two_knight_cards_expected_probability,
                               two_knight_cards_actual_probability)