Beispiel #1
0
def place_special(specials, obj):
    """
    Place at most a single special.
    Return the number of specials placed.
    """
    # Calculate the conditional probabilities that each special is
    # placed here given that a special will be placed here.
    probs = [fo.special_spawn_rate(sp) for sp in specials]
    total_prob = float(sum(probs))
    if total_prob == 0:
        # This shouldn't happen since special_spawn_rate > 0.0 is checked in distribute_specials()
        return 0
    thresholds = [x / total_prob for x in probs]

    chance = random.random()
    for threshold, special in zip(thresholds, specials):
        if chance > threshold:
            chance -= threshold
            continue

        fo.add_special(obj, special)
        print("Special", special, "added to", fo.get_name(obj))
        universe_statistics.specials_summary[special] += 1

        return 1
    return 0
Beispiel #2
0
def place_special(specials, obj):
    """
    Place at most a single special.
    Return the number of specials placed.
    """
    # Calculate the conditional probabilities that each special is
    # placed here given that a special will be placed here.
    probs = [fo.special_spawn_rate(sp) for sp in specials]
    total_prob = float(sum(probs))
    if total_prob == 0:
        # This shouldn't happen since special_spawn_rate > 0.0 is checked in distribute_specials()
        return 0
    thresholds = [x / total_prob for x in probs]

    chance = random.random()
    for threshold, special in zip(thresholds, specials):
        if chance > threshold:
            chance -= threshold
            continue

        fo.add_special(obj, special)
        print "Special", special, "added to", fo.get_name(obj)
        universe_statistics.specials_summary[special] += 1

        return 1
    return 0
Beispiel #3
0
def distribute_specials(specials_freq, universe_objects):
    """
    Adds start-of-game specials to universe objects.
    """
    # get basic chance for occurrence of specials from the universe tables
    base_chance = universe_tables.SPECIALS_FREQUENCY[specials_freq]
    if base_chance <= 0:
        return

    # get a list with all specials that have a spawn rate and limit both > 0 and a location condition defined
    # (no location condition means a special shouldn't get added at game start)
    specials = [
        sp for sp in fo.get_all_specials() if fo.special_spawn_rate(sp) > 0.0
        and fo.special_spawn_limit(sp) > 0 and fo.special_has_location(sp)
    ]
    if not specials:
        return

    # dump a list of all specials meeting that conditions and their properties to the log
    print("Specials available for distribution at game start:")
    for special in specials:
        print("... {:30}: spawn rate {:2.3f} / spawn limit {}".format(
            special, fo.special_spawn_rate(special),
            fo.special_spawn_limit(special)))

    objects_needing_specials = [
        obj for obj in universe_objects if random.random() < base_chance
    ]

    track_num_placed = {obj: 0 for obj in universe_objects}

    print(
        "Base chance for specials is {}. Placing specials on {} of {} ({:1.4f})objects"
        .format(
            base_chance,
            len(objects_needing_specials),
            len(universe_objects),
            float(len(objects_needing_specials)) / len(universe_objects),
        ))

    obj_tuple_needing_specials = set(
        zip(
            objects_needing_specials,
            fo.objs_get_systems(objects_needing_specials),
            calculate_number_of_specials_to_place(objects_needing_specials),
        ))

    # Equal to the largest distance in WithinStarlaneJumps conditions
    # GALAXY_DECOUPLING_DISTANCE is used as follows.  For any two or more objects
    # at least GALAXY_DECOUPLING_DISTANCE appart you only need to check
    # fo.special_locations once and then you can place as many specials as possible,
    # subject to number restrictions.
    #
    # Organize the objects into sets where all objects are spaced GALAXY_DECOUPLING_DISTANCE
    # appart.  Place a special on each one.  Repeat until you run out of specials or objects.
    GALAXY_DECOUPLING_DISTANCE = 6

    while obj_tuple_needing_specials:
        systems_needing_specials = defaultdict(set)
        for (obj, system, specials_count) in obj_tuple_needing_specials:
            systems_needing_specials[system].add((obj, system, specials_count))

        print(" Placing in {} locations remaining.".format(
            len(systems_needing_specials)))

        # Find a list of candidates all spaced GALAXY_DECOUPLING_DISTANCE apart
        candidates = []
        while systems_needing_specials:
            random_sys = random.choice(list(systems_needing_specials.values()))
            member = random.choice(list(random_sys))
            obj, system, specials_count = member
            candidates.append(obj)
            obj_tuple_needing_specials.remove(member)
            if specials_count > 1:
                obj_tuple_needing_specials.add(
                    (obj, system, specials_count - 1))

            # remove all neighbors from the local pool
            for neighbor in fo.systems_within_jumps_unordered(
                    GALAXY_DECOUPLING_DISTANCE, [system]):
                if neighbor in systems_needing_specials:
                    systems_needing_specials.pop(neighbor)

        print("Caching specials_locations() at {} of {} remaining locations.".
              format(str(len(candidates)),
                     str(len(obj_tuple_needing_specials) + len(candidates))))
        # Get the locations at which each special can be placed
        locations_cache = {}
        for special in specials:
            # The fo.special_locations in the following line consumes most of the time in this
            # function.  Decreasing GALAXY_DECOUPLING_DISTANCE will speed up the whole
            # function by reducing the number of times this needs to be called.
            locations_cache[special] = set(
                fo.special_locations(special, candidates))

        # Attempt to apply a special to each candidate
        # by finding a special that can be applied to it and hasn't been added too many times
        for obj in candidates:

            # check if the spawn limit for this special has already been reached (that is, if this special
            # has already been added the maximal allowed number of times)
            specials = [
                s for s in specials if universe_statistics.specials_summary[s]
                < fo.special_spawn_limit(s)
            ]
            if not specials:
                break

            # Find which specials can be placed at this one location
            local_specials = [
                sp for sp in specials if obj in locations_cache[sp]
            ]
            if not local_specials:
                universe_statistics.specials_repeat_dist[0] += 1
                continue

            # All prerequisites and the test have been met, now add this special to this universe object.
            track_num_placed[obj] += place_special(local_specials, obj)

    for num_placed in track_num_placed.values():
        universe_statistics.specials_repeat_dist[num_placed] += 1
Beispiel #4
0
def distribute_specials(specials_freq, universe_objects):
    """
    Adds start-of-game specials to universe objects.
    """

    # get basic chance for occurrence of specials from the universe tables
    # the values there are integers, so we have to divide them by 10,000 to get the actual basic probability value
    basic_chance = float(fo.specials_frequency(specials_freq)) / 10000.0
    if basic_chance <= 0:
        return

    # get a list with all specials that have a spawn rate and limit both > 0 and a location condition defined
    # (no location condition means a special shouldn't get added at game start)
    specials = [
        sp for sp in fo.get_all_specials() if fo.special_spawn_rate(sp) > 0.0
        and fo.special_spawn_limit(sp) > 0 and fo.special_has_location(sp)
    ]
    if not specials:
        return
    # dump a list of all specials meeting that conditions and their properties to the log
    print "Specials available for distribution at game start:"
    for special in specials:
        print "...", special, ": spawn rate", fo.special_spawn_rate(special),\
              "/ spawn limit", fo.special_spawn_limit(special)

    # attempt to apply a special to each universe object in the list that has been passed to this function
    # by finding a special that can be applied to it and hasn't been added too many times, and then attempt
    # to add that special by testing its spawn rate
    repeat_rate = {1: 0.08, 2: 0.05, 3: 0.01, 4: 0.00}
    for univ_obj in universe_objects:
        # for this universe object, find a suitable special
        # start by shuffling our specials list, so each time the specials are considered in a new random order
        random.shuffle(specials)
        num_here = 0

        # then, consider each special until one has been found or we run out of specials
        # (the latter case means that no special is added to this universe object)
        for special in specials:
            # check if the spawn limit for this special has already been reached (that is, if this special
            # has already been added the maximal allowed number of times)
            if statistics.specials_summary[special] >= fo.special_spawn_limit(
                    special):
                # if yes, consider next special
                continue

            # check if this universe object matches the location condition for this special
            # (meaning, if this special can be added to this universe object at all)
            if not fo.special_location(special, univ_obj):
                # if not, consider next special
                continue

            # we have found a special that meets all prerequisites
            # now do the test if we want to add the selected special to this universe object by making a roll against
            # the basic probability multiplied by the spawn rate of the special
            if random.random() > basic_chance * fo.special_spawn_rate(special):
                # no, test failed, break out of the specials loop and continue with the next universe object
                statistics.specials_repeat_dist[num_here] += 1
                break
            num_here += 1

            # all prerequisites and the test have been met, now add this special to this universe object
            fo.add_special(univ_obj, special)
            # increase the statistic counter for this special, so we can keep track of how often it has already
            # been added (needed for the spawn limit test above, and to dump some statistics to the log later)
            statistics.specials_summary[special] += 1
            print "Special", special, "added to", fo.get_name(univ_obj)

            # stop attempting to add specials here?  give a small chance to try more than one special
            if random.random() > repeat_rate.get(num_here, 0.0):
                # sorry, no, break out of the specials loop and continue with the next universe object
                statistics.specials_repeat_dist[num_here] += 1
                break
        else:
            statistics.specials_repeat_dist[num_here] += 1
Beispiel #5
0
def distribute_specials(specials_freq, universe_objects):
    """
    Adds start-of-game specials to universe objects.
    """
    # get basic chance for occurrence of specials from the universe tables
    base_chance = universe_tables.SPECIALS_FREQUENCY[specials_freq]
    if base_chance <= 0:
        return

    # get a list with all specials that have a spawn rate and limit both > 0 and a location condition defined
    # (no location condition means a special shouldn't get added at game start)
    specials = [sp for sp in fo.get_all_specials() if fo.special_spawn_rate(sp) > 0.0 and
                fo.special_spawn_limit(sp) > 0 and fo.special_has_location(sp)]
    if not specials:
        return

    # dump a list of all specials meeting that conditions and their properties to the log
    print "Specials available for distribution at game start:"
    for special in specials:
        print("... {:30}: spawn rate {:2.3f} / spawn limit {}".
              format(special, fo.special_spawn_rate(special), fo.special_spawn_limit(special)))

    objects_needing_specials = [obj for obj in universe_objects if random.random() < base_chance]

    track_num_placed = {obj: 0 for obj in universe_objects}

    print("Base chance for specials is {}. Placing specials on {} of {} ({:1.4f})objects"
          .format(base_chance, len(objects_needing_specials), len(universe_objects),
                  float(len(objects_needing_specials)) / len(universe_objects)))

    obj_tuple_needing_specials = set(zip(objects_needing_specials,
                                         fo.objs_get_systems(objects_needing_specials),
                                         calculate_number_of_specials_to_place(objects_needing_specials)))

    # Equal to the largest distance in WithinStarlaneJumps conditions
    # GALAXY_DECOUPLING_DISTANCE is used as follows.  For any two or more objects
    # at least GALAXY_DECOUPLING_DISTANCE appart you only need to check
    # fo.special_locations once and then you can place as many specials as possible,
    # subject to number restrictions.
    #
    # Organize the objects into sets where all objects are spaced GALAXY_DECOUPLING_DISTANCE
    # appart.  Place a special on each one.  Repeat until you run out of specials or objects.
    GALAXY_DECOUPLING_DISTANCE = 6

    while obj_tuple_needing_specials:
        systems_needing_specials = defaultdict(set)
        for (obj, system, specials_count) in obj_tuple_needing_specials:
            systems_needing_specials[system].add((obj, system, specials_count))

        print " Placing in {} locations remaining.".format(len(systems_needing_specials))

        # Find a list of candidates all spaced GALAXY_DECOUPLING_DISTANCE apart
        candidates = []
        while systems_needing_specials:
            random_sys = random.choice(systems_needing_specials.values())
            member = random.choice(list(random_sys))
            obj, system, specials_count = member
            candidates.append(obj)
            obj_tuple_needing_specials.remove(member)
            if specials_count > 1:
                obj_tuple_needing_specials.add((obj, system, specials_count - 1))

            # remove all neighbors from the local pool
            for neighbor in fo.systems_within_jumps_unordered(GALAXY_DECOUPLING_DISTANCE, [system]):
                if neighbor in systems_needing_specials:
                    systems_needing_specials.pop(neighbor)

        print("Caching specials_locations() at {} of {} remaining locations.".
              format(str(len(candidates)), str(len(obj_tuple_needing_specials) + len(candidates))))
        # Get the locations at which each special can be placed
        locations_cache = {}
        for special in specials:
            # The fo.special_locations in the following line consumes most of the time in this
            # function.  Decreasing GALAXY_DECOUPLING_DISTANCE will speed up the whole
            # function by reducing the number of times this needs to be called.
            locations_cache[special] = set(fo.special_locations(special, candidates))

        # Attempt to apply a special to each candidate
        # by finding a special that can be applied to it and hasn't been added too many times
        for obj in candidates:

            # check if the spawn limit for this special has already been reached (that is, if this special
            # has already been added the maximal allowed number of times)
            specials = [s for s in specials if universe_statistics.specials_summary[s] < fo.special_spawn_limit(s)]
            if not specials:
                break

            # Find which specials can be placed at this one location
            local_specials = [sp for sp in specials if obj in locations_cache[sp]]
            if not local_specials:
                universe_statistics.specials_repeat_dist[0] += 1
                continue

            # All prerequisites and the test have been met, now add this special to this universe object.
            track_num_placed[obj] += place_special(local_specials, obj)

    for num_placed in track_num_placed.values():
        universe_statistics.specials_repeat_dist[num_placed] += 1
Beispiel #6
0
def distribute_specials(specials_freq, universe_objects):
    """
    Adds start-of-game specials to universe objects.
    """

    # get basic chance for occurrence of specials from the universe tables
    # the values there are integers, so we have to divide them by 10,000 to get the actual basic probability value
    basic_chance = float(fo.specials_frequency(specials_freq)) / 10000.0
    if basic_chance <= 0:
        return

    # get a list with all specials that have a spawn rate and limit both > 0 and a location condition defined
    # (no location condition means a special shouldn't get added at game start)
    specials = [sp for sp in fo.get_all_specials() if fo.special_spawn_rate(sp) > 0.0 and
                fo.special_spawn_limit(sp) > 0 and fo.special_has_location(sp)]
    if not specials:
        return
    # dump a list of all specials meeting that conditions and their properties to the log
    print "Specials available for distribution at game start:"
    for special in specials:
        print "...", special, ": spawn rate", fo.special_spawn_rate(special),\
              "/ spawn limit", fo.special_spawn_limit(special)

    # attempt to apply a special to each universe object in the list that has been passed to this function
    # by finding a special that can be applied to it and hasn't been added too many times, and then attempt
    # to add that special by testing its spawn rate
    repeat_rate = {1 : 0.08, 2 : 0.05, 3 : 0.01, 4 : 0.00}
    for univ_obj in universe_objects:
        # for this universe object, find a suitable special
        # start by shuffling our specials list, so each time the specials are considered in a new random order
        random.shuffle(specials)
        num_here = 0

        # then, consider each special until one has been found or we run out of specials
        # (the latter case means that no special is added to this universe object)
        for special in specials:
            # check if the spawn limit for this special has already been reached (that is, if this special
            # has already been added the maximal allowed number of times)
            if statistics.specials_summary[special] >= fo.special_spawn_limit(special):
                # if yes, consider next special
                continue

            # check if this universe object matches the location condition for this special
            # (meaning, if this special can be added to this universe object at all)
            if not fo.special_location(special, univ_obj):
                # if not, consider next special
                continue

            # we have found a special that meets all prerequisites
            # now do the test if we want to add the selected special to this universe object by making a roll against
            # the basic probability multiplied by the spawn rate of the special
            if random.random() > basic_chance * fo.special_spawn_rate(special):
                # no, test failed, break out of the specials loop and continue with the next universe object
                statistics.specials_repeat_dist[num_here] += 1
                break
            num_here += 1

            # all prerequisites and the test have been met, now add this special to this universe object
            fo.add_special(univ_obj, special)
            # increase the statistic counter for this special, so we can keep track of how often it has already
            # been added (needed for the spawn limit test above, and to dump some statistics to the log later)
            statistics.specials_summary[special] += 1
            print "Special", special, "added to", fo.get_name(univ_obj)

            # stop attempting to add specials here?  give a small chance to try more than one special
            if random.random() > repeat_rate.get(num_here, 0.0):
                # sorry, no, break out of the specials loop and continue with the next universe object
                statistics.specials_repeat_dist[num_here] += 1
                break
        else:
                statistics.specials_repeat_dist[num_here] += 1