Ejemplo n.º 1
0
def test_play_monopoly_player_steals_cards():
    player_to_act = SimplePlayer(Color.RED)
    player_to_steal_from_1 = SimplePlayer(Color.BLUE)
    player_to_steal_from_2 = SimplePlayer(Color.ORANGE)
    players = [player_to_act, player_to_steal_from_1, player_to_steal_from_2]
    state = State(players)

    player_deck_replenish(state, player_to_act.color, MONOPOLY)
    player_deck_replenish(state, player_to_steal_from_1.color, ORE, 3)
    player_deck_replenish(state, player_to_steal_from_1.color, WHEAT, 1)
    player_deck_replenish(state, player_to_steal_from_2.color, ORE, 2)
    player_deck_replenish(state, player_to_steal_from_2.color, WHEAT, 1)

    action_to_execute = Action(player_to_act.color, ActionType.PLAY_MONOPOLY,
                               ORE)
    apply_action(state, action_to_execute)

    assert player_num_resource_cards(state, player_to_act.color, ORE) == 5
    assert player_num_resource_cards(state, player_to_steal_from_1.color,
                                     ORE) == 0
    assert player_num_resource_cards(state, player_to_steal_from_1.color,
                                     WHEAT) == 1
    assert player_num_resource_cards(state, player_to_steal_from_2.color,
                                     ORE) == 0
    assert player_num_resource_cards(state, player_to_steal_from_2.color,
                                     WHEAT) == 1
Ejemplo n.º 2
0
def maritime_trade_possibilities(state, color) -> List[Action]:
    trade_offers = set()

    # Get lowest rate per resource
    port_resources = set(state.board.get_player_port_resources(color))
    rates: Dict[FastResource, int] = {
        WOOD: 4,
        BRICK: 4,
        SHEEP: 4,
        WHEAT: 4,
        ORE: 4
    }
    if None in port_resources:
        rates = {WOOD: 3, BRICK: 3, SHEEP: 3, WHEAT: 3, ORE: 3}
    for resource in port_resources:
        if resource != None:
            rates[resource] = 2

    # For resource in hand
    for resource in RESOURCES:
        amount = player_num_resource_cards(state, color, resource)
        if amount >= rates[resource]:
            resource_out: List[Any] = [resource] * rates[resource]
            resource_out += [None] * (4 - rates[resource])
            for j_resource in RESOURCES:
                if (resource != j_resource and freqdeck_count(
                        state.resource_freqdeck, j_resource) > 0):
                    trade_offer = tuple(resource_out + [j_resource])
                    trade_offers.add(trade_offer)

    return list(
        map(lambda t: Action(color, ActionType.MARITIME_TRADE, t),
            trade_offers))
Ejemplo n.º 3
0
def robber_possibilities(state, color) -> List[Action]:
    actions = []
    for (coordinate, tile) in state.board.map.land_tiles.items():
        if coordinate == state.board.robber_coordinate:
            continue  # ignore. must move robber.

        # each tile can yield a (move-but-cant-steal) action or
        #   several (move-and-steal-from-x) actions.
        to_steal_from = set()  # set of player_indexs
        for _, node_id in tile.nodes.items():
            building = state.board.buildings.get(node_id, None)
            if building is not None:
                candidate_color = building[0]
                if (player_num_resource_cards(state, candidate_color) >= 1
                        and color != candidate_color  # can't play yourself
                    ):
                    to_steal_from.add(candidate_color)

        if len(to_steal_from) == 0:
            actions.append(
                Action(color, ActionType.MOVE_ROBBER,
                       (coordinate, None, None)))
        else:
            for enemy_color in to_steal_from:
                actions.append(
                    Action(color, ActionType.MOVE_ROBBER,
                           (coordinate, enemy_color, None)))

    return actions
Ejemplo n.º 4
0
def test_cant_buy_more_than_max_card():
    players = [SimplePlayer(Color.RED), SimplePlayer(Color.BLUE)]
    state = State(players)

    with pytest.raises(ValueError):  # not enough money
        apply_action(
            state,
            Action(players[0].color, ActionType.BUY_DEVELOPMENT_CARD, None))

    player_deck_replenish(state, players[0].color, SHEEP, 26)
    player_deck_replenish(state, players[0].color, WHEAT, 26)
    player_deck_replenish(state, players[0].color, ORE, 26)

    for i in range(25):
        apply_action(
            state,
            Action(players[0].color, ActionType.BUY_DEVELOPMENT_CARD, None))

    # assert must have all victory points
    assert player_num_dev_cards(state, players[0].color) == 25
    assert get_dev_cards_in_hand(state, players[0].color, VICTORY_POINT) == 5

    with pytest.raises(ValueError):  # not enough cards in bank
        apply_action(
            state,
            Action(players[0].color, ActionType.BUY_DEVELOPMENT_CARD, None))

    assert player_num_resource_cards(state, players[0].color) == 3
Ejemplo n.º 5
0
def test_buying_road_is_payed_for():
    players = [SimplePlayer(Color.RED), SimplePlayer(Color.BLUE)]
    state = State(players)

    state.is_initial_build_phase = False
    state.board.build_settlement(players[0].color, 3, True)
    action = Action(players[0].color, ActionType.BUILD_ROAD, (3, 4))
    player_freqdeck_add(
        state,
        players[0].color,
        freqdeck_from_listdeck([WOOD, BRICK]),
    )
    apply_action(state, action)

    assert player_num_resource_cards(state, players[0].color, WOOD) == 0
    assert player_num_resource_cards(state, players[0].color, BRICK) == 0
Ejemplo n.º 6
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
Ejemplo n.º 7
0
def test_moving_robber_steals_correctly():
    players = [SimplePlayer(Color.RED), SimplePlayer(Color.BLUE)]
    state = State(players)

    player_deck_replenish(state, players[1].color, WHEAT, 1)
    state.board.build_settlement(Color.BLUE, 3, initial_build_phase=True)

    action = Action(players[0].color, ActionType.MOVE_ROBBER,
                    ((2, 0, -2), None, None))
    apply_action(state, action)
    assert player_num_resource_cards(state, players[0].color) == 0
    assert player_num_resource_cards(state, players[1].color) == 1

    action = Action(
        players[0].color,
        ActionType.MOVE_ROBBER,
        ((0, 0, 0), players[1].color, WHEAT),
    )
    apply_action(state, action)
    assert player_num_resource_cards(state, players[0].color) == 1
    assert player_num_resource_cards(state, players[1].color) == 0
Ejemplo n.º 8
0
def test_play_year_of_plenty_gives_player_resources():
    players = [SimplePlayer(Color.RED), SimplePlayer(Color.BLUE)]
    state = State(players)

    player_to_act = players[0]
    player_deck_replenish(state, player_to_act.color, YEAR_OF_PLENTY, 1)

    action_to_execute = Action(player_to_act.color,
                               ActionType.PLAY_YEAR_OF_PLENTY, [ORE, WHEAT])

    apply_action(state, action_to_execute)

    for card_type in RESOURCES:
        if card_type == ORE or card_type == WHEAT:
            assert player_num_resource_cards(state, player_to_act.color,
                                             card_type) == 1
            assert freqdeck_count(state.resource_freqdeck, card_type) == 18
        else:
            assert player_num_resource_cards(state, player_to_act.color,
                                             card_type) == 0
            assert freqdeck_count(state.resource_freqdeck, card_type) == 19
    assert get_dev_cards_in_hand(state, player_to_act.color,
                                 YEAR_OF_PLENTY) == 0
Ejemplo n.º 9
0
def test_trade_execution():
    players = [
        SimplePlayer(Color.RED),
        SimplePlayer(Color.BLUE),
        SimplePlayer(Color.WHITE),
        SimplePlayer(Color.ORANGE),
    ]
    state = State(players)

    player_deck_replenish(state, players[0].color, BRICK, 4)
    trade_offer = tuple([BRICK] * 4 + [ORE])
    action = Action(players[0].color, ActionType.MARITIME_TRADE, trade_offer)
    apply_action(state, action)

    assert player_num_resource_cards(state, players[0].color) == 1
    assert sum(state.resource_freqdeck) == 19 * 5 + 4 - 1
Ejemplo n.º 10
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
Ejemplo n.º 11
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"])