Пример #1
0
    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
Пример #3
0
    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)
Пример #4
0
	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
Пример #5
0
	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
Пример #6
0
	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
Пример #7
0
    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:
Пример #8
0
    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:
Пример #9
0
	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:
Пример #10
0
    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:
Пример #11
0
	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)
Пример #12
0
	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:
Пример #13
0
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
Пример #14
0
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