def opposite_edge(cls, coordinate_with_farmer_side: CoordinateWithFarmerSide) -> CoordinateWithFarmerSide: if coordinate_with_farmer_side.farmer_side.get_side() == Side.TOP: return CoordinateWithFarmerSide( Coordinate(coordinate_with_farmer_side.coordinate.row - 1, coordinate_with_farmer_side.coordinate.column), SideModificationUtil.opposite_farmer_side(coordinate_with_farmer_side.farmer_side) ) elif coordinate_with_farmer_side.farmer_side.get_side() == Side.RIGHT: return CoordinateWithFarmerSide( Coordinate(coordinate_with_farmer_side.coordinate.row, coordinate_with_farmer_side.coordinate.column + 1), SideModificationUtil.opposite_farmer_side(coordinate_with_farmer_side.farmer_side) ) elif coordinate_with_farmer_side.farmer_side.get_side() == Side.BOTTOM: return CoordinateWithFarmerSide( Coordinate(coordinate_with_farmer_side.coordinate.row + 1, coordinate_with_farmer_side.coordinate.column), SideModificationUtil.opposite_farmer_side(coordinate_with_farmer_side.farmer_side) ) elif coordinate_with_farmer_side.farmer_side.get_side() == Side.LEFT: return CoordinateWithFarmerSide( Coordinate(coordinate_with_farmer_side.coordinate.row, coordinate_with_farmer_side.coordinate.column - 1), SideModificationUtil.opposite_farmer_side(coordinate_with_farmer_side.farmer_side) )
def test_find_road(self): """ Find the positions for a city with a top and a bottom """ # Given game_state: CarcassonneGameState = CarcassonneGameState() crossroads = base_tiles["crossroads"] game_state.board = [[None for column in range(1)] for row in range(2)] game_state.board[0][0] = crossroads game_state.board[1][0] = crossroads # When road: Road = RoadUtil.find_road(game_state=game_state, road_position=CoordinateWithSide( Coordinate(0, 0), Side.BOTTOM)) # Then self.assertTrue(road.finished) self.assertEqual(2, len(road.road_positions)) self.assertIn(CoordinateWithSide(Coordinate(0, 0), Side.BOTTOM), road.road_positions) self.assertIn(CoordinateWithSide(Coordinate(1, 0), Side.TOP), road.road_positions)
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 opposite_edge(cls, city_position: CoordinateWithSide): if city_position.side == Side.TOP: return CoordinateWithSide(Coordinate(city_position.coordinate.row - 1, city_position.coordinate.column), Side.BOTTOM) elif city_position.side == Side.RIGHT: return CoordinateWithSide(Coordinate(city_position.coordinate.row, city_position.coordinate.column + 1), Side.LEFT) elif city_position.side == Side.BOTTOM: return CoordinateWithSide(Coordinate(city_position.coordinate.row + 1, city_position.coordinate.column), Side.TOP) elif city_position.side == Side.LEFT: return CoordinateWithSide(Coordinate(city_position.coordinate.row, city_position.coordinate.column - 1), Side.RIGHT)
def possible_playing_positions(game_state: CarcassonneGameState, tile_to_play: Tile) -> [PlayingPosition]: if game_state.empty_board(): return [ PlayingPosition(coordinate=game_state.starting_position, turns=0) ] playing_positions = [] for row_index, board_row in enumerate(game_state.board): for column_index, column_tile in enumerate(board_row): if column_tile is not None: continue for tile_turns in range(0, 4): top = game_state.get_tile(row_index - 1, column_index) bottom = game_state.get_tile(row_index + 1, column_index) left = game_state.get_tile(row_index, column_index - 1) right = game_state.get_tile(row_index, column_index + 1) if TileFitter.fits(tile_to_play.turn(tile_turns), top=top, bottom=bottom, left=left, right=right, game_state=game_state): playing_positions.append( PlayingPosition(coordinate=Coordinate( row=row_index, column=column_index), turns=tile_turns)) 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 __init__(self, tile_sets: [TileSet] = (TileSet.BASE, TileSet.THE_RIVER, TileSet.INNS_AND_CATHEDRALS), supplementary_rules: [SupplementaryRule ] = (SupplementaryRule.FARMERS, SupplementaryRule.ABBOTS), players: int = 2, board_size: (int, int) = (35, 35), starting_position: Coordinate = Coordinate(6, 15)): self.deck = self.initialize_deck(tile_sets=tile_sets) self.supplementary_rules: [SupplementaryRule] = supplementary_rules self.board: [[Tile]] = [[None for column in range(board_size[1])] for row in range(board_size[0])] self.starting_position: Coordinate = starting_position self.next_tile = self.deck.pop(0) self.players = players self.meeples = [7 for _ in range(players)] self.abbots = [ 1 if SupplementaryRule.ABBOTS in supplementary_rules else 0 for _ in range(players) ] self.big_meeples = [ 1 if TileSet.INNS_AND_CATHEDRALS in tile_sets else 0 for _ in range(players) ] self.placed_meeples = [[] for _ in range(players)] self.scores: [int] = [0 for _ in range(players)] self.current_player = 0 self.phase = GamePhase.TILES self.last_tile_action: Optional[TileAction] = None self.last_river_rotation: Rotation = Rotation.NONE
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 = [[], []] meeple_0_1 = MeeplePosition(meeple_type=MeepleType.NORMAL, coordinate_with_side=CoordinateWithSide( Coordinate(2, 1), Side.RIGHT)) meeple_0_2 = MeeplePosition(meeple_type=MeepleType.NORMAL, coordinate_with_side=CoordinateWithSide( Coordinate(0, 1), Side.LEFT)) meeple_1_1 = MeeplePosition(meeple_type=MeepleType.BIG, coordinate_with_side=CoordinateWithSide( Coordinate(1, 2), Side.TOP)) game_state.placed_meeples[0].append(meeple_0_1) game_state.placed_meeples[0].append(meeple_0_2) game_state.placed_meeples[1].append(meeple_1_1) game_state.players = 2 meeples_to_remove = [[], []] meeples_to_remove[0].append(copy.deepcopy(meeple_0_1)) meeples_to_remove[1].append(copy.deepcopy(meeple_1_1)) # When MeepleUtil.remove_meeples(game_state=game_state, meeples=meeples_to_remove) # Then self.assertEqual(1, len(game_state.placed_meeples[0])) self.assertEqual(0, len(game_state.placed_meeples[1])) self.assertIn(copy.deepcopy(meeple_0_2), game_state.placed_meeples[0])
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_collect_points_small_city_2(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 game_state.players = 2 game_state.placed_meeples = [[], []] game_state.placed_meeples[0].append(MeeplePosition(meeple_type=MeepleType.NORMAL, coordinate_with_side=CoordinateWithSide(Coordinate(0, 0), Side.RIGHT))) game_state.placed_meeples[1].append(MeeplePosition(meeple_type=MeepleType.NORMAL, coordinate_with_side=CoordinateWithSide(Coordinate(0, 1), Side.BOTTOM))) # When PointsCollector.remove_meeples_and_collect_points(game_state=game_state, coordinate=Coordinate(0, 1)) # Then self.assertEqual(0, len(game_state.placed_meeples[0])) self.assertEqual(1, len(game_state.placed_meeples[1])) self.assertEqual(4, game_state.scores[0]) self.assertEqual(0, game_state.scores[1])
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 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)