Exemple #1
0
 def opposite_edge(cls, road_position: CoordinateWithSide):
     if road_position.side == Side.TOP:
         return CoordinateWithSide(
             Coordinate(road_position.coordinate.row - 1,
                        road_position.coordinate.column), Side.BOTTOM)
     elif road_position.side == Side.RIGHT:
         return CoordinateWithSide(
             Coordinate(road_position.coordinate.row,
                        road_position.coordinate.column + 1), Side.LEFT)
     elif road_position.side == Side.BOTTOM:
         return CoordinateWithSide(
             Coordinate(road_position.coordinate.row + 1,
                        road_position.coordinate.column), Side.TOP)
     elif road_position.side == Side.LEFT:
         return CoordinateWithSide(
             Coordinate(road_position.coordinate.row,
                        road_position.coordinate.column - 1), Side.RIGHT)
Exemple #2
0
    def find_meeples(cls, game_state: CarcassonneGameState, farm: Farm) -> [[MeeplePosition]]:
        meeples: [[MeeplePosition]] = [[] for _ in range(game_state.players)]

        farmer_connection_with_coordinate: FarmerConnectionWithCoordinate
        for farmer_connection_with_coordinate in farm.farmer_connections_with_coordinate:
            farmer_position: CoordinateWithSide = CoordinateWithSide(farmer_connection_with_coordinate.coordinate, farmer_connection_with_coordinate.farmer_connection.farmer_positions[0])
            for player in range(game_state.players):
                meeple_position: MeeplePosition
                for meeple_position in game_state.placed_meeples[player]:
                    if farmer_position == meeple_position.coordinate_with_side:
                        meeples[player].append(meeple_position)

        return meeples
Exemple #3
0
    def outgoing_roads_for_position(
            cls, game_state: CarcassonneGameState,
            road_position: CoordinateWithSide) -> [CoordinateWithSide]:
        tile: Tile = game_state.get_tile(road_position.coordinate.row,
                                         road_position.coordinate.column)
        if tile is None:
            return []

        roads: [CoordinateWithSide] = []

        connection: Connection
        for connection in tile.road:
            if connection.a == road_position.side or connection.b == road_position.side:
                if connection.a != Side.CENTER:
                    roads.append(
                        CoordinateWithSide(coordinate=road_position.coordinate,
                                           side=connection.a))
                if connection.b != Side.CENTER:
                    roads.append(
                        CoordinateWithSide(coordinate=road_position.coordinate,
                                           side=connection.b))

        return roads
Exemple #4
0
    def apply_action2(cls, game_state: CarcassonneGameState,
                      a: int) -> CarcassonneGameState:
        new_game_state: CarcassonneGameState = copy.deepcopy(game_state)

        action = Action.game_phase(a)
        if action is not game_state.phase: raise Exception("invalid action")

        if action == GamePhase.TILES:
            new_game_state.phase = GamePhase.ROTATION  # skip TYPE
            column = a % board_size
            row = int((a - column) / board_size)
            new_game_state.position = (row, column)

            new_game_state.next_tile_action = TileAction(
                new_game_state.next_tile, Coordinate(row, column), 0)

        if action == GamePhase.TYPE:
            # skip -> not needed because it is inferred by the previous drawn card
            new_game_state.phase = GamePhase.ROTATION
            pass
        if action == GamePhase.ROTATION:
            new_game_state.phase = GamePhase.MEEPLES
            rotation = a - ((board_size * board_size) + tile_types)
            new_game_state.next_tile_action.tile_rotations = rotation

            cls.play_tile(game_state=new_game_state,
                          tile_action=new_game_state.next_tile_action)
        if action == GamePhase.MEEPLES:
            pos = a - ((board_size * board_size) + tile_types + rotations)

            # pos 5 = place no meeple
            if pos != 5:
                coordinate_with_side = CoordinateWithSide(
                    new_game_state.next_tile_action.coordinate,
                    Side.from_number(pos))

                meeple = MeepleAction(MeepleType.NORMAL, coordinate_with_side)

                cls.play_meeple(game_state=new_game_state,
                                meeple_action=meeple)
                cls.remove_meeples_and_update_score(game_state=new_game_state)

            cls.draw_tile(game_state=new_game_state)
            # tiles phase set by next_player
            cls.next_player(game_state=new_game_state)

        if new_game_state.is_terminated():
            PointsCollector.count_final_scores(game_state=new_game_state)

        return new_game_state
Exemple #5
0
 def cities_for_position(cls, game_state: CarcassonneGameState,
                         city_position: CoordinateWithSide):
     try:
         tile: Tile = game_state.board[city_position.coordinate.row][
             city_position.coordinate.column]
     except IndexError:
         tile = None
     cities = []
     if tile is None:
         return cities
     for city_group in tile.city:
         if city_position.side in city_group:
             city_group_side: Side
             for city_group_side in city_group:
                 city_position: CoordinateWithSide = CoordinateWithSide(
                     city_position.coordinate, city_group_side)
                 cities.append(city_position)
     return cities
Exemple #6
0
    def find_roads(cls, game_state: CarcassonneGameState,
                   coordinate: Coordinate):
        roads: Set[Road] = set()

        tile: Tile = game_state.board[coordinate.row][coordinate.column]

        if tile is None:
            return roads

        side: Side
        for side in [Side.TOP, Side.RIGHT, Side.BOTTOM, Side.LEFT]:
            if tile.get_type(side) == TerrainType.ROAD:
                road: Road = cls.find_road(game_state=game_state,
                                           road_position=CoordinateWithSide(
                                               coordinate=coordinate,
                                               side=side))
                roads.add(road)

        return list(roads)
Exemple #7
0
    def find_cities(cls,
                    game_state: CarcassonneGameState,
                    coordinate: Coordinate,
                    sides: [Side] = (Side.TOP, Side.RIGHT, Side.BOTTOM,
                                     Side.LEFT)):
        cities: Set[City] = set()

        tile: Tile = game_state.board[coordinate.row][coordinate.column]

        if tile is None:
            return cities

        side: Side
        for side in sides:
            if tile.get_type(side) == TerrainType.CITY:
                city: City = cls.find_city(game_state=game_state,
                                           city_position=CoordinateWithSide(
                                               coordinate=coordinate,
                                               side=side))
                cities.add(city)

        return list(cities)
    def __possible_farmer_position(
            cls, game_state: CarcassonneGameState) -> [CoordinateWithSide]:
        playing_positions: [CoordinateWithSide] = []
        last_tile_action: TileAction = game_state.last_tile_action
        last_played_tile: Tile = last_tile_action.tile
        last_played_position: Coordinate = last_tile_action.coordinate

        farmer_connection: FarmerConnection
        for farmer_connection in last_played_tile.farms:
            farm: Farm = FarmUtil.find_farm(game_state=game_state,
                                            farmer_connection_with_coordinate=
                                            FarmerConnectionWithCoordinate(
                                                farmer_connection,
                                                last_played_position))
            if FarmUtil.has_meeples(game_state, farm):
                continue
            else:
                farmer_position: Side = farmer_connection.farmer_positions[0]
                playing_positions.append(
                    CoordinateWithSide(last_played_position, farmer_position))

        return playing_positions
    def __possible_meeple_positions(
            game_state: CarcassonneGameState) -> [CoordinateWithSide]:
        playing_positions: [CoordinateWithSide] = []
        last_tile_action: TileAction = game_state.last_tile_action
        last_played_tile: Tile = last_tile_action.tile
        last_played_position: Coordinate = last_tile_action.coordinate

        if last_played_tile.chapel:
            playing_positions.append(
                CoordinateWithSide(coordinate=last_played_position,
                                   side=Side.CENTER))

        if last_played_tile.flowers \
                and SupplementaryRule.NORMAL_MEEPLES_CAN_USE_FLOWERS in game_state.supplementary_rules:
            playing_positions.append(
                CoordinateWithSide(coordinate=last_played_position,
                                   side=Side.CENTER))

        for side in [Side.TOP, Side.RIGHT, Side.BOTTOM, Side.LEFT]:
            if last_played_tile.get_type(side) == TerrainType.CITY:
                connected_cities = CityUtil.find_city(
                    game_state,
                    CoordinateWithSide(coordinate=last_played_position,
                                       side=side))
                if CityUtil.city_contains_meeples(game_state,
                                                  connected_cities):
                    continue
                else:
                    playing_positions.append(
                        CoordinateWithSide(coordinate=last_played_position,
                                           side=side))

            if last_played_tile.get_type(side) == TerrainType.ROAD:
                connected_roads = RoadUtil.find_road(
                    game_state,
                    CoordinateWithSide(coordinate=last_played_position,
                                       side=side))
                if RoadUtil.road_contains_meeples(game_state, connected_roads):
                    continue
                else:
                    playing_positions.append(
                        CoordinateWithSide(coordinate=last_played_position,
                                           side=side))

        return playing_positions
    def remove_meeples_and_collect_points(cls, game_state: CarcassonneGameState, coordinate: Coordinate):

        # Points for finished cities
        cities: [City] = CityUtil.find_cities(game_state=game_state, coordinate=coordinate)
        for city in cities:
            if city.finished:
                meeples: [[MeeplePosition]] = CityUtil.find_meeples(game_state=game_state, city=city)
                meeple_counts_per_player = cls.get_meeple_counts_per_player(meeples)
                # print("City finished. Meeples:", json.dumps(meeple_counts_per_player))
                if sum(meeple_counts_per_player) == 0:
                    continue
                winning_player = cls.get_winning_player(meeple_counts_per_player)
                if winning_player is not None:
                    points = cls.count_city_points(game_state=game_state, city=city)
                    # print(points, "points for player", winning_player)
                    game_state.scores[winning_player] += points
                MeepleUtil.remove_meeples(game_state=game_state, meeples=meeples)

        # Points for finished roads
        roads: [Road] = RoadUtil.find_roads(game_state=game_state, coordinate=coordinate)
        for road in roads:
            if road.finished:
                meeples: [[MeeplePosition]] = RoadUtil.find_meeples(game_state=game_state, road=road)
                meeple_counts_per_player = cls.get_meeple_counts_per_player(meeples)
                # print("Road finished. Meeples:", json.dumps(meeple_counts_per_player))
                if sum(meeple_counts_per_player) == 0:
                    continue
                winning_player = cls.get_winning_player(meeple_counts_per_player)
                if winning_player is not None:
                    points = cls.count_road_points(game_state=game_state, road=road)
                    # print(points, "points for player", winning_player)
                    game_state.scores[winning_player] += points
                MeepleUtil.remove_meeples(game_state=game_state, meeples=meeples)

        # Points for finished chapels
        for row in range(coordinate.row - 1, coordinate.row + 2):
            for column in range(coordinate.column - 1, coordinate.column + 2):
                tile: Tile = game_state.get_tile(row, column)

                if tile is None:
                    continue

                coordinate = Coordinate(row=row, column=column)
                coordinate_with_side = CoordinateWithSide(coordinate=coordinate, side=Side.CENTER)
                meeple_of_player = MeepleUtil.position_contains_meeple(game_state=game_state,
                                                                             coordinate_with_side=coordinate_with_side)
                if (tile.chapel or tile.flowers) and meeple_of_player is not None:
                    points = cls.chapel_or_flowers_points(game_state=game_state, coordinate=coordinate)
                    if points == 9:
                        # print("Chapel or flowers finished for player", str(meeple_of_player))
                        # print(points, "points for player", meeple_of_player)
                        game_state.scores[meeple_of_player] += points

                        meeples_per_player = []
                        for _ in range(game_state.players):
                            meeples_per_player.append([])

                        for meeple_position in game_state.placed_meeples[meeple_of_player]:
                            if coordinate_with_side == meeple_position.coordinate_with_side:
                                meeples_per_player[meeple_of_player].append(meeple_position)

                        MeepleUtil.remove_meeples(game_state=game_state, meeples=meeples_per_player)
    def possible_meeple_actions(
            cls, game_state: CarcassonneGameState) -> [MeepleAction]:
        current_player = game_state.current_player
        last_tile_action: TileAction = game_state.last_tile_action
        last_played_tile: Tile = last_tile_action.tile
        last_played_position: Coordinate = last_tile_action.coordinate

        possible_actions: [MeepleAction] = []

        meeple_positions = cls.__possible_meeple_positions(
            game_state=game_state)

        if SupplementaryRule.FARMERS in game_state.supplementary_rules:
            farmer_positions = cls.__possible_farmer_position(
                game_state=game_state)
        else:
            farmer_positions = ()

        if game_state.meeples[current_player] > 0:
            possible_actions.extend(
                list(
                    map(
                        lambda x: MeepleAction(meeple_type=MeepleType.NORMAL,
                                               coordinate_with_side=x),
                        meeple_positions)))

            possible_actions.extend(
                list(
                    map(
                        lambda x: MeepleAction(meeple_type=MeepleType.FARMER,
                                               coordinate_with_side=x),
                        farmer_positions)))

        if game_state.big_meeples[current_player] > 0:
            possible_actions.extend(
                list(
                    map(
                        lambda x: MeepleAction(meeple_type=MeepleType.BIG,
                                               coordinate_with_side=x),
                        meeple_positions)))

            possible_actions.extend(
                list(
                    map(
                        lambda x: MeepleAction(
                            meeple_type=MeepleType.BIG_FARMER,
                            coordinate_with_side=x), farmer_positions)))

        if game_state.abbots[current_player] > 0:
            if last_played_tile.chapel or last_played_tile.flowers:
                possible_actions.append(
                    MeepleAction(meeple_type=MeepleType.ABBOT,
                                 coordinate_with_side=CoordinateWithSide(
                                     coordinate=last_played_position,
                                     side=Side.CENTER)))

        placed_meeple: MeeplePosition
        for placed_meeple in game_state.placed_meeples[current_player]:
            if placed_meeple.meeple_type == MeepleType.ABBOT:
                possible_actions.append(
                    MeepleAction(meeple_type=MeepleType.ABBOT,
                                 coordinate_with_side=placed_meeple.
                                 coordinate_with_side,
                                 remove=True))

        return possible_actions