def _build_extra_road_connection(self, building, collector_building): collector_coords = set( coords for coords in self.production_builder.iter_possible_road_coords( collector_building.position, collector_building.position)) destination_coords = set( coords for coords in self.production_builder.iter_possible_road_coords( building.loading_area, building.position)) pos = building.loading_area beacon = Rect.init_from_borders(pos.left - 1, pos.top - 1, pos.right + 1, pos.bottom + 1) path = RoadPlanner()(self.owner.personality_manager.get('RoadPlanner'), collector_coords, destination_coords, beacon, self.production_builder.get_path_nodes()) if path is None: return BUILD_RESULT.IMPOSSIBLE cost = self.production_builder.get_road_cost(path) for resource_id, amount in cost.items(): if resource_id == RES.GOLD: if self.owner.get_component( StorageComponent).inventory[resource_id] < amount: return BUILD_RESULT.NEED_RESOURCES elif self.settlement.get_component( StorageComponent).inventory[resource_id] < amount: return BUILD_RESULT.NEED_RESOURCES return BUILD_RESULT.OK if self.production_builder.build_road( path) else BUILD_RESULT.UNKNOWN_ERROR
def _build_extra_road_connection(self, building, collector_building): collector_coords = set( coords for coords in self.production_builder.iter_possible_road_coords( collector_building.position, collector_building.position ) ) destination_coords = set( coords for coords in self.production_builder.iter_possible_road_coords(building.loading_area, building.position) ) pos = building.loading_area beacon = Rect.init_from_borders(pos.left - 1, pos.top - 1, pos.right + 1, pos.bottom + 1) path = RoadPlanner()( self.owner.personality_manager.get("RoadPlanner"), collector_coords, destination_coords, beacon, self.production_builder.get_path_nodes(), ) if path is None: return BUILD_RESULT.IMPOSSIBLE cost = self.production_builder.get_road_cost(path) for resource_id, amount in cost.iteritems(): if resource_id == RES.GOLD: if self.owner.get_component(StorageComponent).inventory[resource_id] < amount: return BUILD_RESULT.NEED_RESOURCES elif self.settlement.get_component(StorageComponent).inventory[resource_id] < amount: return BUILD_RESULT.NEED_RESOURCES return BUILD_RESULT.OK if self.production_builder.build_road(path) else BUILD_RESULT.UNKNOWN_ERROR
def _get_road_to_builder(self, builder): """Return a path from the builder to a building with general collectors (None if impossible).""" loading_area = builder.get_loading_area() collector_coords = set() for building in self.collector_buildings: if loading_area.distance(building.position) == 1: return [] if loading_area.distance(building.position) > building.radius: continue # the collector building is too far to be useful for coords in self.iter_possible_road_coords( building.position, building.position): collector_coords.add(coords) destination_coords = set( self.iter_possible_road_coords(loading_area, builder.position)) if self is self.settlement_manager.production_builder: if not self.settlement_manager.production_builder.road_connectivity_cache.is_connection_possible( collector_coords, destination_coords): return None blocked_coords = set([ coords for coords in builder.position.tuple_iter() ]).union(self.land_manager.coastline) beacon = Rect.init_from_borders(loading_area.left - 1, loading_area.top - 1, loading_area.right + 1, loading_area.bottom + 1) return RoadPlanner()(self.owner.personality_manager.get('RoadPlanner'), collector_coords, destination_coords, beacon, self.get_path_nodes(), blocked_coords=blocked_coords)
def load_raw_map(self, savegame_db, preview=False): self.map_name = savegame_db.map_name # load islands self.islands = [] for (islandid,) in savegame_db("SELECT DISTINCT island_id + 1001 FROM ground"): island = Island(savegame_db, islandid, self.session, preview=preview) self.islands.append(island) #calculate map dimensions self.min_x, self.min_y, self.max_x, self.max_y = 0, 0, 0, 0 for island in self.islands: self.min_x = min(island.position.left, self.min_x) self.min_y = min(island.position.top, self.min_y) self.max_x = max(island.position.right, self.max_x) self.max_y = max(island.position.bottom, self.max_y) self.min_x -= savegame_db.map_padding self.min_y -= savegame_db.map_padding self.max_x += savegame_db.map_padding self.max_y += savegame_db.map_padding self.map_dimensions = Rect.init_from_borders(self.min_x, self.min_y, self.max_x, self.max_y) #add water self.log.debug("Filling world with water...") self.ground_map = {} # big sea water tile class if not preview: default_grounds = Entities.grounds[self.properties.get('default_ground', '%d-straight' % GROUND.WATER[0])] fake_tile_class = Entities.grounds['-1-special'] fake_tile_size = 10 for x in xrange(self.min_x-MAP.BORDER, self.max_x+MAP.BORDER, fake_tile_size): for y in xrange(self.min_y-MAP.BORDER, self.max_y+MAP.BORDER, fake_tile_size): fake_tile_x = x - 1 fake_tile_y = y + fake_tile_size - 1 if not preview: # we don't need no references, we don't need no mem control default_grounds(self.session, fake_tile_x, fake_tile_y) for x_offset in xrange(fake_tile_size): if self.min_x <= x + x_offset < self.max_x: for y_offset in xrange(fake_tile_size): if self.min_y <= y + y_offset < self.max_y: self.ground_map[(x+x_offset, y+y_offset)] = fake_tile_class(self.session, fake_tile_x, fake_tile_y) self.fake_tile_map = copy.copy(self.ground_map) # remove parts that are occupied by islands, create the island map and the full map self.island_map = {} self.full_map = copy.copy(self.ground_map) for island in self.islands: for coords in island.ground_map: if coords in self.ground_map: self.full_map[coords] = island.ground_map[coords] del self.ground_map[coords] self.island_map[coords] = island
def load_raw_map(self, savegame_db, preview=False): self.map_name = savegame_db.map_name # Load islands. for (islandid,) in savegame_db("SELECT DISTINCT island_id + 1001 FROM ground"): island = Island(savegame_db, islandid, self.session, preview=preview) self.islands.append(island) # Calculate map dimensions. self.min_x, self.min_y, self.max_x, self.max_y = 0, 0, 0, 0 for island in self.islands: self.min_x = min(island.position.left, self.min_x) self.min_y = min(island.position.top, self.min_y) self.max_x = max(island.position.right, self.max_x) self.max_y = max(island.position.bottom, self.max_y) self.min_x -= savegame_db.map_padding self.min_y -= savegame_db.map_padding self.max_x += savegame_db.map_padding self.max_y += savegame_db.map_padding self.map_dimensions = Rect.init_from_borders(self.min_x, self.min_y, self.max_x, self.max_y) # Add water. self.log.debug("Filling world with water...") self.ground_map = {} # big sea water tile class if not preview: default_grounds = Entities.grounds[self.properties.get('default_ground', '%d-straight' % GROUND.WATER[0])] fake_tile_class = Entities.grounds['-1-special'] fake_tile_size = 10 for x in xrange(self.min_x-MAP.BORDER, self.max_x+MAP.BORDER, fake_tile_size): for y in xrange(self.min_y-MAP.BORDER, self.max_y+MAP.BORDER, fake_tile_size): fake_tile_x = x - 1 fake_tile_y = y + fake_tile_size - 1 if not preview: # we don't need no references, we don't need no mem control default_grounds(self.session, fake_tile_x, fake_tile_y) for x_offset in xrange(fake_tile_size): if self.min_x <= x + x_offset < self.max_x: for y_offset in xrange(fake_tile_size): if self.min_y <= y + y_offset < self.max_y: self.ground_map[(x+x_offset, y+y_offset)] = fake_tile_class(self.session, fake_tile_x, fake_tile_y) self.fake_tile_map = copy.copy(self.ground_map) # Remove parts that are occupied by islands, create the island map and the full map. self.island_map = {} self.full_map = copy.copy(self.ground_map) for island in self.islands: for coords in island.ground_map: if coords in self.ground_map: self.full_map[coords] = island.ground_map[coords] del self.ground_map[coords] self.island_map[coords] = island
def load_raw_map(self, savegame_db, preview=False): # load islands self.islands = [] for (islandid,) in savegame_db("SELECT rowid + 1000 FROM island"): island = Island(savegame_db, islandid, self.session, preview=preview) self.islands.append(island) #calculate map dimensions self.min_x, self.min_y, self.max_x, self.max_y = 0, 0, 0, 0 for i in self.islands: self.min_x = min(i.rect.left, self.min_x) self.min_y = min(i.rect.top, self.min_y) self.max_x = max(i.rect.right, self.max_x) self.max_y = max(i.rect.bottom, self.max_y) self.min_x -= 10 self.min_y -= 10 self.max_x += 10 self.max_y += 10 self.map_dimensions = Rect.init_from_borders(self.min_x, self.min_y, self.max_x, self.max_y) #add water self.log.debug("Filling world with water...") self.ground_map = {} # big sea water tile class if not preview: default_grounds = Entities.grounds[int(self.properties.get('default_ground', GROUND.WATER[0]))] # extra world size that is added so that the player can't see the "black void" border = 30 fake_tile_class = Entities.grounds[-1] for x in xrange(self.min_x-border, self.max_x+border, 10): for y in xrange(self.min_y-border, self.max_y+border, 10): if not preview: # we don't need no references, we don't need no mem control default_grounds(self.session, x, y) for x_offset in xrange(0, 10): if x+x_offset < self.max_x and x+x_offset >= self.min_x: for y_offset in xrange(0, 10): if y+y_offset < self.max_y and y+y_offset >= self.min_y: self.ground_map[(x+x_offset, y+y_offset)] = fake_tile_class(self.session, x, y) # remove parts that are occupied by islands, create the island map and the full map self.island_map = {} self.full_map = copy.copy(self.ground_map) for island in self.islands: for coords in island.ground_map: if coords in self.ground_map: self.full_map[coords] = island.ground_map[coords] del self.ground_map[coords] self.island_map[coords] = island
def __init(self, db, island_id, preview): """ Load the actual island from a file @param preview: flag, map preview mode """ p_x, p_y, width, height = db( "SELECT MIN(x), MIN(y), (1 + MAX(x) - MIN(x)), (1 + MAX(y) - MIN(y)) FROM ground WHERE island_id = ?", island_id - 1001)[0] self.ground_map = {} for (x, y, ground_id, action_id, rotation) in db( "SELECT x, y, ground_id, action_id, rotation FROM ground WHERE island_id = ?", island_id - 1001): # Load grounds if not preview: # actual game, need actual tiles ground = Entities.grounds[str('{:d}-{}'.format( ground_id, action_id))](self.session, x, y) ground.act(rotation) else: ground = MapPreviewTile(x, y, ground_id) # These are important for pathfinding and building to check if the ground tile # is blocked in any way. self.ground_map[(ground.x, ground.y)] = ground self._init_cache() # Contains references to all resource deposits (but not mines) # on the island, regardless of the owner: # {building_id: {(x, y): building_instance, ...}, ...} self.deposits = defaultdict(dict) self.settlements = [] self.wild_animals = [] self.num_trees = 0 # define the rectangle with the smallest area that contains every island tile its position min_x = min(list(zip(*self.ground_map.keys()))[0]) max_x = max(list(zip(*self.ground_map.keys()))[0]) min_y = min(list(zip(*self.ground_map.keys()))[1]) max_y = max(list(zip(*self.ground_map.keys()))[1]) self.position = Rect.init_from_borders(min_x, min_y, max_x, max_y) if not preview: # This isn't needed for map previews, but it is in actual games. self.path_nodes = IslandPathNodes(self) self.barrier_nodes = IslandBarrierNodes(self) # Repopulate wild animals every 2 mins if they die out. Scheduler().add_new_object(self.check_wild_animal_population, self, run_in=Scheduler().get_ticks(120), loops=-1) """TUTORIAL:
def __init(self, db, island_id, preview): """ Load the actual island from a file @param preview: flag, map preview mode """ p_x, p_y, width, height = db( "SELECT MIN(x), MIN(y), (1 + MAX(x) - MIN(x)), (1 + MAX(y) - MIN(y)) FROM ground WHERE island_id = ?", island_id - 1001, )[0] self.ground_map = {} for (x, y, ground_id, action_id, rotation) in db( "SELECT x, y, ground_id, action_id, rotation FROM ground WHERE island_id = ?", island_id - 1001 ): # Load grounds if not preview: # actual game, need actual tiles ground = Entities.grounds[str("%d-%s" % (ground_id, action_id))](self.session, x, y) ground.act(rotation) else: ground = MapPreviewTile(x, y, ground_id) # These are important for pathfinding and building to check if the ground tile # is blocked in any way. self.ground_map[(ground.x, ground.y)] = ground self._init_cache() # Contains references to all resource deposits (but not mines) # on the island, regardless of the owner: # {building_id: {(x, y): building_instance, ...}, ...} self.deposits = defaultdict(dict) self.settlements = [] self.wild_animals = [] self.num_trees = 0 # define the rectangle with the smallest area that contains every island tile its position min_x = min(zip(*self.ground_map.keys())[0]) max_x = max(zip(*self.ground_map.keys())[0]) min_y = min(zip(*self.ground_map.keys())[1]) max_y = max(zip(*self.ground_map.keys())[1]) self.position = Rect.init_from_borders(min_x, min_y, max_x, max_y) if not preview: # This isn't needed for map previews, but it is in actual games. self.path_nodes = IslandPathNodes(self) # Repopulate wild animals every 2 mins if they die out. Scheduler().add_new_object( self.check_wild_animal_population, self, run_in=Scheduler().get_ticks(120), loops=-1 ) """TUTORIAL:
def __init(self, origin, filename, preview=False): """ Load the actual island from a file @param origin: Point @param filename: String, filename of island db or random map id @param preview: flag, map preview mode """ self.file = filename self.origin = origin db = self._get_island_db() p_x, p_y, width, height = db("SELECT (MIN(x) + ?), (MIN(y) + ?), (1 + MAX(x) - MIN(x)), (1 + MAX(y) - MIN(y)) FROM ground", self.origin.x, self.origin.y)[0] # rect for quick checking if a tile isn't on this island # NOTE: it contains tiles, that are not on the island! self.rect = Rect(Point(p_x, p_y), width, height) self.ground_map = {} for (rel_x, rel_y, ground_id, action_id, rotation) in db("SELECT x, y, ground_id, action_id, rotation FROM ground"): # Load grounds if not preview: # actual game, need actual tiles ground = Entities.grounds[ground_id](self.session, self.origin.x + rel_x, self.origin.y + rel_y) ground.act(action_id, rotation) else: ground = Point(self.origin.x + rel_x, self.origin.y + rel_y) ground.classes = tuple() ground.settlement = None # These are important for pathfinding and building to check if the ground tile # is blocked in any way. self.ground_map[(ground.x, ground.y)] = ground self._init_cache() self.settlements = [] self.wild_animals = [] self.num_trees = 0 # define the rectangle with the smallest area that contains every island tile its position min_x = min(zip(*self.ground_map.keys())[0]) max_x = max(zip(*self.ground_map.keys())[0]) min_y = min(zip(*self.ground_map.keys())[1]) max_y = max(zip(*self.ground_map.keys())[1]) self.position = Rect.init_from_borders(min_x, min_y, max_x, max_y) if not preview: # this isn't needed for previews, but it is in actual games self.path_nodes = IslandPathNodes(self) # repopulate wild animals every 2 mins if they die out. Scheduler().add_new_object(self.check_wild_animal_population, self, Scheduler().get_ticks(120), -1) """TUTORIAL:
def __init(self, db, island_id, preview): """ Load the actual island from a file @param preview: flag, map preview mode """ p_x, p_y, width, height = db( "SELECT MIN(x), MIN(y), (1 + MAX(x) - MIN(x)), (1 + MAX(y) - MIN(y)) FROM ground WHERE island_id = ?", island_id - 1001)[0] # rect for quick checking if a tile isn't on this island # NOTE: it contains tiles, that are not on the island! self.rect = Rect(Point(p_x, p_y), width, height) self.ground_map = {} for (x, y, ground_id, action_id, rotation) in db( "SELECT x, y, ground_id, action_id, rotation FROM ground WHERE island_id = ?", island_id - 1001): # Load grounds if not preview: # actual game, need actual tiles ground = Entities.grounds[str( '%d-%s' % (ground_id, action_id))](self.session, x, y) ground.act(rotation) else: ground = MapPreviewTile(x, y, ground_id) # These are important for pathfinding and building to check if the ground tile # is blocked in any way. self.ground_map[(ground.x, ground.y)] = ground self._init_cache() self.settlements = [] self.wild_animals = [] self.num_trees = 0 # define the rectangle with the smallest area that contains every island tile its position min_x = min(zip(*self.ground_map.keys())[0]) max_x = max(zip(*self.ground_map.keys())[0]) min_y = min(zip(*self.ground_map.keys())[1]) max_y = max(zip(*self.ground_map.keys())[1]) self.position = Rect.init_from_borders(min_x, min_y, max_x, max_y) if not preview: # this isn't needed for previews, but it is in actual games self.path_nodes = IslandPathNodes(self) # repopulate wild animals every 2 mins if they die out. Scheduler().add_new_object(self.check_wild_animal_population, self, Scheduler().get_ticks(120), -1) """TUTORIAL:
def _get_road_to_builder(self, builder): """Return a path from the builder to a building with general collectors (None if impossible).""" loading_area = builder.get_loading_area() collector_coords = set() for building in self.collector_buildings: if loading_area.distance(building.position) == 1: return [] if loading_area.distance(building.position) > building.radius: continue # the collector building is too far to be useful for coords in self.iter_possible_road_coords(building.position, building.position): collector_coords.add(coords) blocked_coords = set([coords for coords in builder.position.tuple_iter()]) destination_coords = set(self.iter_possible_road_coords(loading_area, builder.position)) beacon = Rect.init_from_borders(loading_area.left - 1, loading_area.top - 1, loading_area.right + 1, loading_area.bottom + 1) return RoadPlanner()(self.owner.personality_manager.get('RoadPlanner'), collector_coords, destination_coords, beacon, self.get_path_nodes(), blocked_coords=blocked_coords)
def __init(self, db, island_id, preview): """ Load the actual island from a file @param preview: flag, map preview mode """ p_x, p_y, width, height = db("SELECT MIN(x), MIN(y), (1 + MAX(x) - MIN(x)), (1 + MAX(y) - MIN(y)) FROM ground WHERE island_id = ?", island_id - 1001)[0] # rect for quick checking if a tile isn't on this island # NOTE: it contains tiles, that are not on the island! self.rect = Rect(Point(p_x, p_y), width, height) self.ground_map = {} for (x, y, ground_id, action_id, rotation) in db("SELECT x, y, ground_id, action_id, rotation FROM ground WHERE island_id = ?", island_id - 1001): # Load grounds if not preview: # actual game, need actual tiles ground = Entities.grounds[str('%d-%s' % (ground_id, action_id))](self.session, x, y) ground.act(rotation) else: ground = MapPreviewTile(x, y, ground_id) # These are important for pathfinding and building to check if the ground tile # is blocked in any way. self.ground_map[(ground.x, ground.y)] = ground self._init_cache() self.settlements = [] self.wild_animals = [] self.num_trees = 0 # define the rectangle with the smallest area that contains every island tile its position min_x = min(zip(*self.ground_map.keys())[0]) max_x = max(zip(*self.ground_map.keys())[0]) min_y = min(zip(*self.ground_map.keys())[1]) max_y = max(zip(*self.ground_map.keys())[1]) self.position = Rect.init_from_borders(min_x, min_y, max_x, max_y) if not preview: # this isn't needed for previews, but it is in actual games self.path_nodes = IslandPathNodes(self) # repopulate wild animals every 2 mins if they die out. Scheduler().add_new_object(self.check_wild_animal_population, self, Scheduler().get_ticks(120), -1) """TUTORIAL:
def generate_random_map(seed, map_size, water_percent, max_island_size, preferred_island_size, island_size_deviation): """ Generates a random map. @param seed: random number generator seed @param map_size: maximum map side length @param water_percent: minimum percent of map covered with water @param max_island_size: maximum island side length @param preferred_island_size: mean of island side lengths @param island_size_deviation: deviation of island side lengths @return: filename of the SQLite database containing the map """ max_island_size = min(max_island_size, map_size) rand = random.Random(_simplify_seed(seed)) min_island_size = 20 # minimum chosen island side length (the real size my be smaller) min_island_separation = 3 + map_size // 100 # minimum distance between two islands max_island_side_coefficient = 4 # maximum value of island's max(side length) / min(side length) islands = [] estimated_land = 0 max_land_amount = map_size * map_size * (100 - water_percent) // 100 trial_number = 0 while trial_number < 100: trial_number += 1 width = max( min_island_size, min( max_island_size, int( round( rand.gauss(preferred_island_size, island_size_deviation))))) side_coefficient = min(1 + abs(rand.gauss(0, 0.2)), max_island_side_coefficient) side_coefficient = side_coefficient if rand.randint( 0, 1) else 1.0 / side_coefficient height = max( min_island_size, min(max_island_size, int(round(width * side_coefficient)))) size = width * height if estimated_land + size > max_land_amount: continue for _ in xrange(13): x = rand.randint(0, map_size - width) y = rand.randint(0, map_size - height) rect = Rect.init_from_topleft_and_size(x, y, width, height) blocked = False for existing_island in islands: if existing_island.distance(rect) < min_island_separation: blocked = True break if not blocked: islands.append(rect) estimated_land += size trial_number = 0 break # move some of the islands to stretch the map to the right size if len(islands) > 1: min_top = min(rect.top for rect in islands) rect = rand.choice([rect for rect in islands if rect.top == min_top]) islands[islands.index(rect)] = Rect.init_from_borders( rect.left, rect.top - min_top, rect.right, rect.bottom - min_top) max_bottom = max(rect.bottom for rect in islands) rect = rand.choice( [rect for rect in islands if rect.bottom == max_bottom]) shift = map_size - max_bottom - 1 islands[islands.index(rect)] = Rect.init_from_borders( rect.left, rect.top + shift, rect.right, rect.bottom + shift) min_left = min(rect.left for rect in islands) rect = rand.choice([rect for rect in islands if rect.left == min_left]) islands[islands.index(rect)] = Rect.init_from_borders( rect.left - min_left, rect.top, rect.right - min_left, rect.bottom) max_right = max(rect.right for rect in islands) rect = rand.choice( [rect for rect in islands if rect.right == max_right]) shift = map_size - max_right - 1 islands[islands.index(rect)] = Rect.init_from_borders( rect.left + shift, rect.top, rect.right + shift, rect.bottom) island_strings = [] for rect in islands: # The bounds must be platform independent to make sure the same maps are generated on all platforms. island_seed = rand.randint(-2147483648, 2147483647) island_params = { 'creation_method': 2, 'seed': island_seed, 'width': rect.width, 'height': rect.height, 'island_x': rect.left, 'island_y': rect.top } island_string = string.Template( _random_island_id_template).safe_substitute(island_params) island_strings.append(island_string) return island_strings
def generate_random_map(seed, map_size, water_percent, max_island_size, preferred_island_size, island_size_deviation): """ Generates a random map. @param seed: random number generator seed @param map_size: maximum map side length @param water_percent: minimum percent of map covered with water @param max_island_size: maximum island side length @param preferred_island_size: mean of island side lengths @param island_size_deviation: deviation of island side lengths @return: filename of the SQLite database containing the map """ max_island_size = min(max_island_size, map_size) rand = random.Random(_simplify_seed(seed)) min_island_size = 20 # minimum chosen island side length (the real size my be smaller) min_island_separation = 3 + map_size // 100 # minimum distance between two islands max_island_side_coefficient = 4 # maximum value of island's max(side length) / min(side length) islands = [] estimated_land = 0 max_land_amount = map_size * map_size * (100 - water_percent) // 100 trial_number = 0 while trial_number < 100: trial_number += 1 width = max(min_island_size, min(max_island_size, int(round(rand.gauss(preferred_island_size, island_size_deviation))))) side_coefficient = min(1 + abs(rand.gauss(0, 0.2)), max_island_side_coefficient) side_coefficient = side_coefficient if rand.randint(0, 1) else 1.0 / side_coefficient height = max(min_island_size, min(max_island_size, int(round(width * side_coefficient)))) size = width * height if estimated_land + size > max_land_amount: continue for _ in xrange(13): x = rand.randint(0, map_size - width) y = rand.randint(0, map_size - height) rect = Rect.init_from_topleft_and_size(x, y, width, height) blocked = False for existing_island in islands: if existing_island.distance(rect) < min_island_separation: blocked = True break if not blocked: islands.append(rect) estimated_land += size trial_number = 0 break # move some of the islands to stretch the map to the right size if len(islands) > 1: min_top = min(rect.top for rect in islands) rect = rand.choice([rect for rect in islands if rect.top == min_top]) islands[islands.index(rect)] = Rect.init_from_borders(rect.left, rect.top - min_top, rect.right, rect.bottom - min_top) max_bottom = max(rect.bottom for rect in islands) rect = rand.choice([rect for rect in islands if rect.bottom == max_bottom]) shift = map_size - max_bottom - 1 islands[islands.index(rect)] = Rect.init_from_borders(rect.left, rect.top + shift, rect.right, rect.bottom + shift) min_left = min(rect.left for rect in islands) rect = rand.choice([rect for rect in islands if rect.left == min_left]) islands[islands.index(rect)] = Rect.init_from_borders(rect.left - min_left, rect.top, rect.right - min_left, rect.bottom) max_right = max(rect.right for rect in islands) rect = rand.choice([rect for rect in islands if rect.right == max_right]) shift = map_size - max_right - 1 islands[islands.index(rect)] = Rect.init_from_borders(rect.left + shift, rect.top, rect.right + shift, rect.bottom) island_strings = [] for rect in islands: # The bounds must be platform independent to make sure the same maps are generated on all platforms. island_seed = rand.randint(-2147483648, 2147483647) island_params = {'creation_method': 2, 'seed': island_seed, 'width': rect.width, 'height': rect.height, 'island_x': rect.left, 'island_y': rect.top} island_string = string.Template(_random_island_id_template).safe_substitute(island_params) island_strings.append(island_string) return island_strings