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)) 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 test_find_cities(self): """ Find cities left and right """ # Given game_state: CarcassonneGameState = CarcassonneGameState() city_one_side_straight_road = base_tiles[ "city_top_straight_road"].turn(3) city_with_road = inns_and_cathedrals_tiles["ic_15"].turn(3) game_state.board = [[None for column in range(2)] for row in range(1)] game_state.board[0][0] = city_with_road game_state.board[0][1] = city_one_side_straight_road # When cities: [City] = CityUtil.find_cities(game_state=game_state, coordinate=Coordinate(0, 0)) # Then self.assertEqual(1, len(cities)) self.assertEqual(2, len(cities[0].city_positions)) self.assertTrue(cities[0].finished)
def test_find_city(self): """ Find the positions for a city with a top and a bottom """ # Given game_state: CarcassonneGameState = CarcassonneGameState() city_top = base_tiles["city_top"] city_bottom = city_top.turn(2) game_state.board = [[None for column in range(1)] for row in range(2)] game_state.board[0][0] = city_bottom game_state.board[1][0] = city_top # When city: City = CityUtil.find_city(game_state=game_state, city_position=CoordinateWithSide( Coordinate(0, 0), Side.BOTTOM)) # Then self.assertTrue(city.finished) self.assertEqual(2, len(city.city_positions)) self.assertIn(CoordinateWithSide(Coordinate(0, 0), Side.BOTTOM), city.city_positions) self.assertIn(CoordinateWithSide(Coordinate(1, 0), Side.TOP), city.city_positions)
def test_find_meeples_in_donut_city(self): """ Find meeple positions for a donut shaped city """ # Given game_state: CarcassonneGameState = self.create_donut_city_board() game_state.placed_meeples = [[], [], []] game_state.placed_meeples[0].append( MeeplePosition(meeple_type=MeepleType.NORMAL, coordinate_with_side=CoordinateWithSide( Coordinate(2, 1), Side.RIGHT))) game_state.placed_meeples[0].append( MeeplePosition(meeple_type=MeepleType.NORMAL, coordinate_with_side=CoordinateWithSide( Coordinate(0, 1), Side.LEFT))) game_state.placed_meeples[1].append( MeeplePosition(meeple_type=MeepleType.BIG, coordinate_with_side=CoordinateWithSide( Coordinate(1, 2), Side.TOP))) game_state.players = 3 # When city: City = CityUtil.find_city(game_state=game_state, city_position=CoordinateWithSide( Coordinate(0, 0), Side.BOTTOM)) meeples: [[MeeplePosition]] = CityUtil.find_meeples(game_state, city) # Then self.assertEqual(3, len(meeples)) self.assertEqual(2, len(meeples[0])) self.assertEqual(1, len(meeples[1])) self.assertEqual(0, len(meeples[2])) self.assertIn( MeeplePosition(MeepleType.NORMAL, CoordinateWithSide(Coordinate(2, 1), Side.RIGHT)), meeples[0]) self.assertIn( MeeplePosition(MeepleType.NORMAL, CoordinateWithSide(Coordinate(0, 1), Side.LEFT)), meeples[0]) self.assertIn( MeeplePosition(MeepleType.BIG, CoordinateWithSide(Coordinate(1, 2), Side.TOP)), meeples[1])
def test_find_donut_city(self): """ Find the positions for a donut shaped city """ # Given game_state: CarcassonneGameState = self.create_donut_city_board() # When city: City = CityUtil.find_city(game_state=game_state, city_position=CoordinateWithSide( Coordinate(0, 0), Side.BOTTOM)) # Then self.assertTrue(city.finished) self.assertEqual(16, len(city.city_positions)) self.assertIn(CoordinateWithSide(Coordinate(0, 0), Side.BOTTOM), city.city_positions) self.assertIn(CoordinateWithSide(Coordinate(0, 0), Side.RIGHT), city.city_positions) self.assertIn(CoordinateWithSide(Coordinate(0, 1), Side.LEFT), city.city_positions) self.assertIn(CoordinateWithSide(Coordinate(0, 1), Side.RIGHT), city.city_positions) self.assertIn(CoordinateWithSide(Coordinate(0, 2), Side.LEFT), city.city_positions) self.assertIn(CoordinateWithSide(Coordinate(0, 2), Side.BOTTOM), city.city_positions) self.assertIn(CoordinateWithSide(Coordinate(1, 0), Side.TOP), city.city_positions) self.assertIn(CoordinateWithSide(Coordinate(1, 0), Side.BOTTOM), city.city_positions) self.assertIn(CoordinateWithSide(Coordinate(1, 2), Side.TOP), city.city_positions) self.assertIn(CoordinateWithSide(Coordinate(1, 2), Side.BOTTOM), city.city_positions) self.assertIn(CoordinateWithSide(Coordinate(2, 0), Side.TOP), city.city_positions) self.assertIn(CoordinateWithSide(Coordinate(2, 0), Side.RIGHT), city.city_positions) self.assertIn(CoordinateWithSide(Coordinate(2, 1), Side.LEFT), city.city_positions) self.assertIn(CoordinateWithSide(Coordinate(2, 1), Side.RIGHT), city.city_positions) self.assertIn(CoordinateWithSide(Coordinate(2, 2), Side.LEFT), city.city_positions) self.assertIn(CoordinateWithSide(Coordinate(2, 2), Side.TOP), city.city_positions)
def count_farm_points(cls, game_state: CarcassonneGameState, farm: Farm): cities: Set[City] = set() points = 0 farmer_connection_with_coordinate: FarmerConnectionWithCoordinate for farmer_connection_with_coordinate in farm.farmer_connections_with_coordinate: cities = cities.union( CityUtil.find_cities( game_state=game_state, coordinate=farmer_connection_with_coordinate.coordinate, sides=farmer_connection_with_coordinate.farmer_connection. city_sides)) city: City for city in cities: if city.finished: points += 3 return points
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([]) meeples_per_player[meeple_of_player].append( coordinate_with_side) MeepleUtil.remove_meeples(game_state=game_state, meeples=meeples_per_player)
def count_final_scores(cls, game_state: CarcassonneGameState): for player, placed_meeples in enumerate(game_state.placed_meeples): # TODO also remove meeples from meeples_to_remove, when there are multiple meeples_to_remove: Set[MeeplePosition] = set(placed_meeples) while len(meeples_to_remove) > 0: meeple_position: MeeplePosition = meeples_to_remove.pop() tile: Tile = game_state.board[ meeple_position.coordinate_with_side.coordinate.row][ meeple_position.coordinate_with_side.coordinate.column] terrrain_type: TerrainType = tile.get_type( meeple_position.coordinate_with_side.side) if terrrain_type == TerrainType.CITY: city: City = CityUtil.find_city( game_state=game_state, city_position=meeple_position.coordinate_with_side) meeples: [CoordinateWithSide ] = CityUtil.find_meeples(game_state=game_state, city=city) meeple_counts_per_player = cls.get_meeple_counts_per_player( meeples) print("Collecting points for unfinished city. Meeples:", json.dumps(meeple_counts_per_player)) 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", player) game_state.scores[winning_player] += points MeepleUtil.remove_meeples(game_state=game_state, meeples=meeples) continue if terrrain_type == TerrainType.ROAD: road: [Road] = RoadUtil.find_road( game_state=game_state, road_position=meeple_position.coordinate_with_side) meeples: [CoordinateWithSide ] = RoadUtil.find_meeples(game_state=game_state, road=road) meeple_counts_per_player = cls.get_meeple_counts_per_player( meeples) print("Collecting points for unfinished road. Meeples:", json.dumps(meeple_counts_per_player)) 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", player) game_state.scores[winning_player] += points MeepleUtil.remove_meeples(game_state=game_state, meeples=meeples) continue if terrrain_type == TerrainType.CHAPEL or terrrain_type == TerrainType.FLOWERS: points = cls.chapel_or_flowers_points( game_state=game_state, coordinate=meeple_position.coordinate_with_side. coordinate) print( "Collecting points for unfinished chapel or flowers for player", str(player)) print(points, "points for player", player) game_state.scores[player] += points meeples_per_player = [] for _ in range(game_state.players): meeples_per_player.append([]) meeples_per_player[player].append(meeple_position) MeepleUtil.remove_meeples(game_state=game_state, meeples=meeples_per_player) continue if meeple_position.meeple_type == MeepleType.FARMER or meeple_position.meeple_type == MeepleType.BIG_FARMER: farm: Farm = FarmUtil.find_farm_by_coordinate( game_state=game_state, position=meeple_position.coordinate_with_side) meeples: [[MeeplePosition] ] = FarmUtil.find_meeples(game_state=game_state, farm=farm) meeple_counts_per_player = cls.get_meeple_counts_per_player( meeples) print("Collecting points for farm. Meeples:", json.dumps(meeple_counts_per_player)) winning_player = cls.get_winning_player( meeple_counts_per_player) if winning_player is not None: points = cls.count_farm_points(game_state=game_state, farm=farm) print(points, "points for player", winning_player) game_state.scores[winning_player] += points MeepleUtil.remove_meeples(game_state=game_state, meeples=meeples) continue print("Collecting points for unknown type", terrrain_type)