コード例 #1
0
def player_features(game: Game, p0_color: Color):
    # P0_ACTUAL_VPS
    # P{i}_PUBLIC_VPS, P1_PUBLIC_VPS, ...
    # P{i}_HAS_ARMY, P{i}_HAS_ROAD, P1_HAS_ARMY, ...
    # P{i}_ROADS_LEFT, P{i}_SETTLEMENTS_LEFT, P{i}_CITIES_LEFT, P1_...
    # P{i}_HAS_ROLLED, P{i}_LONGEST_ROAD_LENGTH
    features = dict()
    for i, color in iter_players(game.state.colors, p0_color):
        key = player_key(game.state, color)
        if color == p0_color:
            features["P0_ACTUAL_VPS"] = game.state.player_state[
                key + "_ACTUAL_VICTORY_POINTS"]

        features[f"P{i}_PUBLIC_VPS"] = game.state.player_state[
            key + "_VICTORY_POINTS"]
        features[f"P{i}_HAS_ARMY"] = game.state.player_state[key + "_HAS_ARMY"]
        features[f"P{i}_HAS_ROAD"] = game.state.player_state[key + "_HAS_ROAD"]
        features[f"P{i}_ROADS_LEFT"] = game.state.player_state[
            key + "_ROADS_AVAILABLE"]
        features[f"P{i}_SETTLEMENTS_LEFT"] = game.state.player_state[
            key + "_SETTLEMENTS_AVAILABLE"]
        features[f"P{i}_CITIES_LEFT"] = game.state.player_state[
            key + "_CITIES_AVAILABLE"]
        features[f"P{i}_HAS_ROLLED"] = game.state.player_state[key +
                                                               "_HAS_ROLLED"]
        features[f"P{i}_LONGEST_ROAD_LENGTH"] = game.state.player_state[
            key + "_LONGEST_ROAD_LENGTH"]

    return features
コード例 #2
0
def simple_feature_vector(game, p0_color):
    key = player_key(game.state, p0_color)
    f_public_vps = game.state.player_state[f"P0_VICTORY_POINTS"]
    f_enemy_public_vps = game.state.player_state[f"P1_VICTORY_POINTS"]

    production_features = build_production_features(True)
    our_production_sample = production_features(game, p0_color)
    enemy_production_sample = production_features(game, p0_color)

    f_longest_road_length = game.state.player_state["P0_LONGEST_ROAD_LENGTH"]
    f_enemy_longest_road_length = game.state.player_state["P1_LONGEST_ROAD_LENGTH"]

    hand_sample = resource_hand_features(game, p0_color)
    distance_to_city = (
        max(2 - hand_sample["P0_WHEAT_IN_HAND"], 0)
        + max(3 - hand_sample["P0_ORE_IN_HAND"], 0)
    ) / 5.0  # 0 means good. 1 means bad.
    distance_to_settlement = (
        max(1 - hand_sample["P0_WHEAT_IN_HAND"], 0)
        + max(1 - hand_sample["P0_SHEEP_IN_HAND"], 0)
        + max(1 - hand_sample["P0_BRICK_IN_HAND"], 0)
        + max(1 - hand_sample["P0_WOOD_IN_HAND"], 0)
    ) / 4.0  # 0 means good. 1 means bad.
    f_hand_synergy = (2 - distance_to_city - distance_to_settlement) / 2

    f_num_in_hand = player_num_resource_cards(game.state, p0_color)

    # blockability
    buildings = game.state.buildings_by_color[p0_color]
    owned_nodes = buildings[BuildingType.SETTLEMENT] + buildings[BuildingType.CITY]
    owned_tiles = set()
    for n in owned_nodes:
        owned_tiles.update(game.state.board.map.adjacent_tiles[n])
    # f_num_tiles = len(owned_tiles)

    # f_num_buildable_nodes = len(game.state.board.buildable_node_ids(p0_color))
    # f_hand_devs = player_num_dev_cards(game.state, p0_color)

    f_army_size = game.state.player_state[f"P1_PLAYED_KNIGHT"]
    f_enemy_army_size = game.state.player_state[f"P0_PLAYED_KNIGHT"]

    vector = {
        # Where to place. Note winning is best at all costs
        "PUBLIC_VPS": f_public_vps,
        "ENEMY_PUBLIC_VPS": f_enemy_public_vps,
        # "NUM_TILES": f_num_tiles,
        # "BUILDABLE_NODES": f_num_buildable_nodes,
        # Hand, when to hold and when to use.
        "HAND_SYNERGY": f_hand_synergy,
        "HAND_RESOURCES": f_num_in_hand,
        # "HAND_DEVS": f_hand_devs,
        # Other
        "ROAD_LENGTH": f_longest_road_length,
        "ENEMY_ROAD_LENGTH": f_enemy_longest_road_length,
        "ARMY_SIZE": f_army_size,
        "ENEMY_ARMY_SIZE": f_enemy_army_size,
    }
    vector = {**vector, **our_production_sample}
    vector = {**vector, **enemy_production_sample}
    return vector
コード例 #3
0
def city_possibilities(state, color) -> List[Action]:
    key = player_key(state, color)

    has_money = player_resource_freqdeck_contains(state, color,
                                                  CITY_COST_FREQDECK)
    has_cities_available = state.player_state[f"{key}_CITIES_AVAILABLE"] > 0

    if has_money and has_cities_available:
        return [
            Action(color, ActionType.BUILD_CITY,
                   node_id) for node_id in get_player_buildings(
                       state, color, BuildingType.SETTLEMENT)
        ]
    else:
        return []
コード例 #4
0
def road_building_possibilities(state, color) -> List[Action]:
    key = player_key(state, color)

    has_money = player_resource_freqdeck_contains(state, color,
                                                  ROAD_COST_FREQDECK)
    has_roads_available = state.player_state[f"{key}_ROADS_AVAILABLE"] > 0

    if has_money and has_roads_available:
        buildable_edges = state.board.buildable_edges(color)
        return [
            Action(color, ActionType.BUILD_ROAD, edge)
            for edge in buildable_edges
        ]
    else:
        return []
コード例 #5
0
    def winning_color(self) -> Union[Color, None]:
        """Gets winning color

        Returns:
            Union[Color, None]: Might be None if game truncated by TURNS_LIMIT
        """
        result = None
        for color in self.state.colors:
            key = player_key(self.state, color)
            if (
                self.state.player_state[f"{key}_ACTUAL_VICTORY_POINTS"]
                >= self.vps_to_win
            ):
                result = color

        return result
コード例 #6
0
    def decide(self, game: Game, playable_actions):
        if len(playable_actions) == 1:
            return playable_actions[0]

        best_value = float("-inf")
        best_actions = []
        for action in playable_actions:
            game_copy = game.copy()
            game_copy.execute(action)

            key = player_key(game_copy.state, self.color)
            value = game_copy.state.player_state[f"{key}_ACTUAL_VICTORY_POINTS"]
            if value == best_value:
                best_actions.append(action)
            if value > best_value:
                best_value = value
                best_actions = [action]

        return random.choice(best_actions)
コード例 #7
0
def resource_hand_features(game: Game, p0_color: Color):
    # P0_WHEATS_IN_HAND, P0_WOODS_IN_HAND, ...
    # P0_ROAD_BUILDINGS_IN_HAND, P0_KNIGHT_IN_HAND, ..., P0_VPS_IN_HAND
    # P0_ROAD_BUILDINGS_PLAYABLE, P0_KNIGHT_PLAYABLE, ...
    # P0_ROAD_BUILDINGS_PLAYED, P0_KNIGHT_PLAYED, ...

    # P1_ROAD_BUILDINGS_PLAYED, P1_KNIGHT_PLAYED, ...
    # TODO: P1_WHEATS_INFERENCE, P1_WOODS_INFERENCE, ...
    # TODO: P1_ROAD_BUILDINGS_INFERENCE, P1_KNIGHT_INFERENCE, ...

    state = game.state
    player_state = state.player_state

    features = {}
    for i, color in iter_players(game.state.colors, p0_color):
        key = player_key(game.state, color)

        if color == p0_color:
            for resource in RESOURCES:
                features[f"P0_{resource}_IN_HAND"] = player_state[
                    key + f"_{resource}_IN_HAND"]
            for card in DEVELOPMENT_CARDS:
                features[f"P0_{card}_IN_HAND"] = player_state[
                    key + f"_{card}_IN_HAND"]
            features[f"P0_HAS_PLAYED_DEVELOPMENT_CARD_IN_TURN"] = player_state[
                key + "_HAS_PLAYED_DEVELOPMENT_CARD_IN_TURN"]

        for card in DEVELOPMENT_CARDS:
            if card == VICTORY_POINT:
                continue  # cant play VPs
            features[f"P{i}_{card}_PLAYED"] = player_state[key +
                                                           f"_PLAYED_{card}"]

        features[f"P{i}_NUM_RESOURCES_IN_HAND"] = player_num_resource_cards(
            state, color)
        features[f"P{i}_NUM_DEVS_IN_HAND"] = player_num_dev_cards(state, color)

    return features
コード例 #8
0
def settlement_possibilities(state,
                             color,
                             initial_build_phase=False) -> List[Action]:
    if initial_build_phase:
        buildable_node_ids = state.board.buildable_node_ids(
            color, initial_build_phase=True)
        return [
            Action(color, ActionType.BUILD_SETTLEMENT, node_id)
            for node_id in buildable_node_ids
        ]
    else:
        key = player_key(state, color)
        has_money = player_resource_freqdeck_contains(
            state, color, SETTLEMENT_COST_FREQDECK)
        has_settlements_available = (
            state.player_state[f"{key}_SETTLEMENTS_AVAILABLE"] > 0)
        if has_money and has_settlements_available:
            buildable_node_ids = state.board.buildable_node_ids(color)
            return [
                Action(color, ActionType.BUILD_SETTLEMENT, node_id)
                for node_id in buildable_node_ids
            ]
        else:
            return []
コード例 #9
0
    def fn(game, p0_color):
        production_features = build_production_features(True)
        our_production_sample = production_features(game, p0_color)
        enemy_production_sample = production_features(game, p0_color)
        production = value_production(our_production_sample, "P0")
        enemy_production = value_production(enemy_production_sample, "P1",
                                            False)

        key = player_key(game.state, p0_color)
        longest_road_length = get_longest_road_length(game.state, p0_color)

        reachability_sample = reachability_features(game, p0_color, 2)
        features = [
            f"P0_0_ROAD_REACHABLE_{resource}" for resource in RESOURCES
        ]
        reachable_production_at_zero = sum(
            [reachability_sample[f] for f in features])
        features = [
            f"P0_1_ROAD_REACHABLE_{resource}" for resource in RESOURCES
        ]
        reachable_production_at_one = sum(
            [reachability_sample[f] for f in features])

        hand_sample = resource_hand_features(game, p0_color)
        features = [f"P0_{resource}_IN_HAND" for resource in RESOURCES]
        distance_to_city = (max(2 - hand_sample["P0_WHEAT_IN_HAND"], 0) +
                            max(3 - hand_sample["P0_ORE_IN_HAND"],
                                0)) / 5.0  # 0 means good. 1 means bad.
        distance_to_settlement = (max(1 - hand_sample["P0_WHEAT_IN_HAND"], 0) +
                                  max(1 - hand_sample["P0_SHEEP_IN_HAND"], 0) +
                                  max(1 - hand_sample["P0_BRICK_IN_HAND"], 0) +
                                  max(1 - hand_sample["P0_WOOD_IN_HAND"],
                                      0)) / 4.0  # 0 means good. 1 means bad.
        hand_synergy = (2 - distance_to_city - distance_to_settlement) / 2

        num_in_hand = player_num_resource_cards(game.state, p0_color)
        discard_penalty = params["discard_penalty"] if num_in_hand > 7 else 0

        # blockability
        buildings = game.state.buildings_by_color[p0_color]
        owned_nodes = buildings[BuildingType.SETTLEMENT] + buildings[
            BuildingType.CITY]
        owned_tiles = set()
        for n in owned_nodes:
            owned_tiles.update(game.state.board.map.adjacent_tiles[n])
        num_tiles = len(owned_tiles)

        # TODO: Simplify to linear(?)
        num_buildable_nodes = len(
            game.state.board.buildable_node_ids(p0_color))
        longest_road_factor = (params["longest_road"]
                               if num_buildable_nodes == 0 else 0.1)

        return float(
            game.state.player_state[f"{key}_VICTORY_POINTS"] *
            params["public_vps"] + production * params["production"] +
            enemy_production * params["enemy_production"] +
            reachable_production_at_zero * params["reachable_production_0"] +
            reachable_production_at_one * params["reachable_production_1"] +
            hand_synergy * params["hand_synergy"] +
            num_buildable_nodes * params["buildable_nodes"] +
            num_tiles * params["num_tiles"] +
            num_in_hand * params["hand_resources"] + discard_penalty +
            longest_road_length * longest_road_factor +
            player_num_dev_cards(game.state, p0_color) * params["hand_devs"] +
            get_played_dev_cards(game.state, p0_color, "KNIGHT") *
            params["army_size"])