예제 #1
0
def compile_home_system_list(num_home_systems, systems):
    """
    Compiles a list with a requested number of home systems.
    """

    # if the list of systems to choose home systems from is empty, report an error and return empty list
    if not systems:
        util.report_error("Python generate_home_system_list: no systems to choose from")
        return []

    # calculate an initial minimal number of jumps that the home systems should be apart,
    # based on the total number of systems to choose from and the requested number of home systems
    min_jumps = max(int(float(len(systems)) / float(num_home_systems * 2)), 5)
    # try to find the home systems, decrease the min jumps until enough systems can be found, or the min jump distance
    # gets reduced to 0 (meaning we don't have enough systems to choose from at all)
    while min_jumps > 0:
        print "Trying to find", num_home_systems, "home systems that are at least", min_jumps, "jumps apart"
        # try to find home systems...
        home_systems = find_systems_with_min_jumps_between(num_home_systems, systems, min_jumps)
        # ...check if we got enough...
        if len(home_systems) >= num_home_systems:
            # ...yes, we got what we need, so let's break out of the loop
            break
        print "Home system min jump conflict: %d systems and %d empires, tried %d min jump and failed"\
              % (len(systems), num_home_systems, min_jumps)
        # ...no, decrease the min jump distance and try again
        min_jumps -= 1

    # check if the loop above delivered a list with enough home systems, or if it exited because the min jump distance
    # has been decreased to 0 without finding enough systems
    # in that case, our galaxy obviously is too crowded, report an error and return an empty list
    if len(home_systems) < num_home_systems:
        util.report_error("Python generate_home_system_list: requested %d homeworlds in a galaxy with %d systems"
                          % (num_home_systems, len(systems)))
        return []

    # make sure all our home systems have a "real" star (that is, a star that is not a neutron star, black hole,
    # or even no star at all) and at least one planet in it
    for home_system in home_systems:
        # if this home system has no "real" star, change star type to a randomly selected "real" star
        if fo.sys_get_star_type(home_system) not in starsystems.star_types_real:
            star_type = random.choice(starsystems.star_types_real)
            print "Home system", home_system, "has star type", fo.sys_get_star_type(home_system),\
                  ", changing that to", star_type
            fo.sys_set_star_type(home_system, star_type)

        # if this home system has no planets, create one in a random orbit
        # we take random values for type and size, as these will be set to suitable values later
        if not fo.sys_get_planets(home_system):
            print "Home system", home_system, "has no planets, adding one"
            planet = fo.create_planet(random.choice(planets.planet_sizes_real),
                                      random.choice(planets.planet_types_real),
                                      home_system, random.randint(0, fo.sys_get_num_orbits(home_system) - 1), "")
            # if we couldn't create the planet, report an error and return an empty list
            if planet == fo.invalid_object():
                util.report_error("Python generate_home_system_list: couldn't create planet in home system")
                return []

    return home_systems
예제 #2
0
def generate_fields(systems):
    """
    Generates stationary fields in some randomly chosen empty no star systems.
    """
    # filter out all empty no star systems
    candidates = [
        s for s in systems
        if (fo.sys_get_star_type(s) == fo.starType.noStar) and (
            not fo.sys_get_planets(s))
    ]
    # make sure we have at least one empty no star system, otherwise return without creating any fields
    if not candidates:
        print("...no empty no star systems found, no fields created")
        return
    # pick 10-15% of all empty no star systems to create stationary fields in them, but at least one
    accepted = sample(candidates,
                      max(int(len(candidates) * uniform(0.1, 0.15)), 1))
    for system in accepted:
        # randomly pick a field type
        field_type = choice(["FLD_NEBULA_1", "FLD_NEBULA_2", "FLD_NEBULA_3"])
        # and create the field
        if fo.create_field_in_system(field_type, uniform(40, 120),
                                     system) == fo.invalid_object():
            # create field failed, report an error
            report_error(
                "Python generate_fields: create field %s in system %d failed" %
                (field_type, system))
    print("...fields created in %d systems out of %d empty no star systems" %
          (len(accepted), len(candidates)))
예제 #3
0
def generate_fields(systems):
    """
    Generates stationary fields in some randomly chosen empty no star systems.
    """
    # filter out all empty no star systems
    candidates = [s for s in systems if (fo.sys_get_star_type(s) == fo.starType.noStar) and (not fo.sys_get_planets(s))]
    # make sure we have at least one empty no star system, otherwise return without creating any fields
    if not candidates:
        print "...no empty no star systems found, no fields created"
        return
    # pick 10-20% of all empty no star systems to create stationary fields in them, but at least one
    accepted = sample(candidates, max(int(len(candidates) * uniform(0.1, 0.2)), 1))
    for system in accepted:
        # randomly pick a field type
        field_type = choice(["FLD_NEBULA_1", "FLD_NEBULA_2"])
        # and create the field
        if fo.create_field_in_system(field_type, uniform(40, 120), system) == fo.invalid_object():
            # create field failed, report an error
            report_error("Python generate_fields: create field %s in system %d failed" % (field_type, system))
    print "...fields created in %d systems out of %d empty no star systems" % (len(accepted), len(candidates))
예제 #4
0
def compile_home_system_list(num_home_systems, systems, gsd):
    """
    Compiles a list with a requested number of home systems.
    """
    print "Compile home system list:", num_home_systems, "systems requested"

    # if the list of systems to choose home systems from is empty, report an error and return empty list
    if not systems:
        report_error(
            "Python generate_home_system_list: no systems to choose from")
        return []

    # calculate an initial minimal number of jumps that the home systems should be apart,
    # based on the total number of systems to choose from and the requested number of home systems
    # don't let min_jumps be either:
    # a.) larger than a defined limit, because an unreasonably large number is really not at all needed,
    #     and with large galaxies an excessive amount of time can be used in failed attempts
    # b.) lower than the minimum jump distance limit that should be considered high priority (see options.py),
    #     otherwise no attempt at all would be made to enforce the other requirements for home systems (see below)
    min_jumps = min(
        HS_MAX_JUMP_DISTANCE_LIMIT,
        max(int(float(len(systems)) / float(num_home_systems * 2)),
            HS_MIN_DISTANCE_PRIORITY_LIMIT))

    # home systems must have a certain minimum of systems and planets in their near vicinity
    # we will try to select our home systems from systems that match this criteria, if that fails, we will select our
    # home systems from all systems and add the missing number planets to the systems in their vicinity afterwards
    # the minimum system and planet limit and the jump range that defines the "near vicinity" are controlled by the
    # HS_* option constants in options.py (see there)

    # we start by building two additional pools of systems: one that contains all systems that match the criteria
    # completely (meets the min systems and planets limit), and one that contains all systems that match the criteria
    # at least partially (meets the min systems limit)
    pool_matching_sys_and_planet_limit = []
    pool_matching_sys_limit = []
    for system in systems:
        systems_in_vicinity = fo.systems_within_jumps_unordered(
            HS_VICINITY_RANGE, [system])
        if len(systems_in_vicinity) >= HS_MIN_SYSTEMS_IN_VICINITY:
            pool_matching_sys_limit.append(system)
            if count_planets_in_systems(
                    systems_in_vicinity) >= min_planets_in_vicinity_limit(
                        len(systems_in_vicinity)):
                pool_matching_sys_and_planet_limit.append(system)
    print(
        len(pool_matching_sys_and_planet_limit),
        "systems meet the min systems and planets in the near vicinity limit")
    print len(pool_matching_sys_limit
              ), "systems meet the min systems in the near vicinity limit"

    # now try to pick the requested number of home systems
    # we will do this by calling find_home_systems, which takes a list of tuples defining the pools from which to pick
    # the home systems; it will use the pools in the order in which they appear in the list, so put better pools first

    # we will make two attempts: the first one with the filtered pools we just created, and tell find_home_systems
    # to start with the min_jumps jumps distance we calculated above, but not to go lower than
    # HS_MIN_DISTANCE_PRIORITY_LIMIT

    print "First attempt: trying to pick home systems from the filtered pools of preferred systems"
    pool_list = [
        # the better pool is of course the one where all systems meet BOTH the min systems and planets limit
        (pool_matching_sys_and_planet_limit,
         "pool of systems that meet both the min systems and planets limit"),
        # next the less preferred pool where all systems at least meets the min systems limit
        # specify 0 as number of requested home systems to pick as much systems as possible
        (pool_matching_sys_limit,
         "pool of systems that meet at least the min systems limit"),
    ]
    home_systems = find_home_systems(num_home_systems, pool_list, min_jumps,
                                     HS_MIN_DISTANCE_PRIORITY_LIMIT)

    # check if the first attempt delivered a list with enough home systems
    # if not, we make our second attempt, this time disregarding the filtered pools and using all systems, starting
    # again with the min_jumps jump distance limit and specifying 0 as number of required home systems to pick as much
    # systems as possible
    if len(home_systems) < num_home_systems:
        print "Second attempt: trying to pick home systems from all systems"
        home_systems = find_home_systems(num_home_systems,
                                         [(systems, "complete pool")],
                                         min_jumps, 1)

    # check if the selection process delivered a list with enough home systems
    # if not, our galaxy obviously is too crowded, report an error and return an empty list
    if len(home_systems) < num_home_systems:
        report_error(
            "Python generate_home_system_list: requested %d homeworlds in a galaxy with %d systems"
            % (num_home_systems, len(systems)))
        return []

    # check if we got more home systems than we requested
    if len(home_systems) > num_home_systems:
        # yes: calculate the number of planets in the near vicinity of each system
        # and store that value with each system in a map
        hs_planets_in_vicinity_map = {
            s: calculate_home_system_merit(s)
            for s in home_systems
        }
        # sort the home systems by the number of planets in their near vicinity using the map
        # now only pick the number of home systems we need, taking those with the highest number of planets
        home_systems = sorted(home_systems,
                              key=hs_planets_in_vicinity_map.get,
                              reverse=True)[:num_home_systems]

    # make sure all our home systems have a "real" star (that is, a star that is not a neutron star, black hole,
    # or even no star at all) and at least one planet in it
    for home_system in home_systems:
        # if this home system has no "real" star, change star type to a randomly selected "real" star
        if fo.sys_get_star_type(home_system) not in star_types_real:
            star_type = random.choice(star_types_real)
            print "Home system", home_system, "has star type", fo.sys_get_star_type(home_system),\
                  ", changing that to", star_type
            fo.sys_set_star_type(home_system, star_type)

        # if this home system has no planets, create one in a random orbit
        # we take random values for type and size, as these will be set to suitable values later
        if not fo.sys_get_planets(home_system):
            print "Home system", home_system, "has no planets, adding one"
            planet = fo.create_planet(
                random.choice(planet_sizes_real),
                random.choice(planet_types_real), home_system,
                random.randint(0,
                               fo.sys_get_num_orbits(home_system) - 1), "")
            # if we couldn't create the planet, report an error and return an empty list
            if planet == fo.invalid_object():
                report_error(
                    "Python generate_home_system_list: couldn't create planet in home system"
                )
                return []

    # finally, check again if all home systems meet the criteria of having the required minimum number of planets
    # within their near vicinity, if not, add the missing number of planets
    print "Checking if home systems have the required minimum of planets within the near vicinity..."
    for home_system in home_systems:
        # calculate the number of missing planets, and add them if this number is > 0
        systems_in_vicinity = fo.systems_within_jumps_unordered(
            HS_VICINITY_RANGE, [home_system])
        num_systems_in_vicinity = len(systems_in_vicinity)
        num_planets_in_vicinity = count_planets_in_systems(systems_in_vicinity)
        num_planets_to_add = min_planets_in_vicinity_limit(
            num_systems_in_vicinity) - num_planets_in_vicinity
        print "Home system", home_system, "has", num_systems_in_vicinity, "systems and", num_planets_in_vicinity,\
            "planets in the near vicinity, required minimum:", min_planets_in_vicinity_limit(num_systems_in_vicinity)
        if num_planets_to_add > 0:
            systems_in_vicinity.remove(
                home_system
            )  # don't add planets to the home system, so remove it from the list
            # sort the systems_in_vicinity before adding, since the C++ engine doesn't guarrantee the same
            # platform independence as python.
            add_planets_to_vicinity(sorted(systems_in_vicinity),
                                    num_planets_to_add, gsd)

    # as we've sorted the home system list before, lets shuffle it to ensure random order and return
    random.shuffle(home_systems)
    return home_systems
예제 #5
0
def add_planets_to_vicinity(vicinity, num_planets, gsd):
    """
    Adds the specified number of planets to the specified systems.
    """
    print "Adding", num_planets, "planets to the following systems:", vicinity

    # first, compile a list containing all the free orbits in the specified systems
    # begin with adding the free orbits of all systems that have a real star (that is, no neutron star, black hole,
    # and not no star), if that isn't enough, also one, by one, add the free orbits of neutron star, black hole and
    # no star systems (in that order) until we have enough free orbits

    # for that, we use this list of tuples
    # the first tuple contains all real star types, the following tuples the neutron, black hole and no star types,
    # so we can iterate over this list and only add the free orbits of systems that match the respective star types
    # each step
    # this way we can prioritize the systems we want to add planets to by star type
    acceptable_star_types_list = [
        star_types_real, (fo.starType.noStar, ), (fo.starType.neutron, ),
        (fo.starType.blackHole, )
    ]

    # store the free orbits as a list of tuples of (system, orbit)
    free_orbits_map = []

    # now, iterate over the list of acceptable star types
    for acceptable_star_types in acceptable_star_types_list:
        # check all systems in the list of systems we got passed into this function
        for system in vicinity:
            # if this system has a star type we want to accept in this step, add its free orbits to our list
            if fo.sys_get_star_type(system) in acceptable_star_types:
                free_orbits_map.extend([
                    (system, orbit) for orbit in fo.sys_free_orbits(system)
                ])
        # check if we got enough free orbits after completing this step
        # we want 4 times as much free orbits as planets we want to add, that means each system shouldn't get more
        # than 2-3 additional planets on average
        if len(free_orbits_map) > (num_planets * 4):
            break

    # if we got less free orbits than planets that should be added, something is wrong
    # in that case abort and log an error
    if len(free_orbits_map) < num_planets:
        report_error(
            "Python add_planets_to_vicinity: less free orbits than planets to add - cancelled"
        )

    print "...free orbits available:", free_orbits_map
    # as we will pop the free orbits from this list afterwards, shuffle it to randomize the order of the orbits
    random.shuffle(free_orbits_map)

    # add the requested number of planets
    while num_planets > 0:
        # get the next free orbit from the list we just compiled
        system, orbit = free_orbits_map.pop()

        # check the star type of the system containing the orbit we got
        star_type = fo.sys_get_star_type(system)
        if star_type in [fo.starType.noStar, fo.starType.blackHole]:
            # if it is a black hole or has no star, change the star type
            # pick a star type, continue until we get a real star
            # don't accept neutron, black hole or no star
            print "...system picked to add a planet has star type", star_type
            while star_type not in star_types_real:
                star_type = pick_star_type(gsd.age)
            print "...change that to", star_type
            fo.sys_set_star_type(system, star_type)

        # pick a planet size, continue until we get a size that matches the HS_ACCEPTABLE_PLANET_SIZES option
        planet_size = fo.planetSize.unknown
        while planet_size not in HS_ACCEPTABLE_PLANET_SIZES:
            planet_size = calc_planet_size(star_type, orbit,
                                           fo.galaxySetupOption.high,
                                           gsd.shape)

        # pick an according planet type
        planet_type = calc_planet_type(star_type, orbit, planet_size)

        # finally, create the planet in the system and orbit we got
        print "...adding", planet_size, planet_type, "planet to system", system
        if fo.create_planet(planet_size, planet_type, system, orbit,
                            "") == fo.invalid_object():
            report_error(
                "Python add_planets_to_vicinity: create planet in system %d failed"
                % system)

        # continue with next planet
        num_planets -= 1
예제 #6
0
def name_star_systems(system_list):
    # choose star types and planet sizes, before choosing names, so naming can have special handling of Deep Space
    star_type_assignments = {}
    planet_assignments = {}
    position_list = []
    for system in system_list:
        star_type = fo.sys_get_star_type(system)
        systemxy = fo.get_pos(system)
        star_type_assignments[systemxy] = star_type
        planet_assignments[systemxy] = fo.sys_get_planets(system)
        position_list.append(systemxy)

    # will name name a portion of stars on a group basis, where the stars of each group share the same base star name,
    # suffixed by different (default greek) letters or characters (options at top of file)
    star_name_map = {}
    star_names = names.get_name_list("STAR_NAMES")
    group_names = names.get_name_list("STAR_GROUP_NAMES")
    potential_group_names = []
    individual_names = []
    stargroup_words[:] = names.get_name_list("STAR_GROUP_WORDS")
    stargroup_chars[:] = names.get_name_list("STAR_GROUP_CHARS")
    stargroup_modifiers[:] = [stargroup_words, stargroup_chars][options.STAR_GROUPS_USE_CHARS]
    for starname in star_names:
        if len(starname) > 6:  # if starname is long, don't allow it for groups
            individual_names.append(starname)
            continue
        # any names that already have a greek letter in them can only be used for individual stars, not groups
        for namepart in starname.split():
            if namepart in greek_letters:
                individual_names.append(starname)
                break
        else:
            potential_group_names.append(starname)

    if not potential_group_names:
        potential_group_names.append("XYZZY")

    # ensure at least a portion of galaxy gets individual starnames
    num_systems = len(system_list)
    target_indiv_ratio = [options.TARGET_INDIV_RATIO_SMALL, options.TARGET_INDIV_RATIO_LARGE]\
                         [num_systems >= options.NAMING_LARGE_GALAXY_SIZE]
    # TODO improve the following calc to be more likely to hit target_indiv_ratio if more or less than
    # 50% potential_group_names used for groups
    num_individual_stars = int(max(min(num_systems * target_indiv_ratio,
                                       len(individual_names)+int(0.5 * len(potential_group_names))),
                                   num_systems - 0.8 * len(stargroup_modifiers) *
                                   (len(group_names)+int(0.5 * len(potential_group_names)))))
    star_group_size = 1 + int((num_systems - num_individual_stars) /
                              (max(1, len(group_names)+int(0.5 * len(potential_group_names)))))
    # make group size a bit bigger than min necessary, at least a trio
    star_group_size = max(3, star_group_size)
    num_star_groups = 1 + int(num_systems/star_group_size)  # initial value

    # first cluster all systems, then remove some to be individually named (otherwise groups can have too many
    # individually named systems in their middle).  First remove any that are too small (only 1 or 2 systems).
    # The clusters with the most systems are generally the most closely spaced, and though they might make good
    # logical candidates for groups, their names are then prone to overlapping on the galaxy map, so after removing
    # small groups, remove the groups with the most systems.
    random.shuffle(position_list)  # just to be sure it is randomized
    init_cluster_assgts = cluster_stars(position_list, num_star_groups)
    star_groups = {}
    for index_pos, index_group in enumerate(init_cluster_assgts):
        systemxy = position_list[index_pos]
        star_groups.setdefault(index_group, []).append(systemxy)
    indiv_systems = []

    # remove groups with only one non-deep-system
    for groupindex, group_list in star_groups.items():
        max_can_transfer = len(potential_group_names)-len(star_groups)+len(individual_names)-len(indiv_systems)
        if max_can_transfer <= 0:
            break
        elif max_can_transfer <= len(group_list):
            continue
        not_deep, deep_space = check_deep_space(group_list, star_type_assignments, planet_assignments)
        if len(not_deep) > 1:
            continue
        for systemxy in star_groups[groupindex]:
            indiv_systems.append(systemxy)
        del star_groups[groupindex]

    # remove tiny groups
    group_sizes = [(len(group), index) for index, group in star_groups.items()]
    group_sizes.sort()
    while len(indiv_systems) < num_individual_stars and len(group_sizes) > 0:
        groupsize, groupindex = group_sizes.pop()
        max_can_transfer = len(potential_group_names)-len(star_groups)+len(individual_names)-len(indiv_systems)
        if (max_can_transfer <= 0) or (groupsize > 2):
            break
        if max_can_transfer <= groupsize:
            continue
        for systemxy in star_groups[groupindex]:
            indiv_systems.append(systemxy)
        del star_groups[groupindex]

    # remove largest (likely most compact) groups
    while len(indiv_systems) < num_individual_stars and len(group_sizes) > 0:
        groupsize, groupindex = group_sizes.pop(-1)
        max_can_transfer = len(potential_group_names)-len(star_groups)+len(individual_names)-len(indiv_systems)
        if max_can_transfer <= 0:
            break
        if max_can_transfer <= groupsize:
            continue
        for systemxy in star_groups[groupindex]:
            indiv_systems.append(systemxy)
        del star_groups[groupindex]

    num_star_groups = len(star_groups)
    num_individual_stars = len(indiv_systems)
    random.shuffle(potential_group_names)
    random.shuffle(individual_names)
    random.shuffle(group_names)
    num_for_indiv = min(max(len(potential_group_names)/2, num_individual_stars+1-len(individual_names)),
                        len(potential_group_names))
    individual_names.extend(potential_group_names[:num_for_indiv])
    group_names.extend(potential_group_names[num_for_indiv:])

    #print "sampling for %d indiv names from list of %d total indiv names"%(num_individual_stars, len(individual_names))
    indiv_name_sample = random.sample(individual_names, num_individual_stars)
    #indiv_name_assignments = zip([(pos.x, pos.y) for pos in position_list[:num_individual_stars]], indiv_name_sample)
    indiv_name_assignments = zip(indiv_systems, indiv_name_sample)
    star_name_map.update(indiv_name_assignments)
    #print "sampling for %d group names from list of %d total group names"%(num_star_groups, len(group_names))
    if len(group_names) < num_star_groups:
        group_names.extend([names.random_name(6) for _ in range(num_star_groups - len(group_names))])
    group_name_sample = random.sample(group_names, num_star_groups)
    for index_group, group_list in enumerate(sorted(star_groups.values())):
        star_name_map.update(name_group(group_list, group_name_sample[index_group], star_type_assignments,
                                        planet_assignments))

    # assign names from star_name_map to star systems
    for system in system_list:
        fo.set_name(system, star_name_map.get(fo.get_pos(system), "") or random_star_name())
예제 #7
0
def name_star_systems(system_list):
    # choose star types and planet sizes, before choosing names, so naming can have special handling of Deep Space
    star_type_assignments = {}
    planet_assignments = {}
    position_list = []
    for system in system_list:
        star_type = fo.sys_get_star_type(system)
        systemxy = fo.get_pos(system)
        star_type_assignments[systemxy] = star_type
        planet_assignments[systemxy] = fo.sys_get_planets(system)
        position_list.append(systemxy)

    # will name name a portion of stars on a group basis, where the stars of each group share the same base star name,
    # suffixed by different (default greek) letters or characters (options at top of file)
    star_name_map = {}
    star_names = names.get_name_list("STAR_NAMES")
    group_names = names.get_name_list("STAR_GROUP_NAMES")
    potential_group_names = []
    individual_names = []
    stargroup_words[:] = names.get_name_list("STAR_GROUP_WORDS")
    stargroup_chars[:] = names.get_name_list("STAR_GROUP_CHARS")
    stargroup_modifiers[:] = [stargroup_words,
                              stargroup_chars][options.STAR_GROUPS_USE_CHARS]
    for starname in star_names:
        if len(starname) > 6:  # if starname is long, don't allow it for groups
            individual_names.append(starname)
            continue
        # any names that already have a greek letter in them can only be used for individual stars, not groups
        for namepart in starname.split():
            if namepart in greek_letters:
                individual_names.append(starname)
                break
        else:
            potential_group_names.append(starname)

    if not potential_group_names:
        potential_group_names.append("XYZZY")

    # ensure at least a portion of galaxy gets individual starnames
    num_systems = len(system_list)
    choice = num_systems >= options.NAMING_LARGE_GALAXY_SIZE
    target_indiv_ratio = [
        options.TARGET_INDIV_RATIO_SMALL, options.TARGET_INDIV_RATIO_LARGE
    ][choice]
    # TODO improve the following calc to be more likely to hit target_indiv_ratio if more or less than
    # 50% potential_group_names used for groups
    num_individual_stars = int(
        max(
            min(num_systems * target_indiv_ratio,
                len(individual_names) + int(0.5 * len(potential_group_names))),
            num_systems - 0.8 * len(stargroup_modifiers) *
            (len(group_names) + int(0.5 * len(potential_group_names)))))
    star_group_size = 1 + int(
        (num_systems - num_individual_stars) /
        (max(1,
             len(group_names) + int(0.5 * len(potential_group_names)))))
    # make group size a bit bigger than min necessary, at least a trio
    star_group_size = max(3, star_group_size)
    num_star_groups = 1 + int(num_systems / star_group_size)  # initial value

    # first cluster all systems, then remove some to be individually named (otherwise groups can have too many
    # individually named systems in their middle).  First remove any that are too small (only 1 or 2 systems).
    # The clusters with the most systems are generally the most closely spaced, and though they might make good
    # logical candidates for groups, their names are then prone to overlapping on the galaxy map, so after removing
    # small groups, remove the groups with the most systems.
    random.shuffle(position_list)  # just to be sure it is randomized
    init_cluster_assgts = cluster_stars(position_list, num_star_groups)
    star_groups = {}
    for index_pos, index_group in enumerate(init_cluster_assgts):
        systemxy = position_list[index_pos]
        star_groups.setdefault(index_group, []).append(systemxy)
    indiv_systems = []

    # remove groups with only one non-deep-system
    for groupindex, group_list in list(star_groups.items()):
        max_can_transfer = len(potential_group_names) - len(star_groups) + len(
            individual_names) - len(indiv_systems)
        if max_can_transfer <= 0:
            break
        elif max_can_transfer <= len(group_list):
            continue
        not_deep, deep_space = check_deep_space(group_list,
                                                star_type_assignments,
                                                planet_assignments)
        if len(not_deep) > 1:
            continue
        for systemxy in star_groups[groupindex]:
            indiv_systems.append(systemxy)
        del star_groups[groupindex]

    # remove tiny groups
    group_sizes = [(len(group), index) for index, group in star_groups.items()]
    group_sizes.sort()
    while len(indiv_systems) < num_individual_stars and len(group_sizes) > 0:
        groupsize, groupindex = group_sizes.pop()
        max_can_transfer = len(potential_group_names) - len(star_groups) + len(
            individual_names) - len(indiv_systems)
        if (max_can_transfer <= 0) or (groupsize > 2):
            break
        if max_can_transfer <= groupsize:
            continue
        for systemxy in star_groups[groupindex]:
            indiv_systems.append(systemxy)
        del star_groups[groupindex]

    # remove largest (likely most compact) groups
    while len(indiv_systems) < num_individual_stars and len(group_sizes) > 0:
        groupsize, groupindex = group_sizes.pop(-1)
        max_can_transfer = len(potential_group_names) - len(star_groups) + len(
            individual_names) - len(indiv_systems)
        if max_can_transfer <= 0:
            break
        if max_can_transfer <= groupsize:
            continue
        for systemxy in star_groups[groupindex]:
            indiv_systems.append(systemxy)
        del star_groups[groupindex]

    num_star_groups = len(star_groups)
    num_individual_stars = len(indiv_systems)
    random.shuffle(potential_group_names)
    random.shuffle(individual_names)
    random.shuffle(group_names)
    num_for_indiv = min(
        max(
            len(potential_group_names) // 2,
            num_individual_stars + 1 - len(individual_names)),
        len(potential_group_names))
    individual_names.extend(potential_group_names[:num_for_indiv])
    group_names.extend(potential_group_names[num_for_indiv:])

    # print "sampling for %d indiv names from list of %d total indiv names" % (
    #     num_individual_stars, len(individual_names))
    indiv_name_sample = random.sample(individual_names, num_individual_stars)
    # indiv_name_assignments = zip([(pos.x, pos.y) for pos in position_list[:num_individual_stars]], indiv_name_sample)
    star_name_map.update(zip(indiv_systems, indiv_name_sample))
    # print "sampling for %d group names from list of %d total group names"%(num_star_groups, len(group_names))
    if len(group_names) < num_star_groups:
        group_names.extend([
            names.random_name(6)
            for _ in range(num_star_groups - len(group_names))
        ])
    group_name_sample = random.sample(group_names, num_star_groups)
    for index_group, group_list in enumerate(sorted(star_groups.values())):
        star_name_map.update(
            name_group(group_list, group_name_sample[index_group],
                       star_type_assignments, planet_assignments))

    # assign names from star_name_map to star systems
    for system in system_list:
        fo.set_name(
            system,
            star_name_map.get(fo.get_pos(system), "") or random_star_name())
예제 #8
0
def compile_home_system_list(num_home_systems, systems, gsd):
    """
    Compiles a list with a requested number of home systems.
    """
    print "Compile home system list:", num_home_systems, "systems requested"

    # if the list of systems to choose home systems from is empty, report an error and return empty list
    if not systems:
        report_error("Python generate_home_system_list: no systems to choose from")
        return []

    # calculate an initial minimal number of jumps that the home systems should be apart,
    # based on the total number of systems to choose from and the requested number of home systems
    # don't let min_jumps be either:
    # a.) larger than a defined limit, because an unreasonably large number is really not at all needed,
    #     and with large galaxies an excessive amount of time can be used in failed attempts
    # b.) lower than the minimum jump distance limit that should be considered high priority (see options.py),
    #     otherwise no attempt at all would be made to enforce the other requirements for home systems (see below)
    min_jumps = min(HS_MAX_JUMP_DISTANCE_LIMIT, max(int(float(len(systems)) / float(num_home_systems * 2)),
                                                    HS_MIN_DISTANCE_PRIORITY_LIMIT))

    # home systems must have a certain minimum of systems and planets in their near vicinity
    # we will try to select our home systems from systems that match this criteria, if that fails, we will select our
    # home systems from all systems and add the missing number planets to the systems in their vicinity afterwards
    # the minimum system and planet limit and the jump range that defines the "near vicinity" are controlled by the
    # HS_* option constants in options.py (see there)

    # we start by building two additional pools of systems: one that contains all systems that match the criteria
    # completely (meets the min systems and planets limit), and one that contains all systems that match the criteria
    # at least partially (meets the min systems limit)
    pool_matching_sys_and_planet_limit = []
    pool_matching_sys_limit = []
    for system in systems:
        systems_in_vicinity = get_systems_within_jumps(system, HS_VICINITY_RANGE)
        if len(systems_in_vicinity) >= HS_MIN_SYSTEMS_IN_VICINITY:
            pool_matching_sys_limit.append(system)
            if count_planets_in_systems(systems_in_vicinity) >= min_planets_in_vicinity_limit(len(systems_in_vicinity)):
                pool_matching_sys_and_planet_limit.append(system)
    print len(pool_matching_sys_and_planet_limit), "systems meet the min systems and planets in the near vicinity limit"
    print len(pool_matching_sys_limit), "systems meet the min systems in the near vicinity limit"

    # now try to pick the requested number of home systems
    # we will do this by calling find_home_systems, which takes a list of tuples defining the pools from which to pick
    # the home systems; it will use the pools in the order in which they appear in the list, so put better pools first

    # we will make two attempts: the first one with the filtered pools we just created, and tell find_home_systems
    # to start with the min_jumps jumps distance we calculated above, but not to go lower than
    # HS_MIN_DISTANCE_PRIORITY_LIMIT

    print "First attempt: trying to pick home systems from the filtered pools of preferred systems"
    pool_list = [
        # the better pool is of course the one where all systems meet BOTH the min systems and planets limit
        (pool_matching_sys_and_planet_limit, "pool of systems that meet both the min systems and planets limit"),
        # next the less preferred pool where all systems at least meets the min systems limit
        # specify 0 as number of requested home systems to pick as much systems as possible
        (pool_matching_sys_limit, "pool of systems that meet at least the min systems limit"),
    ]
    home_systems = find_home_systems(num_home_systems, pool_list, min_jumps, HS_MIN_DISTANCE_PRIORITY_LIMIT)

    # check if the first attempt delivered a list with enough home systems
    # if not, we make our second attempt, this time disregarding the filtered pools and using all systems, starting
    # again with the min_jumps jump distance limit and specifying 0 as number of required home systems to pick as much
    # systems as possible
    if len(home_systems) < num_home_systems:
        print "Second attempt: trying to pick home systems from all systems"
        home_systems = find_home_systems(num_home_systems, [(systems, "complete pool")], min_jumps, 1)

    # check if the selection process delivered a list with enough home systems
    # if not, our galaxy obviously is too crowded, report an error and return an empty list
    if len(home_systems) < num_home_systems:
        report_error("Python generate_home_system_list: requested %d homeworlds in a galaxy with %d systems"
                     % (num_home_systems, len(systems)))
        return []

    # check if we got more home systems than we requested
    if len(home_systems) > num_home_systems:
        # yes: calculate the number of planets in the near vicinity of each system
        # and store that value with each system in a map
        hs_planets_in_vicinity_map = {s: count_planets_in_systems(get_systems_within_jumps(s, HS_VICINITY_RANGE))
                                      for s in home_systems}
        # sort the home systems by the number of planets in their near vicinity using the map
        # now only pick the number of home systems we need, taking those with the highest number of planets
        home_systems = sorted(home_systems, key=hs_planets_in_vicinity_map.get, reverse=True)[:num_home_systems]

    # make sure all our home systems have a "real" star (that is, a star that is not a neutron star, black hole,
    # or even no star at all) and at least one planet in it
    for home_system in home_systems:
        # if this home system has no "real" star, change star type to a randomly selected "real" star
        if fo.sys_get_star_type(home_system) not in star_types_real:
            star_type = random.choice(star_types_real)
            print "Home system", home_system, "has star type", fo.sys_get_star_type(home_system),\
                  ", changing that to", star_type
            fo.sys_set_star_type(home_system, star_type)

        # if this home system has no planets, create one in a random orbit
        # we take random values for type and size, as these will be set to suitable values later
        if not fo.sys_get_planets(home_system):
            print "Home system", home_system, "has no planets, adding one"
            planet = fo.create_planet(random.choice(planet_sizes_real),
                                      random.choice(planet_types_real),
                                      home_system, random.randint(0, fo.sys_get_num_orbits(home_system) - 1), "")
            # if we couldn't create the planet, report an error and return an empty list
            if planet == fo.invalid_object():
                report_error("Python generate_home_system_list: couldn't create planet in home system")
                return []

    # finally, check again if all home systems meet the criteria of having the required minimum number of planets
    # within their near vicinity, if not, add the missing number of planets
    print "Checking if home systems have the required minimum of planets within the near vicinity..."
    for home_system in home_systems:
        # calculate the number of missing planets, and add them if this number is > 0
        systems_in_vicinity = get_systems_within_jumps(home_system, HS_VICINITY_RANGE)
        num_systems_in_vicinity = len(systems_in_vicinity)
        num_planets_in_vicinity = count_planets_in_systems(systems_in_vicinity)
        num_planets_to_add = min_planets_in_vicinity_limit(num_systems_in_vicinity) - num_planets_in_vicinity
        print "Home system", home_system, "has", num_systems_in_vicinity, "systems and", num_planets_in_vicinity,\
            "planets in the near vicinity, required minimum:", min_planets_in_vicinity_limit(num_systems_in_vicinity)
        if num_planets_to_add > 0:
            systems_in_vicinity.remove(home_system)  # don't add planets to the home system, so remove it from the list
            add_planets_to_vicinity(systems_in_vicinity, num_planets_to_add, gsd)

    # as we've sorted the home system list before, lets shuffle it to ensure random order and return
    random.shuffle(home_systems)
    return home_systems
예제 #9
0
def add_planets_to_vicinity(vicinity, num_planets, gsd):
    """
    Adds the specified number of planets to the specified systems.
    """
    print "Adding", num_planets, "planets to the following systems:", vicinity

    # first, compile a list containing all the free orbits in the specified systems
    # begin with adding the free orbits of all systems that have a real star (that is, no neutron star, black hole,
    # and not no star), if that isn't enough, also one, by one, add the free orbits of neutron star, black hole and
    # no star systems (in that order) until we have enough free orbits

    # for that, we use this list of tuples
    # the first tuple contains all real star types, the following tuples the neutron, black hole and no star types,
    # so we can iterate over this list and only add the free orbits of systems that match the respective star types
    # each step
    # this way we can prioritize the systems we want to add planets to by star type
    acceptable_star_types_list = [
        star_types_real,
        (fo.starType.noStar,),
        (fo.starType.neutron,),
        (fo.starType.blackHole,)
    ]

    # store the free orbits as a list of tuples of (system, orbit)
    free_orbits_map = []

    # now, iterate over the list of acceptable star types
    for acceptable_star_types in acceptable_star_types_list:
        # check all systems in the list of systems we got passed into this function
        for system in vicinity:
            # if this system has a star type we want to accept in this step, add its free orbits to our list
            if fo.sys_get_star_type(system) in acceptable_star_types:
                free_orbits_map.extend([(system, orbit) for orbit in fo.sys_free_orbits(system)])
        # check if we got enough free orbits after completing this step
        # we want 4 times as much free orbits as planets we want to add, that means each system shouldn't get more
        # than 2-3 additional planets on average
        if len(free_orbits_map) > (num_planets * 4):
            break

    # if we got less free orbits than planets that should be added, something is wrong
    # in that case abort and log an error
    if len(free_orbits_map) < num_planets:
        report_error("Python add_planets_to_vicinity: less free orbits than planets to add - cancelled")

    print "...free orbits available:", free_orbits_map
    # as we will pop the free orbits from this list afterwards, shuffle it to randomize the order of the orbits
    random.shuffle(free_orbits_map)

    # add the requested number of planets
    while num_planets > 0:
        # get the next free orbit from the list we just compiled
        system, orbit = free_orbits_map.pop()

        # check the star type of the system containing the orbit we got
        star_type = fo.sys_get_star_type(system)
        if star_type in [fo.starType.noStar, fo.starType.blackHole]:
            # if it is a black hole or has no star, change the star type
            # pick a star type, continue until we get a real star
            # don't accept neutron, black hole or no star
            print "...system picked to add a planet has star type", star_type
            while star_type not in star_types_real:
                star_type = pick_star_type(gsd.age)
            print "...change that to", star_type
            fo.sys_set_star_type(system, star_type)

        # pick a planet size, continue until we get a size that matches the HS_ACCEPTABLE_PLANET_SIZES option
        planet_size = fo.planetSize.unknown
        while planet_size not in HS_ACCEPTABLE_PLANET_SIZES:
            planet_size = calc_planet_size(star_type, orbit, fo.galaxySetupOption.high, gsd.shape)

        # pick an according planet type
        planet_type = calc_planet_type(star_type, orbit, planet_size)

        # finally, create the planet in the system and orbit we got
        print "...adding", planet_size, planet_type, "planet to system", system
        if fo.create_planet(planet_size, planet_type, system, orbit, "") == fo.invalid_object():
            report_error("Python add_planets_to_vicinity: create planet in system %d failed" % system)

        # continue with next planet
        num_planets -= 1
예제 #10
0
def compile_home_system_list(num_home_systems, systems):
    """
    Compiles a list with a requested number of home systems.
    """
    print "Compile home system list:", num_home_systems, "systems requested"

    # if the list of systems to choose home systems from is empty, report an error and return empty list
    if not systems:
        report_error(
            "Python generate_home_system_list: no systems to choose from")
        return []

    # calculate an initial minimal number of jumps that the home systems should be apart,
    # based on the total number of systems to choose from and the requested number of home systems
    # Don't let min_jumps be larger than 10, because a larger number is really not at all needed and with large
    # galaxies an excessive amount of time can be used in failed attempts
    min_jumps = min(
        10, max(int(float(len(systems)) / float(num_home_systems * 2)), 5))

    # home systems must have a certain minimum of systems in their near vicinity
    # we will try to select our home systems from systems that match this criteria, if that fails, we will select our
    # home systems from all systems and add the missing number planets to the systems in their vicinity afterwards
    # the minimum planet limit and the jump range that defines the "near vicinity" are controlled by the
    # HS_* option constants in options.py (see there)

    # lets start by filtering out all systems from the pool we got passed into this function that match the criteria
    filtered_pool = [s for s in systems if has_min_planets_in_vicinity(s)]
    print "Filtering out systems that meet the minimum planets in the near vicinity condition yielded",\
        len(filtered_pool), "systems"
    print "Using this as the preferred pool for home system selection"
    # now try to pick the requested number of home systems by calling find_home_systems
    # this function takes two pools, a "complete" pool and one with preferred systems
    # it will try to pick the home systems from the preferred pool first, so pass our filtered pool as preferred pool
    home_systems = find_home_systems(num_home_systems, systems, filtered_pool,
                                     min_jumps)

    # check if the selection process delivered a list with enough home systems
    # if not, our galaxy obviously is too crowded, report an error and return an empty list
    if len(home_systems) < num_home_systems:
        report_error(
            "Python generate_home_system_list: requested %d homeworlds in a galaxy with %d systems"
            % (num_home_systems, len(systems)))
        return []

    # check if we got more home systems than we requested
    if len(home_systems) > num_home_systems:
        # yes: calculate the number of planets in the near vicinity of each system
        # and store that value with each system in a map
        hs_planets_in_vicinity_map = {
            s: count_planets_in_systems(
                get_systems_within_jumps(s, HS_VICINITY_RANGE))
            for s in home_systems
        }
        # sort the home systems by the number of planets in their near vicinity using the map
        # now only pick the number of home systems we need, taking those with the highest number of planets
        home_systems = sorted(home_systems,
                              key=hs_planets_in_vicinity_map.get,
                              reverse=True)[:num_home_systems]

    # make sure all our home systems have a "real" star (that is, a star that is not a neutron star, black hole,
    # or even no star at all) and at least one planet in it
    for home_system in home_systems:
        # if this home system has no "real" star, change star type to a randomly selected "real" star
        if fo.sys_get_star_type(home_system) not in star_types_real:
            star_type = random.choice(star_types_real)
            print "Home system", home_system, "has star type", fo.sys_get_star_type(home_system),\
                  ", changing that to", star_type
            fo.sys_set_star_type(home_system, star_type)

        # if this home system has no planets, create one in a random orbit
        # we take random values for type and size, as these will be set to suitable values later
        if not fo.sys_get_planets(home_system):
            print "Home system", home_system, "has no planets, adding one"
            planet = fo.create_planet(
                random.choice(planet_sizes_real),
                random.choice(planet_types_real), home_system,
                random.randint(0,
                               fo.sys_get_num_orbits(home_system) - 1), "")
            # if we couldn't create the planet, report an error and return an empty list
            if planet == fo.invalid_object():
                report_error(
                    "Python generate_home_system_list: couldn't create planet in home system"
                )
                return []

    # finally, check again if all home systems meet the criteria of having the required minimum number of planets
    # within their near vicinity, if not, add the missing number of planets
    print "Checking if home systems have the required minimum of planets within the near vicinity..."
    for home_system in home_systems:
        # calculate the number of missing planets, and add them if this number is > 0
        systems_in_vicinity = get_systems_within_jumps(home_system,
                                                       HS_VICINITY_RANGE)
        num_systems_in_vicinity = len(systems_in_vicinity)
        num_planets_in_vicinity = count_planets_in_systems(systems_in_vicinity)
        num_planets_to_add = min_planets_in_vicinity_limit(
            num_systems_in_vicinity) - num_planets_in_vicinity
        print "Home system", home_system, "has", num_systems_in_vicinity, "systems and", num_planets_in_vicinity,\
            "planets in the near vicinity, required minimum:", min_planets_in_vicinity_limit(num_systems_in_vicinity)
        if num_planets_to_add > 0:
            systems_in_vicinity.remove(
                home_system
            )  # don't add planets to the home system, so remove it from the list
            add_planets_to_vicinity(systems_in_vicinity, num_planets_to_add)

    # as we've sorted the home system list before, lets shuffle it to ensure random order and return
    random.shuffle(home_systems)
    return home_systems
예제 #11
0
def compile_home_system_list(num_home_systems, systems):
    """
    Compiles a list with a requested number of home systems.
    """

    # if the list of systems to choose home systems from is empty, report an error and return empty list
    if not systems:
        util.report_error(
            "Python generate_home_system_list: no systems to choose from")
        return []

    # calculate an initial minimal number of jumps that the home systems should be apart,
    # based on the total number of systems to choose from and the requested number of home systems
    min_jumps = max(int(float(len(systems)) / float(num_home_systems * 2)), 5)
    # try to find the home systems, decrease the min jumps until enough systems can be found, or the min jump distance
    # gets reduced to 0 (meaning we don't have enough systems to choose from at all)
    while min_jumps > 0:
        print "Trying to find", num_home_systems, "home systems that are at least", min_jumps, "jumps apart"
        # try to find home systems...
        home_systems = find_systems_with_min_jumps_between(
            num_home_systems, systems, min_jumps)
        # ...check if we got enough...
        if len(home_systems) >= num_home_systems:
            # ...yes, we got what we need, so let's break out of the loop
            break
        print "Home system min jump conflict: %d systems and %d empires, tried %d min jump and failed"\
              % (len(systems), num_home_systems, min_jumps)
        # ...no, decrease the min jump distance and try again
        min_jumps -= 1

    # check if the loop above delivered a list with enough home systems, or if it exited because the min jump distance
    # has been decreased to 0 without finding enough systems
    # in that case, our galaxy obviously is too crowded, report an error and return an empty list
    if len(home_systems) < num_home_systems:
        util.report_error(
            "Python generate_home_system_list: requested %d homeworlds in a galaxy with %d systems"
            % (num_home_systems, len(systems)))
        return []

    # make sure all our home systems have a "real" star (that is, a star that is not a neutron star, black hole,
    # or even no star at all) and at least one planet in it
    for home_system in home_systems:
        # if this home system has no "real" star, change star type to a randomly selected "real" star
        if fo.sys_get_star_type(
                home_system) not in starsystems.star_types_real:
            star_type = random.choice(starsystems.star_types_real)
            print "Home system", home_system, "has star type", fo.sys_get_star_type(home_system),\
                  ", changing that to", star_type
            fo.sys_set_star_type(home_system, star_type)

        # if this home system has no planets, create one in a random orbit
        # we take random values for type and size, as these will be set to suitable values later
        if not fo.sys_get_planets(home_system):
            print "Home system", home_system, "has no planets, adding one"
            planet = fo.create_planet(
                random.choice(planets.planet_sizes_real),
                random.choice(planets.planet_types_real), home_system,
                random.randint(0,
                               fo.sys_get_num_orbits(home_system) - 1), "")
            # if we couldn't create the planet, report an error and return an empty list
            if planet == fo.invalid_object():
                util.report_error(
                    "Python generate_home_system_list: couldn't create planet in home system"
                )
                return []

    return home_systems
예제 #12
0
파일: empires.py 프로젝트: b606/freeorion
def compile_home_system_list(num_home_systems, systems):
    """
    Compiles a list with a requested number of home systems.
    """
    print "Compile home system list:", num_home_systems, "systems requested"

    # if the list of systems to choose home systems from is empty, report an error and return empty list
    if not systems:
        report_error("Python generate_home_system_list: no systems to choose from")
        return []

    # calculate an initial minimal number of jumps that the home systems should be apart,
    # based on the total number of systems to choose from and the requested number of home systems
    # Don't let min_jumps be larger than 10, because a larger number is really not at all needed and with large
    # galaxies an excessive amount of time can be used in failed attempts
    min_jumps = min(10, max(int(float(len(systems)) / float(num_home_systems * 2)), 5))

    # home systems must have a certain minimum of systems in their near vicinity
    # we will try to select our home systems from systems that match this criteria, if that fails, we will select our
    # home systems from all systems and add the missing number planets to the systems in their vicinity afterwards
    # the minimum planet limit and the jump range that defines the "near vicinity" are controlled by the
    # HS_* option constants in options.py (see there)

    # lets start by filtering out all systems from the pool we got passed into this function that match the criteria
    filtered_pool = [s for s in systems if has_min_planets_in_vicinity(s)]
    print "Filtering out systems that meet the minimum planets in the near vicinity condition yielded",\
        len(filtered_pool), "systems"
    print "Using this as the preferred pool for home system selection"
    # now try to pick the requested number of home systems by calling find_home_systems
    # this function takes two pools, a "complete" pool and one with preferred systems
    # it will try to pick the home systems from the preferred pool first, so pass our filtered pool as preferred pool
    home_systems = find_home_systems(num_home_systems, systems, filtered_pool, min_jumps)

    # check if the selection process delivered a list with enough home systems
    # if not, our galaxy obviously is too crowded, report an error and return an empty list
    if len(home_systems) < num_home_systems:
        report_error("Python generate_home_system_list: requested %d homeworlds in a galaxy with %d systems"
                     % (num_home_systems, len(systems)))
        return []

    # check if we got more home systems than we requested
    if len(home_systems) > num_home_systems:
        # yes: calculate the number of planets in the near vicinity of each system
        # and store that value with each system in a map
        hs_planets_in_vicinity_map = {s: count_planets_in_systems(get_systems_within_jumps(s, HS_VICINITY_RANGE))
                                      for s in home_systems}
        # sort the home systems by the number of planets in their near vicinity using the map
        # now only pick the number of home systems we need, taking those with the highest number of planets
        home_systems = sorted(home_systems, key=hs_planets_in_vicinity_map.get, reverse=True)[:num_home_systems]

    # make sure all our home systems have a "real" star (that is, a star that is not a neutron star, black hole,
    # or even no star at all) and at least one planet in it
    for home_system in home_systems:
        # if this home system has no "real" star, change star type to a randomly selected "real" star
        if fo.sys_get_star_type(home_system) not in star_types_real:
            star_type = random.choice(star_types_real)
            print "Home system", home_system, "has star type", fo.sys_get_star_type(home_system),\
                  ", changing that to", star_type
            fo.sys_set_star_type(home_system, star_type)

        # if this home system has no planets, create one in a random orbit
        # we take random values for type and size, as these will be set to suitable values later
        if not fo.sys_get_planets(home_system):
            print "Home system", home_system, "has no planets, adding one"
            planet = fo.create_planet(random.choice(planet_sizes_real),
                                      random.choice(planet_types_real),
                                      home_system, random.randint(0, fo.sys_get_num_orbits(home_system) - 1), "")
            # if we couldn't create the planet, report an error and return an empty list
            if planet == fo.invalid_object():
                report_error("Python generate_home_system_list: couldn't create planet in home system")
                return []

    # finally, check again if all home systems meet the criteria of having the required minimum number of planets
    # within their near vicinity, if not, add the missing number of planets
    print "Checking if home systems have the required minimum of planets within the near vicinity..."
    for home_system in home_systems:
        # calculate the number of missing planets, and add them if this number is > 0
        systems_in_vicinity = get_systems_within_jumps(home_system, HS_VICINITY_RANGE)
        num_systems_in_vicinity = len(systems_in_vicinity)
        num_planets_in_vicinity = count_planets_in_systems(systems_in_vicinity)
        num_planets_to_add = min_planets_in_vicinity_limit(num_systems_in_vicinity) - num_planets_in_vicinity
        print "Home system", home_system, "has", num_systems_in_vicinity, "systems and", num_planets_in_vicinity,\
            "planets in the near vicinity, required minimum:", min_planets_in_vicinity_limit(num_systems_in_vicinity)
        if num_planets_to_add > 0:
            systems_in_vicinity.remove(home_system)  # don't add planets to the home system, so remove it from the list
            add_planets_to_vicinity(systems_in_vicinity, num_planets_to_add)

    # as we've sorted the home system list before, lets shuffle it to ensure random order and return
    random.shuffle(home_systems)
    return home_systems