Exemple #1
0
def log_planet_count_dist(sys_list):

    planet_count_dist = {}
    planet_size_dist = {size: 0 for size in planets.planet_sizes}
    for system in sys_list:
        planet_count = 0
        for planet in fo.sys_get_planets(system):
            this_size = fo.planet_get_size(planet)
            if this_size in planets.planet_sizes:
                planet_count += 1
                planet_size_dist[this_size] += 1
        planet_count_dist.setdefault(planet_count, [0])[0] += 1
    planet_tally = sum(planet_size_dist.values())

    count_distribution_table = Table(
        [Text('planets in system'), Text('num of systems'), Float('% of systems', precession=1)],
        table_name='Planet Count Distribution'
    )
    for planet_count, sys_count in planet_count_dist.items():
        count_distribution_table.add_row((planet_count, sys_count[0], 100.0 * sys_count[0] / len(sys_list)))
    count_distribution_table.print_table()
    print

    size_distribution = Table(
        [Text('size'), Text('count'), Float('% of planets', precession=1)],
        table_name='Planet Size Distribution'
    )
    for planet_size, planet_count in sorted(planet_size_dist.items()):
        size_distribution.add_row((planet_size, planet_count, 100.0 * planet_count / planet_tally))
    size_distribution.print_table()
    print
def _report_classes_without_instances(classes_map, instance_names,
                                      classes_to_ignore: set):
    missed_instances = instance_names.symmetric_difference(
        classes_map).difference(classes_to_ignore)

    if not missed_instances:
        return

    warning("")
    warning(
        "In order to get more information about the classes in API we need to process an instances of thea classes."
    )
    warning(
        "Classes mentioned bellow does not have instances so their specs are not full."
    )
    warning("Please provide instances or add them to ignored,")
    warning(
        "check generate_stub usage in the freeorion/default/python/handlers folder."
    )
    warning("")

    table = Table([Text("classes")], )

    for inst in sorted(missed_instances, key=str.lower):
        table.add_row((str(inst), ))
    warning(table.get_table())
def log_planets():
    universe = fo.get_universe()

    planets_table = Table(
        [Text('id'), Text('name'), Text('system'), Text('type'),
         Sequence('specials'), Text('species'), Sequence('buildings')],
        table_name='Planets summary')
    # group planets by system
    for sid in fo.get_systems():
        for pid in fo.sys_get_planets(sid):
            planet = universe.getPlanet(pid)

            planet_type = fo.planet_get_type(pid).name
            planet_size = fo.planet_get_size(pid).name
            if planet_type != planet_size:
                planet_type = '%s %s' % (planet_type, planet_size)

            buildings = [universe.getBuilding(x).name for x in planet.buildingIDs]
            planets_table.add_row([
                pid, planet.name, planet.systemID, planet_type, list(planet.specials), planet.speciesName, buildings
            ])

    # Printing too much info at once will lead to truncation of text
    for line in planets_table.get_table().split('\n'):
        print line
def log_planets():
    universe = fo.get_universe()

    planets_table = Table([
        Text('id'),
        Text('name'),
        Text('system'),
        Text('type'),
        Sequence('specials'),
        Text('species'),
        Sequence('buildings')
    ],
                          table_name='Planets summary')
    # group planets by system
    for sid in fo.get_systems():
        for pid in fo.sys_get_planets(sid):
            planet = universe.getPlanet(pid)

            planet_type = fo.planet_get_type(pid).name
            planet_size = fo.planet_get_size(pid).name
            if planet_type != planet_size:
                planet_type = '%s %s' % (planet_type, planet_size)

            buildings = [
                universe.getBuilding(x).name for x in planet.buildingIDs
            ]
            planets_table.add_row([
                pid, planet.name, planet.systemID, planet_type,
                list(planet.specials), planet.speciesName, buildings
            ])

    # Printing too much info at once will lead to truncation of text
    for line in planets_table.get_table().split('\n'):
        print line
def test_empty_table():
    empty = Table(
        [Text('name', description='Name for first column'), Float('value', description='VValue'),
         Sequence('zzz'), Sequence('zzzzzzzzzzzzzzzzzz')],
        table_name='Wooho'
    )
    assert empty.get_table() == EXPECTED_EMPTY_TABLE
Exemple #6
0
 def __report_system_threats(self):
     """Print a table with system threats to the logfile."""
     current_turn = fo.currentTurn()
     if current_turn >= 100:
         return
     threat_table = Table([
         Text('System'), Text('Vis.'), Float('Total'), Float('by Monsters'), Float('by Fleets'),
         Float('by Planets'), Float('1 jump away'), Float('2 jumps'), Float('3 jumps')],
         table_name="System Threat Turn %d" % current_turn
     )
     universe = fo.getUniverse()
     for sys_id in universe.systemIDs:
         sys_status = self.systemStatus.get(sys_id, {})
         system = universe.getSystem(sys_id)
         threat_table.add_row([
             system,
             "Yes" if sys_status.get('currently_visible', False) else "No",
             sys_status.get('totalThreat', 0),
             sys_status.get('monsterThreat', 0),
             sys_status.get('fleetThreat', 0),
             sys_status.get('planetThreat', 0),
             sys_status.get('neighborThreat', 0.0),
             sys_status.get('jump2_threat', 0.0),
             sys_status.get('jump3_threat', 0.0),
         ])
     info(threat_table)
Exemple #7
0
 def __report_system_threats(self):
     """Print a table with system threats to the logfile."""
     current_turn = fo.currentTurn()
     if current_turn >= 100:
         return
     threat_table = Table([
         Text('System'), Text('Vis.'), Float('Total'), Float('by Monsters'), Float('by Fleets'),
         Float('by Planets'), Float('1 jump away'), Float('2 jumps'), Float('3 jumps')],
         table_name="System Threat Turn %d" % current_turn
     )
     universe = fo.getUniverse()
     for sys_id in universe.systemIDs:
         sys_status = self.systemStatus.get(sys_id, {})
         system = universe.getSystem(sys_id)
         threat_table.add_row([
             system,
             "Yes" if sys_status.get('currently_visible', False) else "No",
             sys_status.get('totalThreat', 0),
             sys_status.get('monsterThreat', 0),
             sys_status.get('fleetThreat', 0),
             sys_status.get('planetThreat', 0),
             sys_status.get('neighborThreat', 0.0),
             sys_status.get('jump2_threat', 0.0),
             sys_status.get('jump3_threat', 0.0),
         ])
     info(threat_table)
Exemple #8
0
    def print_resources_priority():
        """Calculate top resource priority."""
        universe = fo.getUniverse()
        empire = fo.getEmpire()
        empire_planet_ids = PlanetUtilsAI.get_owned_planets_by_empire(
            universe.planetIDs)
        debug("Resource Priorities:")
        resource_priorities = {}
        aistate = get_aistate()
        for priority_type in get_priority_resource_types():
            resource_priorities[priority_type] = aistate.get_priority(
                priority_type)

        sorted_priorities = sorted(resource_priorities.items(),
                                   key=itemgetter(1),
                                   reverse=True)
        top_priority = -1
        for evaluation_priority, evaluation_score in sorted_priorities:
            if top_priority < 0:
                top_priority = evaluation_priority
            debug("  %s: %.2f", evaluation_priority, evaluation_score)

        # what is the focus of available resource centers?
        debug('')
        warnings = {}
        foci_table = Table([
            Text('Planet'),
            Text('Size'),
            Text('Type'),
            Text('Focus'),
            Text('Species'),
            Text('Pop')
        ],
                           table_name="Planetary Foci Overview Turn %d" %
                           fo.currentTurn())
        for pid in empire_planet_ids:
            planet = universe.getPlanet(pid)
            population = planet.currentMeterValue(fo.meterType.population)
            max_population = planet.currentMeterValue(
                fo.meterType.targetPopulation)
            if max_population < 1 and population > 0:
                warnings[planet.name] = (population, max_population)
            foci_table.add_row([
                planet, planet.size, planet.type,
                "_".join(str(planet.focus).split("_")[1:])[:8],
                planet.speciesName,
                "%.1f/%.1f" % (population, max_population)
            ])
        info(foci_table)
        debug(
            "Empire Totals:\nPopulation: %5d \nProduction: %5d\nResearch: %5d\n",
            empire.population(), empire.productionPoints,
            empire.resourceProduction(fo.resourceType.research))
        for name, (cp, mp) in warnings.items():
            warn(
                "Population Warning! -- %s has unsustainable current pop %d -- target %d",
                name, cp, mp)
Exemple #9
0
def test_empty_table():
    empty = Table(
        [
            Text("name", description="Name for first column"),
            Float("value", description="VValue"),
            Sequence("zzz"),
            Sequence("zzzzzzzzzzzzzzzzzz"),
        ],
        table_name="Wooho",
    )
    assert empty.get_table() == EXPECTED_EMPTY_TABLE
Exemple #10
0
def log_planet_count_dist(sys_list):

    planet_count_dist = {}
    planet_size_dist = {size: 0 for size in planets.planet_sizes}
    for system in sys_list:
        planet_count = 0
        for planet in fo.sys_get_planets(system):
            this_size = fo.planet_get_size(planet)
            if this_size in planets.planet_sizes:
                planet_count += 1
                planet_size_dist[this_size] += 1
        planet_count_dist.setdefault(planet_count, [0])[0] += 1
    planet_tally = sum(planet_size_dist.values())

    count_distribution_table = Table(
        [Text('planets in system'), Text('num of systems'), Float('% of systems', precession=1)],
        table_name='Planet Count Distribution'
    )
    for planet_count, sys_count in planet_count_dist.items():
        count_distribution_table.add_row((planet_count, sys_count[0], 100.0 * sys_count[0] / len(sys_list)))
    print(count_distribution_table)
    print()

    size_distribution = Table(
        [Text('size'), Text('count'), Float('% of planets', precession=1)],
        table_name='Planet Size Distribution'
    )
    for planet_size, planet_count in sorted(planet_size_dist.items()):
        size_distribution.add_row((planet_size, planet_count, 100.0 * planet_count / planet_tally))
    print(size_distribution)
    print()
Exemple #11
0
def log_monsters_summary(monster_freq):
    monster_place_table = Table(
        [Text('monster'), Text('count')], table_name='Monster placement')
    for monster, counter in sorted(monsters_summary):
        monster_place_table.add_row([monster, counter])
    print(monster_place_table)
    print()

    monster_chance = universe_tables.MONSTER_FREQUENCY[monster_freq]
    monster_table = Table(
        [
            Text('monster'),
            Float('chance'),
            Text('attempts'),
            Text('number placed'),
            Text('number valid sys locs'),
            Text('number valid nest planet locs')
        ],
        table_name=(
            "Space Monsters Placement Summary\n"
            "Tracked Monster and Nest Summary (base monster freq: %4.1f%%)" %
            (100 * monster_chance)))
    for monster in sorted(tracked_monsters_summary):
        monster_table.add_row((monster, tracked_monsters_chance[monster],
                               tracked_monsters_tries[monster],
                               tracked_monsters_summary[monster],
                               tracked_monsters_location_summary[monster],
                               tracked_nest_location_summary[monster]))
    print(monster_table)
    print()
Exemple #12
0
    def print_resources_priority():
        """Calculate top resource priority."""
        universe = fo.getUniverse()
        empire = fo.getEmpire()
        empire_planet_ids = PlanetUtilsAI.get_owned_planets_by_empire(universe.planetIDs)
        print "Resource Priorities:"
        resource_priorities = {}
        aistate = get_aistate()
        for priority_type in get_priority_resource_types():
            resource_priorities[priority_type] = aistate.get_priority(priority_type)

        sorted_priorities = resource_priorities.items()
        sorted_priorities.sort(lambda x, y: cmp(x[1], y[1]), reverse=True)
        top_priority = -1
        for evaluation_priority, evaluation_score in sorted_priorities:
            if top_priority < 0:
                top_priority = evaluation_priority
            print "  %s: %.2f" % (evaluation_priority, evaluation_score)

        # what is the focus of available resource centers?
        print
        warnings = {}
        foci_table = Table([
                Text('Planet'),
                Text('Size'),
                Text('Type'),
                Text('Focus'),
                Text('Species'),
                Text('Pop')
            ], table_name="Planetary Foci Overview Turn %d" % fo.currentTurn())
        for pid in empire_planet_ids:
            planet = universe.getPlanet(pid)
            population = planet.currentMeterValue(fo.meterType.population)
            max_population = planet.currentMeterValue(fo.meterType.targetPopulation)
            if max_population < 1 and population > 0:
                warnings[planet.name] = (population, max_population)
            foci_table.add_row([
                planet,
                planet.size,
                planet.type,
                "_".join(str(planet.focus).split("_")[1:])[:8],
                planet.speciesName,
                "%.1f/%.1f" % (population, max_population)
            ])
        info(foci_table)
        print "Empire Totals:\nPopulation: %5d \nProduction: %5d\nResearch: %5d\n" % (
            empire.population(), empire.productionPoints, empire.resourceProduction(fo.resourceType.research))
        for name, (cp, mp) in warnings.iteritems():
            print "Population Warning! -- %s has unsustainable current pop %d -- target %d" % (name, cp, mp)
def log_systems():
    universe = fo.get_universe()

    systems_table = Table(
        [Text('id'), Text('name'), Sequence('planets'), Sequence('connections'), Text('star')],
        table_name='System summary')
    for sid in fo.get_systems():
        system = universe.getSystem(sid)
        systems_table.add_row([
            sid, system.name, fo.sys_get_planets(sid), fo.sys_get_starlanes(sid), system.starType.name
        ])

    # Printing too much info at once will lead to truncation of text
    for line in systems_table.get_table().split('\n'):
        print line
Exemple #14
0
def log_systems():
    universe = fo.get_universe()

    systems_table = Table(
        [Text('id'), Text('name'), Sequence('planets'), Sequence('connections'), Text('star')],
        table_name='System summary')
    for sid in fo.get_systems():
        system = universe.getSystem(sid)
        systems_table.add_row([
            sid, system.name, fo.sys_get_planets(sid), fo.sys_get_starlanes(sid), system.starType.name
        ])

    # Printing too much info at once will lead to truncation of text
    for line in systems_table.get_table().split('\n'):
        print(line)
Exemple #15
0
def log_planet_type_summary(sys_list):
    planet_type_summary_table = {k: 0 for k in planets.planet_types}
    for system in sys_list:
        for planet in fo.sys_get_planets(system):
            planet_type_summary_table[fo.planet_get_type(planet)] += 1
    planet_total = sum(planet_type_summary_table.values())

    type_summary_table = Table(
        [Text('planet type', align='<'), Float('% of planets', precession=1)],
        table_name='Planet Type Summary for a total of %d placed planets' % planet_total
    )

    for planet_type, planet_count in sorted(planet_type_summary_table.items()):
        type_summary_table.add_row((planet_type.name, 100.0 * planet_count / planet_total))
    print(type_summary_table)
    print()
def log_planet_type_summary(sys_list):
    planet_type_summary_table = {k: 0 for k in planets.planet_types}
    for system in sys_list:
        for planet in fo.sys_get_planets(system):
            planet_type_summary_table[fo.planet_get_type(planet)] += 1
    planet_total = sum(planet_type_summary_table.values())

    type_summary_table = Table(
        [Text('planet type', align='<'), Float('% of planets', precession=1)],
        table_name='Planet Type Summary for a total of %d placed planets' % planet_total
    )

    for planet_type, planet_count in sorted(planet_type_summary_table.items()):
        type_summary_table.add_row((planet_type.name, 100.0 * planet_count / planet_total))
    print type_summary_table
    print
Exemple #17
0
def test_total_is_calculated():
    table = Table(
        Number("A", precession=0, total=True),
        Number("B", precession=0, total=True),
    )
    table.add_row(1, 10)
    table.add_row(2, 20)
    assert list(table) == [
        "============",
        "| A  | B   |",
        "============",
        "|  1 |  10 |",
        "|  2 |  20 |",
        "============",
        "|  3 |  30 |",
        "============",
    ]
Exemple #18
0
def test_empty_table():
    empty = Table(
        Text("name", description="Name for first column"),
        Number("value", description="VValue"),
        Sequence("zzz"),
        Sequence("zzzzzzzzzzzzzzzzzz"),
        table_name="Wooho",
    )

    io = StringIO()

    def writer(row):
        io.write(row)
        io.write("\n")

    empty.print_table(writer)

    assert io.getvalue() == EXPECTED_EMPTY_TABLE
Exemple #19
0
def log_specials_summary():
    special_placement_count_table = Table(
        [Text('special'), Text('times placed')],
        table_name="Special Placement Summary"
    )
    for special in sorted(specials_summary):
        special_placement_count_table.add_row([special, specials_summary[special]])
    special_placement_count_table.print_table()
    print

    special_placement = Table(
        [Text('count'), Text('tally'), Float('% of objects', precession=1)],
        table_name="Specials Count(Repeat) Distribution"
    )
    objects_tally = sum(specials_repeat_dist.values())
    for number, tally in specials_repeat_dist.items():
        special_placement.add_row((number, tally, 100.0 * tally / (1E-10 + objects_tally)))
    special_placement.print_table()
    print
Exemple #20
0
    def split_new_fleets(self):
        """Split any new fleets (at new game creation, can have unplanned mix of ship roles)."""
        universe = fo.getUniverse()
        mission_table = Table(
            [
                Text('Fleet'),
                Text('Mission'),
                Text('Ships'),
                Float('Rating'),
                Float('Troops'),
                Text('Target')
            ],
            table_name="Turn %d: Fleet Mission Review from Last Turn" %
            fo.currentTurn())
        for fleet_id, mission in self.get_fleet_missions_map().items():
            fleet = universe.getFleet(fleet_id)
            if not fleet:
                continue
            if not mission:
                mission_table.add_row([fleet])
            else:
                mission_table.add_row([
                    fleet, mission.type or "None",
                    len(fleet.shipIDs),
                    CombatRatingsAI.get_fleet_rating(fleet_id),
                    FleetUtilsAI.count_troops_in_fleet(fleet_id),
                    mission.target or "-"
                ])
        mission_table.print_table()
        # TODO: check length of fleets for losses or do in AIstat.__cleanRoles
        known_fleets = self.get_fleet_roles_map()
        self.newlySplitFleets.clear()

        fleets_to_split = [
            fleet_id for fleet_id in FleetUtilsAI.get_empire_fleet_ids()
            if fleet_id not in known_fleets
        ]

        if fleets_to_split:
            print "Splitting new fleets"
            for fleet_id in fleets_to_split:
                fleet = universe.getFleet(fleet_id)
                if not fleet:
                    print >> sys.stderr, "After splitting fleet: resulting fleet ID %d appears to not exist" % fleet_id
                    continue
                fleet_len = len(list(fleet.shipIDs))
                if fleet_len == 1:
                    continue
                new_fleets = FleetUtilsAI.split_fleet(
                    fleet_id)  # try splitting fleet
                print "\t from splitting fleet ID %4d with %d ships, got %d new fleets:" % (
                    fleet_id, fleet_len, len(new_fleets))
Exemple #21
0
 def report_system_threats(self):
     if fo.currentTurn() >= 100:
         return
     universe = fo.getUniverse()
     sys_id_list = sorted(universe.systemIDs)  # will normally look at this, the list of all known systems
     current_turn = fo.currentTurn()
     # assess fleet and planet threats
     threat_table = Table([
         Text('System'), Text('Vis.'), Float('Total'), Float('by Monsters'), Float('by Fleets'),
         Float('by Planets'), Float('1 jump away'), Float('2 jumps'), Float('3 jumps')],
         table_name="System Threat Turn %d" % current_turn
     )
     defense_table = Table([
         Text('System Defenses'), Float('Total'), Float('by Planets'), Float('by Fleets'),
         Float('Fleets 1 jump away'), Float('2 jumps'), Float('3 jumps')],
         table_name="System Defenses Turn %d" % current_turn
     )
     for sys_id in sys_id_list:
         sys_status = self.systemStatus.get(sys_id, {})
         system = universe.getSystem(sys_id)
         threat_table.add_row([
             system,
             "Yes" if sys_status.get('currently_visible', False) else "No",
             sys_status.get('totalThreat', 0),
             sys_status.get('monsterThreat', 0),
             sys_status.get('fleetThreat', 0),
             sys_status.get('planetThreat', 0),
             sys_status.get('neighborThreat', 0.0),
             sys_status.get('jump2_threat', 0.0),
             sys_status.get('jump3_threat', 0.0),
         ])
         defense_table.add_row([
             system,
             sys_status.get('all_local_defenses', 0.0),
             sys_status.get('mydefenses', {}).get('overall', 0.0),
             sys_status.get('myFleetRating', 0.0),
             sys_status.get('my_neighbor_rating', 0.0),
             sys_status.get('my_jump2_rating', 0.0),
             sys_status.get('my_jump3_rating', 0.0),
         ])
     threat_table.print_table()
     defense_table.print_table()
Exemple #22
0
def print_capital_info(homeworld):
    table = Table(
        Text("Id", description="Building id"),
        Text("Name"),
        Text("Type"),
        Sequence("Tags"),
        Sequence("Specials"),
        Text("Owner Id"),
        table_name="Buildings present at empire Capital in Turn %d" %
        fo.currentTurn(),
    )

    universe = fo.getUniverse()

    for building_id in homeworld.buildingIDs:
        building = universe.getBuilding(building_id)

        table.add_row(
            building_id,
            building.name,
            "_".join(building.buildingTypeName.split("_")[-2:]),
            sorted(building.tags),
            sorted(building.specials),
            building.owner,
        )

    table.print_table(info)
Exemple #23
0
def print_production_queue(after_turn=False):
    """Print production queue content with relevant info in table format."""
    universe = fo.getUniverse()
    s = "after" if after_turn else "before"
    title = "Production Queue Turn %d %s ProductionAI calls" % (
        fo.currentTurn(), s)
    prod_queue_table = Table(
        Text("Object"),
        Text("Location"),
        Text("Quantity"),
        Text("Progress"),
        Text("Allocated PP"),
        Text("Turns left"),
        table_name=title,
    )
    for element in fo.getEmpire().productionQueue:
        if element.buildType == EmpireProductionTypes.BT_SHIP:
            item = fo.getShipDesign(element.designID)
        elif element.buildType == EmpireProductionTypes.BT_BUILDING:
            item = fo.getBuildingType(element.name)
        else:
            continue
        cost = item.productionCost(fo.empireID(), element.locationID)

        prod_queue_table.add_row(
            element.name,
            universe.getPlanet(element.locationID),
            "%dx %d" % (element.remaining, element.blocksize),
            "%.1f / %.1f" % (element.progress * cost, cost),
            "%.1f" % element.allocation,
            "%d" % element.turnsLeft,
        )
    prod_queue_table.print_table(info)
Exemple #24
0
def __print_candidate_table(candidates, mission, show_detail=False):
    universe = fo.getUniverse()
    if mission == "Colonization":
        first_column = Text("Score/Species")

        def get_first_column_value(x):
            return round(x[0], 2), x[1]

    elif mission == "Outposts":
        first_column = Number("Score")
        get_first_column_value = itemgetter(0)
    else:
        warning("__print_candidate_table(%s, %s): Invalid mission type" % (candidates, mission))
        return
    columns = [first_column, Text("Planet"), Text("System"), Sequence("Specials")]
    if show_detail:
        columns.append(Sequence("Detail"))
    candidate_table = Table(*columns, table_name="Potential Targets for %s in Turn %d" % (mission, fo.currentTurn()))
    for planet_id, score_tuple in candidates:
        if score_tuple[0] > 0.5:
            planet = universe.getPlanet(planet_id)
            entries = [
                get_first_column_value(score_tuple),
                planet,
                universe.getSystem(planet.systemID),
                planet.specials,
            ]
            if show_detail:
                entries.append(score_tuple[-1])
            candidate_table.add_row(*entries)
    candidate_table.print_table(info)
def _report_classes_without_instances(classes_map: Iterable[str],
                                      instance_names,
                                      classes_to_ignore: Set[str]):
    missed_instances = instance_names.symmetric_difference(
        classes_map).difference(classes_to_ignore)

    if not missed_instances:
        return

    warning("")
    warning(
        fill(
            "In order to get more information about the classes in API"
            " we need to process an instances of classes."
            " Classes mentioned bellow does not have instances so their specs are not full."
            " Please provide instances or add them to ignored,"
            " check generate_stub usage in the"
            " freeorion/default/python/handlers folder.",
            width=60,
        ))

    table = Table(Text("classes without instances"))

    for inst in sorted(missed_instances, key=str.lower):
        table.add_row(inst)
    table.print_table(warning)
Exemple #26
0
def log_monsters_summary(monster_freq):
    monster_place_table = Table([Text('monster'), Text('count')], table_name='Monster placement')
    for monster, counter in sorted(monsters_summary):
        monster_place_table.add_row([monster, counter])
    monster_place_table.print_table()
    print

    monster_chance = universe_tables.MONSTER_FREQUENCY[monster_freq]
    monster_table = Table(
        [Text('monster'), Float('chance'), Text('attempts'),
         Text('number placed'), Text('number valid sys locs'), Text('number valid nest planet locs')],
        table_name=("Space Monsters Placement Summary\n"
                    "Tracked Monster and Nest Summary (base monster freq: %4.1f%%)" % (100 * monster_chance))
    )
    for monster in sorted(tracked_monsters_summary):
        monster_table.add_row(
            (monster, tracked_monsters_chance[monster],
             tracked_monsters_tries[monster], tracked_monsters_summary[monster],
             tracked_monsters_location_summary[monster], tracked_nest_location_summary[monster])
        )
    monster_table.print_table()
    print
Exemple #27
0
 def __report_last_turn_fleet_missions(self):
     """Print a table reviewing last turn fleet missions to the log file."""
     universe = fo.getUniverse()
     mission_table = Table(
             [Text('Fleet'), Text('Mission'), Text('Ships'), Float('Rating'), Float('Troops'), Text('Target')],
             table_name="Turn %d: Fleet Mission Review from Last Turn" % fo.currentTurn())
     for fleet_id, mission in self.get_fleet_missions_map().items():
         fleet = universe.getFleet(fleet_id)
         if not fleet:
             continue
         if not mission:
             mission_table.add_row([fleet])
         else:
             mission_table.add_row([
                 fleet,
                 mission.type or "None",
                 len(fleet.shipIDs),
                 CombatRatingsAI.get_fleet_rating(fleet_id),
                 FleetUtilsAI.count_troops_in_fleet(fleet_id),
                 mission.target or "-"
             ])
     info(mission_table)
Exemple #28
0
 def __report_system_defenses(self):
     """Print a table with system defenses to the logfile."""
     current_turn = fo.currentTurn()
     if current_turn >= 100:
         return
     defense_table = Table([
         Text('System Defenses'), Float('Total'), Float('by Planets'), Float('by Fleets'),
         Float('Fleets 1 jump away'), Float('2 jumps'), Float('3 jumps')],
             table_name="System Defenses Turn %d" % current_turn
     )
     universe = fo.getUniverse()
     for sys_id in universe.systemIDs:
         sys_status = self.systemStatus.get(sys_id, {})
         system = universe.getSystem(sys_id)
         defense_table.add_row([
             system,
             sys_status.get('all_local_defenses', 0.0),
             sys_status.get('mydefenses', {}).get('overall', 0.0),
             sys_status.get('myFleetRating', 0.0),
             sys_status.get('my_neighbor_rating', 0.0),
             sys_status.get('my_jump2_rating', 0.0),
             sys_status.get('my_jump3_rating', 0.0),
         ])
     info(defense_table)
Exemple #29
0
 def __report_system_defenses(self):
     """Print a table with system defenses to the logfile."""
     current_turn = fo.currentTurn()
     if current_turn >= 100:
         return
     defense_table = Table([
         Text('System Defenses'), Float('Total'), Float('by Planets'), Float('by Fleets'),
         Float('Fleets 1 jump away'), Float('2 jumps'), Float('3 jumps')],
             table_name="System Defenses Turn %d" % current_turn
     )
     universe = fo.getUniverse()
     for sys_id in universe.systemIDs:
         sys_status = self.systemStatus.get(sys_id, {})
         system = universe.getSystem(sys_id)
         defense_table.add_row([
             system,
             sys_status.get('all_local_defenses', 0.0),
             sys_status.get('mydefenses', {}).get('overall', 0.0),
             sys_status.get('myFleetRating', 0.0),
             sys_status.get('my_neighbor_rating', 0.0),
             sys_status.get('my_jump2_rating', 0.0),
             sys_status.get('my_jump3_rating', 0.0),
         ])
     info(defense_table)
Exemple #30
0
def log_specials_summary():
    special_placement_count_table = Table(
        [Text('special'), Text('times placed')],
        table_name="Special Placement Summary"
    )
    for special in sorted(specials_summary):
        special_placement_count_table.add_row([special, specials_summary[special]])
    print(special_placement_count_table)
    print()

    special_placement = Table(
        [Text('count'), Text('tally'), Float('% of objects', precession=1)],
        table_name="Specials Count(Repeat) Distribution"
    )
    objects_tally = sum(specials_repeat_dist.values())
    for number, tally in specials_repeat_dist.items():
        special_placement.add_row((number, tally, 100.0 * tally / (1E-10 + objects_tally)))
    print(special_placement)
    print()
Exemple #31
0
    def split_new_fleets(self):
        """Split any new fleets (at new game creation, can have unplanned mix of ship roles)."""
        universe = fo.getUniverse()
        mission_table = Table([Text('Fleet'), Text('Mission'), Text('Ships'), Float('Rating'), Float('Troops'), Text('Target')],
                              table_name="Turn %d: Fleet Mission Review from Last Turn" % fo.currentTurn())
        for fleet_id, mission in self.get_fleet_missions_map().items():
            fleet = universe.getFleet(fleet_id)
            if not fleet:
                continue
            if not mission:
                mission_table.add_row([fleet])
            else:
                mission_table.add_row([
                    fleet,
                    mission.type or "None",
                    len(fleet.shipIDs),
                    CombatRatingsAI.get_fleet_rating(fleet_id),
                    FleetUtilsAI.count_troops_in_fleet(fleet_id),
                    mission.target or "-"
                ])
        mission_table.print_table()
        # TODO: check length of fleets for losses or do in AIstat.__cleanRoles
        known_fleets = self.get_fleet_roles_map()
        self.newlySplitFleets.clear()

        fleets_to_split = [fleet_id for fleet_id in FleetUtilsAI.get_empire_fleet_ids() if fleet_id not in known_fleets]

        if fleets_to_split:
            print "Splitting new fleets"
            for fleet_id in fleets_to_split:
                fleet = universe.getFleet(fleet_id)
                if not fleet:
                    print >> sys.stderr, "After splitting fleet: resulting fleet ID %d appears to not exist" % fleet_id
                    continue
                fleet_len = len(list(fleet.shipIDs))
                if fleet_len == 1:
                    continue
                new_fleets = FleetUtilsAI.split_fleet(fleet_id)  # try splitting fleet
                print "\t from splitting fleet ID %4d with %d ships, got %d new fleets:" % (fleet_id, fleet_len, len(new_fleets))
Exemple #32
0
def _print_empire_species_roster():
    """Print empire species roster in table format to log."""
    grade_map = {"ULTIMATE": "+++", "GREAT": "++", "GOOD": "+", "AVERAGE": "o", "BAD": "-", "NO": "---"}

    grade_tags = [
        Tags.INDUSTRY,
        Tags.RESEARCH,
        Tags.POPULATION,
        Tags.SUPPLY,
        Tags.WEAPONS,
        Tags.ATTACKTROOPS,
    ]

    grade_tags_names = {
        Tags.INDUSTRY: "Ind.",
        Tags.RESEARCH: "Res.",
        Tags.POPULATION: "Pop.",
        Tags.SUPPLY: "Supply",
        Tags.WEAPONS: "Pilot",
        Tags.ATTACKTROOPS: "Troop",
    }

    species_table = Table(
        Text("species"),
        Sequence("PIDs"),
        Bool("Colonize"),
        Text("Shipyards"),
        *[Text(grade_tags_names[v]) for v in grade_tags],
        Sequence("Tags"),
        table_name="Empire species roster Turn %d" % fo.currentTurn(),
    )
    for species_name, planet_ids in get_empire_planets_by_species().items():
        species_tags = fo.getSpecies(species_name).tags
        number_of_shipyards = len(get_ship_builder_locations(species_name))
        species_table.add_row(
            species_name,
            planet_ids,
            can_build_colony_for_species(species_name),
            number_of_shipyards,
            *[grade_map.get(get_species_tag_grade(species_name, tag).upper(), "o") for tag in grade_tags],
            [tag for tag in species_tags if not any(s in tag for s in grade_tags) and "PEDIA" not in tag],
        )
    species_table.print_table(info)
Exemple #33
0
def log_planet_type_summary(sys_list):
    planet_type_summary_table = {k: 0 for k in planets.planet_types}
    for system in sys_list:
        for planet in fo.sys_get_planets(system):
            planet_type_summary_table[fo.planet_get_type(planet)] += 1
    planet_total = sum(planet_type_summary_table.values())

    type_summary_table = Table(
        Text("planet type", align="<"),
        Number("% of planets", precession=1),
        table_name="Planet Type Summary for a total of %d placed planets" %
        planet_total,
    )

    for planet_type, planet_count in sorted(planet_type_summary_table.items()):
        type_summary_table.add_row(
            planet_type.name,
            100.0 * planet_count / planet_total,
        )
    type_summary_table.print_table(print)
    print()
Exemple #34
0
def log_systems():
    universe = fo.get_universe()

    systems_table = Table(
        Text("id"),
        Text("name"),
        Sequence("planets"),
        Sequence("connections"),
        Text("star"),
        table_name="System summary",
    )
    for sid in fo.get_systems():
        system = universe.getSystem(sid)
        systems_table.add_row(
            sid,
            system.name,
            fo.sys_get_planets(sid),
            fo.sys_get_starlanes(sid),
            system.starType.name,
        )
    systems_table.print_table(print)
Exemple #35
0
 def __report_last_turn_fleet_missions(self):
     """Print a table reviewing last turn fleet missions to the log file."""
     universe = fo.getUniverse()
     mission_table = Table(
             [Text('Fleet'), Text('Mission'), Text('Ships'), Float('Rating'), Float('Troops'), Text('Target')],
             table_name="Turn %d: Fleet Mission Review from Last Turn" % fo.currentTurn())
     for fleet_id, mission in self.get_fleet_missions_map().items():
         fleet = universe.getFleet(fleet_id)
         if not fleet:
             continue
         if not mission:
             mission_table.add_row([fleet])
         else:
             mission_table.add_row([
                 fleet,
                 mission.type or "None",
                 len(fleet.shipIDs),
                 CombatRatingsAI.get_fleet_rating(fleet_id),
                 FleetUtilsAI.count_troops_in_fleet(fleet_id),
                 mission.target or "-"
             ])
     info(mission_table)
Exemple #36
0
def log_planets():
    universe = fo.get_universe()
    planets_table = Table(
        Text("id"),
        Text("name"),
        Text("system"),
        Text("type"),
        Sequence("specials"),
        Text("species"),
        Sequence("buildings"),
        table_name="Planets summary",
    )
    # group planets by system
    for sid in fo.get_systems():
        for pid in fo.sys_get_planets(sid):
            planet = universe.getPlanet(pid)

            planet_type = fo.planet_get_type(pid).name
            planet_size = fo.planet_get_size(pid).name
            if planet_type != planet_size:
                planet_type = "%s %s" % (planet_type, planet_size)

            buildings = [
                universe.getBuilding(x).name for x in planet.buildingIDs
            ]
            planets_table.add_row(
                pid,
                planet.name,
                planet.systemID,
                planet_type,
                list(planet.specials),
                planet.speciesName,
                buildings,
            )

    planets_table.print_table(print)
def log_species_summary(native_freq):
    num_empires = sum(empire_species.values())
    num_species = len(fo.get_playable_species())
    exp_count = num_empires // num_species

    species_summary_table = Table(
        [Text('species'),
         Text('count'),
         Float('%', precession=1)],
        table_name=('Empire Starting Species Summary\n'
                    'Approximately %d to %d empires expected per species\n'
                    '%d Empires and %d playable species') %
        (max(0, exp_count - 1), exp_count + 1, num_empires, num_species))

    for species, count in sorted(empire_species.items()):
        species_summary_table.add_row(
            (species, count, 100.0 * count / num_empires))
    species_summary_table.print_table()
    print

    native_chance = universe_tables.NATIVE_FREQUENCY[native_freq]
    # as the value in the universe table is higher for a lower frequency, we have to invert it
    # a value of 0 means no natives, in this case return immediately
    if native_chance <= 0:
        return
    native_table = Table(
        [
            Text('settled natives'),
            Text('on planets'),
            Float('total', precession=1),
            Float('actual', precession=1),
            Float('expected', precession=1),
            Sequence('planet types')
        ],
        table_name="Natives Placement Summary (native frequency: %.1f%%)" %
        (100 * native_chance))

    native_potential_planet_total = sum(
        potential_native_planet_summary.values())
    for species in sorted(species_summary):
        if species_summary[species] > 0:
            settleable_planets = 0
            expectation_tally = 0.0
            for p_type in natives.planet_types_for_natives[species]:
                settleable_planets += potential_native_planet_summary[p_type]
                expectation_tally += native_chance * 100.0 * potential_native_planet_summary[
                    p_type] / (1E-10 +
                               len(natives.natives_for_planet_type[p_type]))
            expectation = expectation_tally / (1E-10 + settleable_planets)
            native_table.add_row([
                species, species_summary[species],
                100.0 * species_summary[species] /
                (1E-10 + native_potential_planet_total), 100.0 *
                species_summary[species] / (1E-10 + settleable_planets),
                expectation,
                [
                    str(p_t)
                    for p_t in natives.planet_types_for_natives[species]
                ]
            ])

    native_table.print_table()
    print

    native_settled_planet_total = sum(settled_native_planet_summary.values())
    type_summary_table = Table(
        [
            Text('planet type'),
            Float('potential (% of tot)', precession=1),
            Float('settled (% of potential)', precession=1)
        ],
        table_name=
        ("Planet Type Summary for Native Planets (native frequency: %.1f%%)\n"
         "Totals: native_potential_planet_total: %s; native_settled_planet_total %s"
         ) % (100 * native_chance, native_potential_planet_total,
              native_settled_planet_total))

    for planet_type, planet_count in sorted(
            potential_native_planet_summary.items()):
        settled_planet_count = settled_native_planet_summary.get(
            planet_type, 0)
        potential_percent = 100.0 * planet_count / (
            1E-10 + native_potential_planet_total)
        settled_percent = 100.0 * settled_planet_count / (1E-10 + planet_count)
        type_summary_table.add_row(
            (planet_type.name, potential_percent, settled_percent))
    type_summary_table.print_table()
    print
Exemple #38
0
def test_simple_table():
    t = Table(
        [
            Text("name", description="Name for first column"),
            Float("value", description="VValue"),
            Sequence("zzz"),
            Sequence("zzzzzzzzzzzzzzzzzz"),
        ],
        table_name="Wooho",
    )
    t.add_row(["hello", 144444, "abcffff", "a"])
    t.add_row([u"Plato aa\u03b2 III", 21, "de", "a"])
    t.add_row([u"Plato \u03b2 III", 21, "de", "a"])
    t.add_row(["Plato B III", 21, "d", "a"])
    t.add_row(["Plato Bddddd III", 21, "d", "a"])
    t.add_row(["Plato III", 21, "d", "a"])
    assert t.get_table() == EXPECTED_SIMPLE_TABLE
Exemple #39
0
 def report_system_threats(self):
     if fo.currentTurn() >= 100:
         return
     universe = fo.getUniverse()
     sys_id_list = sorted(
         universe.systemIDs
     )  # will normally look at this, the list of all known systems
     current_turn = fo.currentTurn()
     # assess fleet and planet threats
     threat_table = Table([
         Text('System'),
         Text('Vis.'),
         Float('Total'),
         Float('by Monsters'),
         Float('by Fleets'),
         Float('by Planets'),
         Float('1 jump away'),
         Float('2 jumps'),
         Float('3 jumps')
     ],
                          table_name="System Threat Turn %d" % current_turn)
     defense_table = Table([
         Text('System Defenses'),
         Float('Total'),
         Float('by Planets'),
         Float('by Fleets'),
         Float('Fleets 1 jump away'),
         Float('2 jumps'),
         Float('3 jumps')
     ],
                           table_name="System Defenses Turn %d" %
                           current_turn)
     for sys_id in sys_id_list:
         sys_status = self.systemStatus.get(sys_id, {})
         system = universe.getSystem(sys_id)
         threat_table.add_row([
             system,
             "Yes" if sys_status.get('currently_visible', False) else "No",
             sys_status.get('totalThreat', 0),
             sys_status.get('monsterThreat', 0),
             sys_status.get('fleetThreat', 0),
             sys_status.get('planetThreat', 0),
             sys_status.get('neighborThreat', 0.0),
             sys_status.get('jump2_threat', 0.0),
             sys_status.get('jump3_threat', 0.0),
         ])
         defense_table.add_row([
             system,
             sys_status.get('all_local_defenses', 0.0),
             sys_status.get('mydefenses', {}).get('overall', 0.0),
             sys_status.get('myFleetRating', 0.0),
             sys_status.get('my_neighbor_rating', 0.0),
             sys_status.get('my_jump2_rating', 0.0),
             sys_status.get('my_jump3_rating', 0.0),
         ])
     threat_table.print_table()
     defense_table.print_table()
Exemple #40
0
    def __clean_fleet_roles(self, just_resumed=False):
        """Removes fleetRoles if a fleet has been lost, and update fleet Ratings."""
        for sys_id in self.systemStatus:
            self.systemStatus[sys_id]['myFleetRating'] = 0
            self.systemStatus[sys_id]['myFleetRatingVsPlanets'] = 0

        universe = fo.getUniverse()
        ok_fleets = FleetUtilsAI.get_empire_fleet_ids()
        fleet_list = sorted(list(self.__fleetRoleByID))
        ship_count = 0
        destroyed_object_ids = universe.destroyedObjectIDs(fo.empireID())

        fleet_table = Table([
            Text('Fleet'),
            Float('Rating'),
            Float('Troops'),
            Text('Location'),
            Text('Destination')
        ],
                            table_name="Fleet Summary Turn %d" %
                            fo.currentTurn())
        for fleet_id in fleet_list:
            status = self.fleetStatus.setdefault(fleet_id, {})
            rating = CombatRatingsAI.get_fleet_rating(
                fleet_id, self.get_standard_enemy())
            troops = FleetUtilsAI.count_troops_in_fleet(fleet_id)
            old_sys_id = status.get('sysID', -2)
            fleet = universe.getFleet(fleet_id)
            if fleet:
                sys_id = fleet.systemID
                if old_sys_id in [-2, -1]:
                    old_sys_id = sys_id
                status['nships'] = len(fleet.shipIDs)
                ship_count += status['nships']
            else:
                # can still retrieve a fleet object even if fleet was just destroyed, so shouldn't get here
                # however,this has been observed happening, and is the reason a fleet check was added a few lines below.
                # Not at all sure how this came about, but was throwing off threat assessments
                sys_id = old_sys_id
            if fleet_id not in ok_fleets:  # or fleet.empty:
                if (fleet and self.__fleetRoleByID.get(fleet_id, -1) != -1
                        and fleet_id not in destroyed_object_ids
                        and any(ship_id not in destroyed_object_ids
                                for ship_id in fleet.shipIDs)):
                    if not just_resumed:
                        fleetsLostBySystem.setdefault(old_sys_id, []).append(
                            max(rating, MilitaryAI.MinThreat))
                if fleet_id in self.__fleetRoleByID:
                    del self.__fleetRoleByID[fleet_id]
                if fleet_id in self.__aiMissionsByFleetID:
                    del self.__aiMissionsByFleetID[fleet_id]
                if fleet_id in self.fleetStatus:
                    del self.fleetStatus[fleet_id]
                continue
            else:  # fleet in ok fleets
                this_sys = universe.getSystem(sys_id)
                next_sys = universe.getSystem(fleet.nextSystemID)

                fleet_table.add_row([
                    fleet,
                    rating,
                    troops,
                    this_sys or 'starlane',
                    next_sys or '-',
                ])

                status['rating'] = rating
                if next_sys:
                    status['sysID'] = next_sys.id
                elif this_sys:
                    status['sysID'] = this_sys.id
                else:
                    main_mission = self.get_fleet_mission(fleet_id)
                    main_mission_type = (main_mission.getAIMissionTypes() +
                                         [-1])[0]
                    if main_mission_type != -1:
                        targets = main_mission.getAITargets(main_mission_type)
                        if targets:
                            m_mt0 = targets[0]
                            if isinstance(m_mt0.target_type, System):
                                status[
                                    'sysID'] = m_mt0.target.id  # hmm, but might still be a fair ways from here
        fleet_table.print_table()
        self.shipCount = ship_count
        # Next string used in charts. Don't modify it!
        print "Empire Ship Count: ", ship_count
        print "Empire standard fighter summary: ", CombatRatingsAI.get_empire_standard_fighter(
        ).get_stats()
        print "------------------------"
Exemple #41
0
def get_invasion_fleets():
    invasion_timer.start("gathering initial info")
    universe = fo.getUniverse()
    empire = fo.getEmpire()
    empire_id = fo.empireID()

    home_system_id = PlanetUtilsAI.get_capital_sys_id()
    aistate = get_aistate()
    visible_system_ids = list(aistate.visInteriorSystemIDs) + list(aistate.visBorderSystemIDs)

    if home_system_id != INVALID_ID:
        accessible_system_ids = [sys_id for sys_id in visible_system_ids if
                                 (sys_id != INVALID_ID) and universe.systemsConnected(sys_id, home_system_id,
                                                                                      empire_id)]
    else:
        debug("Empire has no identifiable homeworld; will treat all visible planets as accessible.")
        # TODO: check if any troop ships owned, use their system as home system
        accessible_system_ids = visible_system_ids

    acessible_planet_ids = PlanetUtilsAI.get_planets_in__systems_ids(accessible_system_ids)
    all_owned_planet_ids = PlanetUtilsAI.get_all_owned_planet_ids(acessible_planet_ids)  # includes unpopulated outposts
    all_populated_planets = PlanetUtilsAI.get_populated_planet_ids(acessible_planet_ids)  # includes unowned natives
    empire_owned_planet_ids = PlanetUtilsAI.get_owned_planets_by_empire(universe.planetIDs)
    invadable_planet_ids = set(all_owned_planet_ids).union(all_populated_planets) - set(empire_owned_planet_ids)

    invasion_targeted_planet_ids = get_invasion_targeted_planet_ids(universe.planetIDs, MissionType.INVASION)
    invasion_targeted_planet_ids.extend(
        get_invasion_targeted_planet_ids(universe.planetIDs, MissionType.ORBITAL_INVASION))
    all_invasion_targeted_system_ids = set(PlanetUtilsAI.get_systems(invasion_targeted_planet_ids))

    invasion_fleet_ids = FleetUtilsAI.get_empire_fleet_ids_by_role(MissionType.INVASION)
    num_invasion_fleets = len(FleetUtilsAI.extract_fleet_ids_without_mission_types(invasion_fleet_ids))

    debug("Current Invasion Targeted SystemIDs: %s" % PlanetUtilsAI.sys_name_ids(AIstate.invasionTargetedSystemIDs))
    debug("Current Invasion Targeted PlanetIDs: %s" % PlanetUtilsAI.planet_string(invasion_targeted_planet_ids))
    debug(invasion_fleet_ids and "Invasion Fleet IDs: %s" % invasion_fleet_ids or "Available Invasion Fleets: 0")
    debug("Invasion Fleets Without Missions: %s" % num_invasion_fleets)

    invasion_timer.start("planning troop base production")
    reserved_troop_base_targets = []
    if aistate.character.may_invade_with_bases():
        available_pp = {}
        for el in empire.planetsWithAvailablePP:  # keys are sets of ints; data is doubles
            avail_pp = el.data()
            for pid in el.key():
                available_pp[pid] = avail_pp
        # For planning base trooper invasion targets we have a two-pass system.  (1) In the first pass we consider all
        # the invasion targets and figure out which ones appear to be suitable for using base troopers against (i.e., we
        # already have a populated planet in the same system that could build base troopers) and we have at least a
        # minimal amount of PP available, and (2) in the second pass we go through the reserved base trooper target list
        # and check to make sure that there does not appear to be too much military action still needed before the
        # target is ready to be invaded, we double check that not too many base troopers would be needed, and if things
        # look clear then we queue up the base troopers on the Production Queue and keep track of where we are building
        # them, and how many; we may also disqualify and remove previously qualified targets (in case, for example,
        # we lost our base trooper source planet since it was first added to list).
        #
        # For planning and tracking base troopers under construction, we use a dictionary store in
        # get_aistate().qualifyingTroopBaseTargets, keyed by the invasion target planet ID.  We only store values
        # for invasion targets that appear likely to be suitable for base trooper use, and store a 2-item list.
        # The first item in this list is the ID of the planet where we expect to build the base troopers, and the second
        # entry initially is set to INVALID_ID (-1).  The presence of this entry in qualifyingTroopBaseTargets
        # flags this target as being reserved as a base-trooper invasion target.
        # In the second pass, if/when we actually start construction, then we modify the record, replacing that second
        # value with the ID of the planet where the troopers are actually being built.  (Right now that is always the
        # same as the source planet originally identified, but we could consider reevaluating that, or use that second
        # value to instead record how many base troopers have been queued, so that on later turns we can assess if the
        # process got delayed & perhaps more troopers need to be queued).
        secure_ai_fleet_missions = aistate.get_fleet_missions_with_any_mission_types([MissionType.SECURE,
                                                                                      MissionType.MILITARY])

        # Pass 1: identify qualifying base troop invasion targets
        for pid in invadable_planet_ids:  # TODO: reorganize
            if pid in aistate.qualifyingTroopBaseTargets:
                continue
            planet = universe.getPlanet(pid)
            if not planet:
                continue
            sys_id = planet.systemID
            sys_partial_vis_turn = get_partial_visibility_turn(sys_id)
            planet_partial_vis_turn = get_partial_visibility_turn(pid)
            if planet_partial_vis_turn < sys_partial_vis_turn:
                continue
            best_base_planet = INVALID_ID
            best_trooper_count = 0
            for pid2 in state.get_empire_planets_by_system(sys_id, include_outposts=False):
                if available_pp.get(pid2, 0) < 2:  # TODO: improve troop base PP sufficiency determination
                    break
                planet2 = universe.getPlanet(pid2)
                if not planet2 or planet2.speciesName not in ColonisationAI.empire_ship_builders:
                    continue
                best_base_trooper_here = \
                    ProductionAI.get_best_ship_info(PriorityType.PRODUCTION_ORBITAL_INVASION, pid2)[1]
                if not best_base_trooper_here:
                    continue
                troops_per_ship = best_base_trooper_here.troopCapacity
                if not troops_per_ship:
                    continue
                species_troop_grade = CombatRatingsAI.get_species_troops_grade(planet2.speciesName)
                troops_per_ship = CombatRatingsAI.weight_attack_troops(troops_per_ship, species_troop_grade)
                if troops_per_ship > best_trooper_count:
                    best_base_planet = pid2
                    best_trooper_count = troops_per_ship
            if best_base_planet != INVALID_ID:
                aistate.qualifyingTroopBaseTargets.setdefault(pid, [best_base_planet, INVALID_ID])

        # Pass 2: for each target previously identified for base troopers, check that still qualifies and
        # check how many base troopers would be needed; if reasonable then queue up the troops and record this in
        # get_aistate().qualifyingTroopBaseTargets
        for pid in aistate.qualifyingTroopBaseTargets.keys():
            planet = universe.getPlanet(pid)
            if planet and planet.owner == empire_id:
                del aistate.qualifyingTroopBaseTargets[pid]
                continue
            if pid in invasion_targeted_planet_ids:  # TODO: consider overriding standard invasion mission
                continue
            if aistate.qualifyingTroopBaseTargets[pid][1] != -1:
                reserved_troop_base_targets.append(pid)
                if planet:
                    all_invasion_targeted_system_ids.add(planet.systemID)
                # TODO: evaluate changes to situation, any more troops needed, etc.
                continue  # already building for here
            _, planet_troops = evaluate_invasion_planet(pid, secure_ai_fleet_missions, True)
            sys_id = planet.systemID
            this_sys_status = aistate.systemStatus.get(sys_id, {})
            troop_tally = 0
            for _fid in this_sys_status.get('myfleets', []):
                troop_tally += FleetUtilsAI.count_troops_in_fleet(_fid)
            if troop_tally > planet_troops:  # base troopers appear unneeded
                del aistate.qualifyingTroopBaseTargets[pid]
                continue
            if (planet.currentMeterValue(fo.meterType.shield) > 0 and
                    (this_sys_status.get('myFleetRating', 0) < 0.8 * this_sys_status.get('totalThreat', 0) or
                     this_sys_status.get('myFleetRatingVsPlanets', 0) < this_sys_status.get('planetThreat', 0))):
                # this system not secured, so ruling out invasion base troops for now
                # don't immediately delete from qualifyingTroopBaseTargets or it will be opened up for regular troops
                continue
            loc = aistate.qualifyingTroopBaseTargets[pid][0]
            best_base_trooper_here = ProductionAI.get_best_ship_info(PriorityType.PRODUCTION_ORBITAL_INVASION, loc)[1]
            loc_planet = universe.getPlanet(loc)
            if best_base_trooper_here is None:  # shouldn't be possible at this point, but just to be safe
                warn("Could not find a suitable orbital invasion design at %s" % loc_planet)
                continue
            # TODO: have TroopShipDesigner give the expected number of troops including species effects directly
            troops_per_ship = best_base_trooper_here.troopCapacity
            species_troop_grade = CombatRatingsAI.get_species_troops_grade(loc_planet.speciesName)
            troops_per_ship = CombatRatingsAI.weight_attack_troops(troops_per_ship, species_troop_grade)
            if not troops_per_ship:
                warn("The best orbital invasion design at %s seems not to have any troop capacity." % loc_planet)
                continue
            _, col_design, build_choices = ProductionAI.get_best_ship_info(PriorityType.PRODUCTION_ORBITAL_INVASION,
                                                                           loc)
            if not col_design:
                continue
            if loc not in build_choices:
                warn('Best troop design %s can not be produced at planet with id: %s\d' % (col_design, build_choices))
                continue
            n_bases = math.ceil((planet_troops + 1) / troops_per_ship)  # TODO: reconsider this +1 safety factor
            # TODO: evaluate cost and time-to-build of best base trooper here versus cost and time-to-build-and-travel
            # for best regular trooper elsewhere
            # For now, we assume what building base troopers is best so long as either (1) we would need no more than
            # MAX_BASE_TROOPERS_POOR_INVADERS base troop ships, or (2) our base troopers have more than 1 trooper per
            # ship and we would need no more than MAX_BASE_TROOPERS_GOOD_INVADERS base troop ships
            if (n_bases > MAX_BASE_TROOPERS_POOR_INVADERS or
                    (troops_per_ship > 1 and n_bases > MAX_BASE_TROOPERS_GOOD_INVADERS)):
                debug("ruling out base invasion troopers for %s due to high number (%d) required." % (planet, n_bases))
                del aistate.qualifyingTroopBaseTargets[pid]
                continue
            debug("Invasion base planning, need %d troops at %d per ship, will build %d ships." % (
                (planet_troops + 1), troops_per_ship, n_bases))
            retval = fo.issueEnqueueShipProductionOrder(col_design.id, loc)
            debug("Enqueueing %d Troop Bases at %s for %s" % (n_bases, PlanetUtilsAI.planet_string(loc),
                                                              PlanetUtilsAI.planet_string(pid)))
            if retval != 0:
                all_invasion_targeted_system_ids.add(planet.systemID)
                reserved_troop_base_targets.append(pid)
                aistate.qualifyingTroopBaseTargets[pid][1] = loc
                fo.issueChangeProductionQuantityOrder(empire.productionQueue.size - 1, 1, int(n_bases))
                fo.issueRequeueProductionOrder(empire.productionQueue.size - 1, 0)

    invasion_timer.start("evaluating target planets")
    # TODO: check if any invasion_targeted_planet_ids need more troops assigned
    evaluated_planet_ids = list(
        set(invadable_planet_ids) - set(invasion_targeted_planet_ids) - set(reserved_troop_base_targets))
    evaluated_planets = assign_invasion_values(evaluated_planet_ids)

    sorted_planets = [(pid, pscore % 10000, ptroops) for pid, (pscore, ptroops) in evaluated_planets.items()]
    sorted_planets.sort(key=lambda x: x[1], reverse=True)
    sorted_planets = [(pid, pscore % 10000, ptroops) for pid, pscore, ptroops in sorted_planets]

    invasion_table = Table([Text('Planet'), Float('Score'), Text('Species'), Float('Troops')],
                           table_name="Potential Targets for Invasion Turn %d" % fo.currentTurn())

    for pid, pscore, ptroops in sorted_planets:
        planet = universe.getPlanet(pid)
        invasion_table.add_row([
            planet,
            pscore,
            planet and planet.speciesName or "unknown",
            ptroops
        ])
    info(invasion_table)

    sorted_planets = filter(lambda x: x[1] > 0, sorted_planets)
    # export opponent planets for other AI modules
    AIstate.opponentPlanetIDs = [pid for pid, __, __ in sorted_planets]
    AIstate.invasionTargets = sorted_planets

    # export invasion targeted systems for other AI modules
    AIstate.invasionTargetedSystemIDs = list(all_invasion_targeted_system_ids)
    invasion_timer.stop(section_name="evaluating %d target planets" % (len(evaluated_planet_ids)))
    invasion_timer.stop_print_and_clear()
def log_species_summary(native_freq):
    num_empires = sum(empire_species.values())
    num_species = len(fo.get_playable_species())
    exp_count = num_empires // num_species

    species_summary_table = Table(
        [Text('species'), Text('count'), Float('%', precession=1)],
        table_name=('Empire Starting Species Summary\n'
                    'Approximately %d to %d empires expected per species\n'
                    '%d Empires and %d playable species') % (max(0, exp_count - 1), exp_count + 1,
                                                             num_empires, num_species)
    )

    for species, count in sorted(empire_species.items()):
        species_summary_table.add_row((species, count, 100.0 * count / num_empires))
    print species_summary_table
    print

    native_chance = universe_tables.NATIVE_FREQUENCY[native_freq]
    # as the value in the universe table is higher for a lower frequency, we have to invert it
    # a value of 0 means no natives, in this case return immediately
    if native_chance <= 0:
        return
    native_table = Table(
        [
            Text('settled natives'),
            Text('on planets'),
            Float('total', precession=1),
            Float('actual', precession=1),
            Float('expected', precession=1),
            Sequence('planet types')
        ],
        table_name="Natives Placement Summary (native frequency: %.1f%%)" % (100 * native_chance)
    )

    native_potential_planet_total = sum(potential_native_planet_summary.values())
    for species in sorted(species_summary):
        if species_summary[species] > 0:
            settleable_planets = 0
            expectation_tally = 0.0
            for p_type in natives.planet_types_for_natives[species]:
                settleable_planets += potential_native_planet_summary[p_type]
                expectation_tally += (
                        native_chance *
                        100.0 *
                        potential_native_planet_summary[p_type] /
                        (1E-10 + len(natives.natives_for_planet_type[p_type]))
                )
            expectation = expectation_tally / (1E-10 + settleable_planets)
            native_table.add_row(
                [species,
                 species_summary[species], 100.0 * species_summary[species] / (1E-10 + native_potential_planet_total),
                 100.0 * species_summary[species] / (1E-10 + settleable_planets),
                 expectation,
                 [str(p_t) for p_t in natives.planet_types_for_natives[species]]]
            )

    print native_table
    print

    native_settled_planet_total = sum(settled_native_planet_summary.values())
    type_summary_table = Table(
        [Text('planet type'), Float('potential (% of tot)', precession=1),
         Float('settled (% of potential)', precession=1)],
        table_name=("Planet Type Summary for Native Planets (native frequency: %.1f%%)\n"
                    "Totals: native_potential_planet_total: %s; native_settled_planet_total %s"
                    ) % (100 * native_chance, native_potential_planet_total, native_settled_planet_total)
    )

    for planet_type, planet_count in sorted(potential_native_planet_summary.items()):
        settled_planet_count = settled_native_planet_summary.get(planet_type, 0)
        potential_percent = 100.0 * planet_count / (1E-10 + native_potential_planet_total)
        settled_percent = 100.0 * settled_planet_count / (1E-10 + planet_count)
        type_summary_table.add_row((planet_type.name, potential_percent, settled_percent))
    print type_summary_table
    print
Exemple #43
0
    def __clean_fleet_roles(self, just_resumed=False):
        """Removes fleetRoles if a fleet has been lost, and update fleet Ratings."""
        universe = fo.getUniverse()
        current_empire_fleets = FleetUtilsAI.get_empire_fleet_ids()
        self.shipCount = 0
        destroyed_object_ids = universe.destroyedObjectIDs(fo.empireID())

        fleet_table = Table([
            Text('Fleet'), Float('Rating'), Float('Troops'),
            Text('Location'), Text('Destination')],
            table_name="Fleet Summary Turn %d" % fo.currentTurn()
        )
        # need to loop over a copy as entries are deleted in loop
        for fleet_id in list(self.__fleetRoleByID):
            fleet_status = self.fleetStatus.setdefault(fleet_id, {})
            rating = CombatRatingsAI.get_fleet_rating(fleet_id, self.get_standard_enemy())
            old_sys_id = fleet_status.get('sysID', -2)  # TODO: Introduce helper function instead
            fleet = universe.getFleet(fleet_id)
            if fleet:
                sys_id = fleet.systemID
                if old_sys_id in [-2, -1]:
                    old_sys_id = sys_id
                fleet_status['nships'] = len(fleet.shipIDs)  # TODO: Introduce helper function instead
                self.shipCount += fleet_status['nships']
            else:
                # can still retrieve a fleet object even if fleet was just destroyed, so shouldn't get here
                # however,this has been observed happening, and is the reason a fleet check was added a few lines below.
                # Not at all sure how this came about, but was throwing off threat assessments
                sys_id = old_sys_id

            # check if fleet is destroyed and if so, delete stored information
            if fleet_id not in current_empire_fleets:  # or fleet.empty:
                # TODO(Morlic): Is this condition really correct? Seems like should actually be in destroyed object ids
                if (fleet and self.__fleetRoleByID.get(fleet_id, -1) != -1 and
                        fleet_id not in destroyed_object_ids and
                        any(ship_id not in destroyed_object_ids for ship_id in fleet.shipIDs)):
                    if not just_resumed:
                        fleetsLostBySystem.setdefault(old_sys_id, []).append(max(rating, MilitaryAI.MinThreat))

                self.delete_fleet_info(fleet_id)
                continue

            # if reached here, the fleet does still exist
            this_sys = universe.getSystem(sys_id)
            next_sys = universe.getSystem(fleet.nextSystemID)

            fleet_table.add_row([
                    fleet,
                    rating,
                    FleetUtilsAI.count_troops_in_fleet(fleet_id),
                    this_sys or 'starlane',
                    next_sys or '-',
                ])

            fleet_status['rating'] = rating
            if next_sys:
                fleet_status['sysID'] = next_sys.id
            elif this_sys:
                fleet_status['sysID'] = this_sys.id
            else:
                error("Fleet %s has no valid system." % fleet)
        info(fleet_table)
        # Next string used in charts. Don't modify it!
        debug("Empire Ship Count: %s" % self.shipCount)
        debug("Empire standard fighter summary: %s", (CombatRatingsAI.get_empire_standard_fighter().get_stats(), ))
        debug("------------------------")
Exemple #44
0
    def __clean_fleet_roles(self, just_resumed=False):
        """Removes fleetRoles if a fleet has been lost, and update fleet Ratings."""
        universe = fo.getUniverse()
        current_empire_fleets = FleetUtilsAI.get_empire_fleet_ids()
        self.shipCount = 0
        destroyed_object_ids = universe.destroyedObjectIDs(fo.empireID())

        fleet_table = Table([
            Text('Fleet'), Float('Rating'), Float('Troops'),
            Text('Location'), Text('Destination')],
            table_name="Fleet Summary Turn %d" % fo.currentTurn()
        )
        # need to loop over a copy as entries are deleted in loop
        for fleet_id in list(self.__fleetRoleByID):
            fleet_status = self.fleetStatus.setdefault(fleet_id, {})
            rating = CombatRatingsAI.get_fleet_rating(fleet_id, self.get_standard_enemy())
            old_sys_id = fleet_status.get('sysID', -2)  # TODO: Introduce helper function instead
            fleet = universe.getFleet(fleet_id)
            if fleet:
                sys_id = fleet.systemID
                if old_sys_id in [-2, -1]:
                    old_sys_id = sys_id
                fleet_status['nships'] = len(fleet.shipIDs)  # TODO: Introduce helper function instead
                self.shipCount += fleet_status['nships']
            else:
                # can still retrieve a fleet object even if fleet was just destroyed, so shouldn't get here
                # however,this has been observed happening, and is the reason a fleet check was added a few lines below.
                # Not at all sure how this came about, but was throwing off threat assessments
                sys_id = old_sys_id

            # check if fleet is destroyed and if so, delete stored information
            if fleet_id not in current_empire_fleets:  # or fleet.empty:
                # TODO(Morlic): Is this condition really correct? Seems like should actually be in destroyed object ids
                if (fleet and self.__fleetRoleByID.get(fleet_id, -1) != -1 and
                        fleet_id not in destroyed_object_ids and
                        any(ship_id not in destroyed_object_ids for ship_id in fleet.shipIDs)):
                    if not just_resumed:
                        fleetsLostBySystem.setdefault(old_sys_id, []).append(max(rating, MilitaryAI.MinThreat))

                self.delete_fleet_info(fleet_id)
                continue

            # if reached here, the fleet does still exist
            this_sys = universe.getSystem(sys_id)
            next_sys = universe.getSystem(fleet.nextSystemID)

            fleet_table.add_row([
                    fleet,
                    rating,
                    FleetUtilsAI.count_troops_in_fleet(fleet_id),
                    this_sys or 'starlane',
                    next_sys or '-',
                ])

            fleet_status['rating'] = rating
            if next_sys:
                fleet_status['sysID'] = next_sys.id
            elif this_sys:
                fleet_status['sysID'] = this_sys.id
            else:
                error("Fleet %s has no valid system." % fleet)
        info(fleet_table)
        # Next string used in charts. Don't modify it!
        print "Empire Ship Count: ", self.shipCount
        print "Empire standard fighter summary: ", CombatRatingsAI.get_empire_standard_fighter().get_stats()
        print "------------------------"
def test_simple_table():
    t = Table(
        [Text('name', description='Name for first column'), Float('value', description='VValue'),
         Sequence('zzz'), Sequence('zzzzzzzzzzzzzzzzzz')],
        table_name='Wooho')
    t.add_row(['hello', 144444, 'abcffff', 'a'])
    t.add_row([u'Plato aa\u03b2 III', 21, 'de', 'a'])
    t.add_row([u'Plato \u03b2 III', 21, 'de', 'a'])
    t.add_row(['Plato B III', 21, 'd', 'a'])
    t.add_row(['Plato Bddddd III', 21, 'd', 'a'])
    t.add_row(['Plato III', 21, 'd', 'a'])
    assert t.get_table() == EXPECTED_SIMPLE_TABLE
Exemple #46
0
def make_table():
    t = Table(
        Text("name", description="Name for first column"),
        Number("value", description="VValue"),
        Sequence("zzz"),
        Sequence("zzzzzzzzzzzzzzzzzz"),
        table_name="Wooho",
    )
    t.add_row("hello", 144444, "abcffff", "a")
    t.add_row("Plato aa\u03b2 III", 21, "de", "a")
    t.add_row("Plato \u03b2 III", 21, "de", "a")
    t.add_row("Plato B III", 21, "d", "a")
    t.add_row("Plato Bddddd III", 21, "d", "a")
    t.add_row("Plato III", 21, "d", "a")
    return t
Exemple #47
0
    def __clean_fleet_roles(self, just_resumed=False):
        """Removes fleetRoles if a fleet has been lost, and update fleet Ratings."""
        for sys_id in self.systemStatus:
            self.systemStatus[sys_id]['myFleetRating'] = 0
            self.systemStatus[sys_id]['myFleetRatingVsPlanets'] = 0

        universe = fo.getUniverse()
        ok_fleets = FleetUtilsAI.get_empire_fleet_ids()
        fleet_list = sorted(list(self.__fleetRoleByID))
        ship_count = 0
        destroyed_object_ids = universe.destroyedObjectIDs(fo.empireID())

        fleet_table = Table([
            Text('Fleet'), Float('Rating'), Float('Troops'),
            Text('Location'), Text('Destination')],
            table_name="Fleet Summary Turn %d" % fo.currentTurn()
        )
        for fleet_id in fleet_list:
            status = self.fleetStatus.setdefault(fleet_id, {})
            rating = CombatRatingsAI.get_fleet_rating(fleet_id, self.get_standard_enemy())
            troops = FleetUtilsAI.count_troops_in_fleet(fleet_id)
            old_sys_id = status.get('sysID', -2)
            fleet = universe.getFleet(fleet_id)
            if fleet:
                sys_id = fleet.systemID
                if old_sys_id in [-2, -1]:
                    old_sys_id = sys_id
                status['nships'] = len(fleet.shipIDs)
                ship_count += status['nships']
            else:
                sys_id = old_sys_id  # can still retrieve a fleet object even if fleet was just destroyed, so shouldn't get here
                # however,this has been observed happening, and is the reason a fleet check was added a few lines below.
                # Not at all sure how this came about, but was throwing off threat assessments
            if fleet_id not in ok_fleets:  # or fleet.empty:
                if (fleet and self.__fleetRoleByID.get(fleet_id, -1) != -1 and fleet_id not in destroyed_object_ids and
                                [ship_id for ship_id in fleet.shipIDs if ship_id not in destroyed_object_ids]):
                    if not just_resumed:
                        fleetsLostBySystem.setdefault(old_sys_id, []).append(max(rating, MilitaryAI.MinThreat))
                if fleet_id in self.__fleetRoleByID:
                    del self.__fleetRoleByID[fleet_id]
                if fleet_id in self.__aiMissionsByFleetID:
                    del self.__aiMissionsByFleetID[fleet_id]
                if fleet_id in self.fleetStatus:
                    del self.fleetStatus[fleet_id]
                continue
            else:  # fleet in ok fleets
                this_sys = universe.getSystem(sys_id)
                next_sys = universe.getSystem(fleet.nextSystemID)

                fleet_table.add_row(
                    [
                        fleet,
                        rating,
                        troops,
                        this_sys or 'starlane',
                        next_sys or '-',
                    ])

                status['rating'] = rating
                if next_sys:
                    status['sysID'] = next_sys.id
                elif this_sys:
                    status['sysID'] = this_sys.id
                else:
                    main_mission = self.get_fleet_mission(fleet_id)
                    main_mission_type = (main_mission.getAIMissionTypes() + [-1])[0]
                    if main_mission_type != -1:
                        targets = main_mission.getAITargets(main_mission_type)
                        if targets:
                            m_mt0 = targets[0]
                            if isinstance(m_mt0.target_type, System):
                                status['sysID'] = m_mt0.target.id  # hmm, but might still be a fair ways from here
        fleet_table.print_table()
        self.shipCount = ship_count
        # Next string used in charts. Don't modify it!
        print "Empire Ship Count: ", ship_count
        print "Empire standard fighter summary: ", CombatRatingsAI.get_empire_standard_fighter().get_stats()
        print "------------------------"
Exemple #48
0
def get_invasion_fleets():
    invasion_timer.start("gathering initial info")
    universe = fo.getUniverse()
    empire = fo.getEmpire()
    empire_id = fo.empireID()

    home_system_id = PlanetUtilsAI.get_capital_sys_id()
    aistate = get_aistate()
    visible_system_ids = list(aistate.visInteriorSystemIDs) + list(
        aistate.visBorderSystemIDs)

    if home_system_id != INVALID_ID:
        accessible_system_ids = [
            sys_id for sys_id in visible_system_ids
            if systems_connected(sys_id, home_system_id)
        ]
    else:
        debug(
            "Empire has no identifiable homeworld; will treat all visible planets as accessible."
        )
        # TODO: check if any troop ships owned, use their system as home system
        accessible_system_ids = visible_system_ids

    acessible_planet_ids = PlanetUtilsAI.get_planets_in__systems_ids(
        accessible_system_ids)
    all_owned_planet_ids = PlanetUtilsAI.get_all_owned_planet_ids(
        acessible_planet_ids)  # includes unpopulated outposts
    all_populated_planets = PlanetUtilsAI.get_populated_planet_ids(
        acessible_planet_ids)  # includes unowned natives
    empire_owned_planet_ids = PlanetUtilsAI.get_owned_planets_by_empire(
        universe.planetIDs)
    invadable_planet_ids = set(all_owned_planet_ids).union(
        all_populated_planets) - set(empire_owned_planet_ids)

    invasion_targeted_planet_ids = get_invasion_targeted_planet_ids(
        universe.planetIDs, MissionType.INVASION)
    invasion_targeted_planet_ids.extend(
        get_invasion_targeted_planet_ids(universe.planetIDs,
                                         MissionType.ORBITAL_INVASION))
    all_invasion_targeted_system_ids = set(
        PlanetUtilsAI.get_systems(invasion_targeted_planet_ids))

    invasion_fleet_ids = FleetUtilsAI.get_empire_fleet_ids_by_role(
        MissionType.INVASION)
    num_invasion_fleets = len(
        FleetUtilsAI.extract_fleet_ids_without_mission_types(
            invasion_fleet_ids))

    debug("Current Invasion Targeted SystemIDs: %s" %
          PlanetUtilsAI.sys_name_ids(AIstate.invasionTargetedSystemIDs))
    debug("Current Invasion Targeted PlanetIDs: %s" %
          PlanetUtilsAI.planet_string(invasion_targeted_planet_ids))
    debug(invasion_fleet_ids and "Invasion Fleet IDs: %s" % invasion_fleet_ids
          or "Available Invasion Fleets: 0")
    debug("Invasion Fleets Without Missions: %s" % num_invasion_fleets)

    invasion_timer.start("planning troop base production")
    reserved_troop_base_targets = []
    if aistate.character.may_invade_with_bases():
        available_pp = {}
        for el in empire.planetsWithAvailablePP:  # keys are sets of ints; data is doubles
            avail_pp = el.data()
            for pid in el.key():
                available_pp[pid] = avail_pp
        # For planning base trooper invasion targets we have a two-pass system.  (1) In the first pass we consider all
        # the invasion targets and figure out which ones appear to be suitable for using base troopers against (i.e., we
        # already have a populated planet in the same system that could build base troopers) and we have at least a
        # minimal amount of PP available, and (2) in the second pass we go through the reserved base trooper target list
        # and check to make sure that there does not appear to be too much military action still needed before the
        # target is ready to be invaded, we double check that not too many base troopers would be needed, and if things
        # look clear then we queue up the base troopers on the Production Queue and keep track of where we are building
        # them, and how many; we may also disqualify and remove previously qualified targets (in case, for example,
        # we lost our base trooper source planet since it was first added to list).
        #
        # For planning and tracking base troopers under construction, we use a dictionary store in
        # get_aistate().qualifyingTroopBaseTargets, keyed by the invasion target planet ID.  We only store values
        # for invasion targets that appear likely to be suitable for base trooper use, and store a 2-item list.
        # The first item in this list is the ID of the planet where we expect to build the base troopers, and the second
        # entry initially is set to INVALID_ID (-1).  The presence of this entry in qualifyingTroopBaseTargets
        # flags this target as being reserved as a base-trooper invasion target.
        # In the second pass, if/when we actually start construction, then we modify the record, replacing that second
        # value with the ID of the planet where the troopers are actually being built.  (Right now that is always the
        # same as the source planet originally identified, but we could consider reevaluating that, or use that second
        # value to instead record how many base troopers have been queued, so that on later turns we can assess if the
        # process got delayed & perhaps more troopers need to be queued).

        # Pass 1: identify qualifying base troop invasion targets
        for pid in invadable_planet_ids:  # TODO: reorganize
            if pid in aistate.qualifyingTroopBaseTargets:
                continue
            planet = universe.getPlanet(pid)
            if not planet:
                continue
            sys_id = planet.systemID
            sys_partial_vis_turn = get_partial_visibility_turn(sys_id)
            planet_partial_vis_turn = get_partial_visibility_turn(pid)
            if planet_partial_vis_turn < sys_partial_vis_turn:
                continue
            best_base_planet = INVALID_ID
            best_trooper_count = 0
            for pid2 in get_colonized_planets_in_system(sys_id):
                if available_pp.get(
                        pid2, 0
                ) < 2:  # TODO: improve troop base PP sufficiency determination
                    break
                planet2 = universe.getPlanet(pid2)
                if not planet2 or not can_build_ship_for_species(
                        planet2.speciesName):
                    continue
                best_base_trooper_here = get_best_ship_info(
                    PriorityType.PRODUCTION_ORBITAL_INVASION, pid2)[1]
                if not best_base_trooper_here:
                    continue
                troops_per_ship = best_base_trooper_here.troopCapacity
                if not troops_per_ship:
                    continue
                species_troop_grade = get_species_tag_grade(
                    planet2.speciesName, Tags.ATTACKTROOPS)
                troops_per_ship = CombatRatingsAI.weight_attack_troops(
                    troops_per_ship, species_troop_grade)
                if troops_per_ship > best_trooper_count:
                    best_base_planet = pid2
                    best_trooper_count = troops_per_ship
            if best_base_planet != INVALID_ID:
                aistate.qualifyingTroopBaseTargets.setdefault(
                    pid, [best_base_planet, INVALID_ID])

        # Pass 2: for each target previously identified for base troopers, check that still qualifies and
        # check how many base troopers would be needed; if reasonable then queue up the troops and record this in
        # get_aistate().qualifyingTroopBaseTargets
        for pid in list(aistate.qualifyingTroopBaseTargets.keys()):
            planet = universe.getPlanet(pid)
            if planet and planet.owner == empire_id:
                del aistate.qualifyingTroopBaseTargets[pid]
                continue
            if pid in invasion_targeted_planet_ids:  # TODO: consider overriding standard invasion mission
                continue
            if aistate.qualifyingTroopBaseTargets[pid][1] != -1:
                reserved_troop_base_targets.append(pid)
                if planet:
                    all_invasion_targeted_system_ids.add(planet.systemID)
                # TODO: evaluate changes to situation, any more troops needed, etc.
                continue  # already building for here
            _, planet_troops = evaluate_invasion_planet(pid)
            sys_id = planet.systemID
            this_sys_status = aistate.systemStatus.get(sys_id, {})
            troop_tally = 0
            for _fid in this_sys_status.get("myfleets", []):
                troop_tally += FleetUtilsAI.count_troops_in_fleet(_fid)
            if troop_tally > planet_troops:  # base troopers appear unneeded
                del aistate.qualifyingTroopBaseTargets[pid]
                continue
            if planet.currentMeterValue(fo.meterType.shield) > 0 and (
                    this_sys_status.get("myFleetRating", 0) <
                    0.8 * this_sys_status.get("totalThreat", 0)
                    or this_sys_status.get("myFleetRatingVsPlanets", 0) <
                    this_sys_status.get("planetThreat", 0)):
                # this system not secured, so ruling out invasion base troops for now
                # don't immediately delete from qualifyingTroopBaseTargets or it will be opened up for regular troops
                continue
            loc = aistate.qualifyingTroopBaseTargets[pid][0]
            best_base_trooper_here = get_best_ship_info(
                PriorityType.PRODUCTION_ORBITAL_INVASION, loc)[1]
            loc_planet = universe.getPlanet(loc)
            if best_base_trooper_here is None:  # shouldn't be possible at this point, but just to be safe
                warning(
                    "Could not find a suitable orbital invasion design at %s" %
                    loc_planet)
                continue
            # TODO: have TroopShipDesigner give the expected number of troops including species effects directly
            troops_per_ship = best_base_trooper_here.troopCapacity
            species_troop_grade = get_species_tag_grade(
                loc_planet.speciesName, Tags.ATTACKTROOPS)
            troops_per_ship = CombatRatingsAI.weight_attack_troops(
                troops_per_ship, species_troop_grade)
            if not troops_per_ship:
                warning(
                    "The best orbital invasion design at %s seems not to have any troop capacity."
                    % loc_planet)
                continue
            _, col_design, build_choices = get_best_ship_info(
                PriorityType.PRODUCTION_ORBITAL_INVASION, loc)
            if not col_design:
                continue
            if loc not in build_choices:
                warning(
                    "Best troop design %s can not be produced at planet with id: %s"
                    % (col_design, build_choices))
                continue
            n_bases = math.ceil(
                (planet_troops + 1) /
                troops_per_ship)  # TODO: reconsider this +1 safety factor
            # TODO: evaluate cost and time-to-build of best base trooper here versus cost and time-to-build-and-travel
            # for best regular trooper elsewhere
            # For now, we assume what building base troopers is best so long as either (1) we would need no more than
            # MAX_BASE_TROOPERS_POOR_INVADERS base troop ships, or (2) our base troopers have more than 1 trooper per
            # ship and we would need no more than MAX_BASE_TROOPERS_GOOD_INVADERS base troop ships
            if n_bases > MAX_BASE_TROOPERS_POOR_INVADERS or (
                    troops_per_ship > 1
                    and n_bases > MAX_BASE_TROOPERS_GOOD_INVADERS):
                debug(
                    "ruling out base invasion troopers for %s due to high number (%d) required."
                    % (planet, n_bases))
                del aistate.qualifyingTroopBaseTargets[pid]
                continue
            debug(
                "Invasion base planning, need %d troops at %d per ship, will build %d ships."
                % ((planet_troops + 1), troops_per_ship, n_bases))
            retval = fo.issueEnqueueShipProductionOrder(col_design.id, loc)
            debug("Enqueueing %d Troop Bases at %s for %s" %
                  (n_bases, PlanetUtilsAI.planet_string(loc),
                   PlanetUtilsAI.planet_string(pid)))
            if retval != 0:
                all_invasion_targeted_system_ids.add(planet.systemID)
                reserved_troop_base_targets.append(pid)
                aistate.qualifyingTroopBaseTargets[pid][1] = loc
                fo.issueChangeProductionQuantityOrder(
                    empire.productionQueue.size - 1, 1, int(n_bases))
                fo.issueRequeueProductionOrder(empire.productionQueue.size - 1,
                                               0)

    invasion_timer.start("evaluating target planets")
    # TODO: check if any invasion_targeted_planet_ids need more troops assigned
    evaluated_planet_ids = list(
        set(invadable_planet_ids) - set(invasion_targeted_planet_ids) -
        set(reserved_troop_base_targets))
    evaluated_planets = assign_invasion_values(evaluated_planet_ids)

    sorted_planets = [(pid, pscore % 10000, ptroops)
                      for pid, (pscore, ptroops) in evaluated_planets.items()]
    sorted_planets.sort(key=lambda x: x[1], reverse=True)
    sorted_planets = [(pid, pscore % 10000, ptroops)
                      for pid, pscore, ptroops in sorted_planets]

    invasion_table = Table(
        Text("Planet"),
        Number("Score"),
        Text("Species"),
        Number("Troops"),
        table_name="Potential Targets for Invasion Turn %d" % fo.currentTurn(),
    )

    for pid, pscore, ptroops in sorted_planets:
        planet = universe.getPlanet(pid)
        invasion_table.add_row(planet, pscore, planet and planet.speciesName
                               or "unknown", ptroops)
    invasion_table.print_table(info)

    sorted_planets = [x for x in sorted_planets if x[1] > 0]
    # export opponent planets for other AI modules
    AIstate.opponentPlanetIDs = [pid for pid, __, __ in sorted_planets]
    AIstate.invasionTargets = sorted_planets

    # export invasion targeted systems for other AI modules
    AIstate.invasionTargetedSystemIDs = list(all_invasion_targeted_system_ids)
    invasion_timer.stop(section_name="evaluating %d target planets" %
                        (len(evaluated_planet_ids)))
    invasion_timer.stop_print_and_clear()
Exemple #49
0
def get_invasion_fleets():
    invasion_timer.start("gathering initial info")
    universe = fo.getUniverse()
    empire = fo.getEmpire()
    empire_id = empire.empireID

    all_invasion_fleet_ids = FleetUtilsAI.get_empire_fleet_ids_by_role(MissionType.INVASION)
    AIstate.invasionFleetIDs = FleetUtilsAI.extract_fleet_ids_without_mission_types(all_invasion_fleet_ids)

    home_system_id = PlanetUtilsAI.get_capital_sys_id()
    visible_system_ids = foAI.foAIstate.visInteriorSystemIDs.keys() + foAI.foAIstate. visBorderSystemIDs.keys()

    if home_system_id != -1:
        accessible_system_ids = [sys_id for sys_id in visible_system_ids
                                 if (sys_id != -1) and universe.systemsConnected(sys_id, home_system_id, empire_id)]
    else:
        print "Warning: Empire has no identifiable homeworld; will treat all visible planets as accessible."
        accessible_system_ids = visible_system_ids  # TODO: check if any troop ships owned, use their system as home system

    acessible_planet_ids = PlanetUtilsAI.get_planets_in__systems_ids(accessible_system_ids)
    all_owned_planet_ids = PlanetUtilsAI.get_all_owned_planet_ids(acessible_planet_ids)  # includes unpopulated outposts
    all_populated_planets = PlanetUtilsAI.get_populated_planet_ids(acessible_planet_ids)  # includes unowned natives
    empire_owned_planet_ids = PlanetUtilsAI.get_owned_planets_by_empire(universe.planetIDs)
    invadable_planet_ids = set(all_owned_planet_ids).union(all_populated_planets) - set(empire_owned_planet_ids)

    invasion_targeted_planet_ids = get_invasion_targeted_planet_ids(universe.planetIDs, MissionType.INVASION)
    invasion_targeted_planet_ids.extend(get_invasion_targeted_planet_ids(universe.planetIDs, MissionType.ORBITAL_INVASION))
    all_invasion_targeted_system_ids = set(PlanetUtilsAI.get_systems(invasion_targeted_planet_ids))

    invasion_fleet_ids = FleetUtilsAI.get_empire_fleet_ids_by_role(MissionType.INVASION)
    num_invasion_fleets = len(FleetUtilsAI.extract_fleet_ids_without_mission_types(invasion_fleet_ids))

    print "Current Invasion Targeted SystemIDs: ", PlanetUtilsAI.sys_name_ids(AIstate.invasionTargetedSystemIDs)
    print "Current Invasion Targeted PlanetIDs: ", PlanetUtilsAI.planet_name_ids(invasion_targeted_planet_ids)
    print invasion_fleet_ids and "Invasion Fleet IDs: %s" % invasion_fleet_ids or "Available Invasion Fleets: 0"
    print "Invasion Fleets Without Missions: %s" % num_invasion_fleets

    invasion_timer.start("planning troop base production")
    # only do base invasions if aggression is typical or above
    reserved_troop_base_targets = []
    if foAI.foAIstate.aggression > fo.aggression.typical:
        available_pp = {}
        for el in empire.planetsWithAvailablePP:  # keys are sets of ints; data is doubles
            avail_pp = el.data()
            for pid in el.key():
                available_pp[pid] = avail_pp
        for pid in invadable_planet_ids:  # TODO: reorganize
            planet = universe.getPlanet(pid)
            if not planet:
                continue
            sys_id = planet.systemID
            sys_partial_vis_turn = universe.getVisibilityTurnsMap(planet.systemID, empire_id).get(fo.visibility.partial, -9999)
            planet_partial_vis_turn = universe.getVisibilityTurnsMap(pid, empire_id).get(fo.visibility.partial, -9999)
            if planet_partial_vis_turn < sys_partial_vis_turn:
                continue
            for pid2 in state.get_empire_inhabited_planets_by_system().get(sys_id, []):
                if available_pp.get(pid2, 0) < 2:  # TODO: improve troop base PP sufficiency determination
                    break
                planet2 = universe.getPlanet(pid2)
                if not planet2:
                    continue
                if pid not in foAI.foAIstate.qualifyingTroopBaseTargets and planet2.speciesName in ColonisationAI.empire_ship_builders:
                    foAI.foAIstate.qualifyingTroopBaseTargets.setdefault(pid, [pid2, -1])
                    break

        for pid in list(foAI.foAIstate.qualifyingTroopBaseTargets):
            planet = universe.getPlanet(pid)  # TODO: also check that still have a colony in this system that can make troops
            if planet and planet.owner == empire_id:
                del foAI.foAIstate.qualifyingTroopBaseTargets[pid]

        secure_ai_fleet_missions = foAI.foAIstate.get_fleet_missions_with_any_mission_types([MissionType.SECURE])
        for pid in (set(foAI.foAIstate.qualifyingTroopBaseTargets.keys()) - set(invasion_targeted_planet_ids)):  # TODO: consider overriding standard invasion mission
            planet = universe.getPlanet(pid)
            if foAI.foAIstate.qualifyingTroopBaseTargets[pid][1] != -1:
                reserved_troop_base_targets.append(pid)
                if planet:
                    all_invasion_targeted_system_ids.add(planet.systemID)
                continue  # already building for here
            sys_id = planet.systemID
            this_sys_status = foAI.foAIstate.systemStatus.get(sys_id, {})
            if (planet.currentMeterValue(fo.meterType.shield) > 0 and
                    this_sys_status.get('myFleetRating', 0) < 0.8 * this_sys_status.get('totalThreat', 0)):
                continue
            loc = foAI.foAIstate.qualifyingTroopBaseTargets[pid][0]
            best_base_trooper_here = ProductionAI.get_best_ship_info(PriorityType.PRODUCTION_ORBITAL_INVASION, loc)[1]
            loc_planet = universe.getPlanet(loc)
            if best_base_trooper_here is None:  # shouldn't be possible at this point, but just to be safe
                print "Could not find a suitable orbital invasion design at %s" % loc_planet
                continue
            # TODO: have TroopShipDesigner give the expected number of troops including species effects directly
            troops_per_ship = best_base_trooper_here.troopCapacity
            species_troop_grade = CombatRatingsAI.get_species_troops_grade(loc_planet.speciesName)
            troops_per_ship = CombatRatingsAI.weight_attack_troops(troops_per_ship, species_troop_grade)
            if not troops_per_ship:
                print "The best orbital invasion design at %s seems not to have any troop capacity." % loc_planet
                continue
            this_score, p_troops = evaluate_invasion_planet(pid, empire, secure_ai_fleet_missions, False)
            _, col_design, build_choices = ProductionAI.get_best_ship_info(PriorityType.PRODUCTION_ORBITAL_INVASION, loc)
            if not col_design:
                continue
            if loc not in build_choices:
                sys.stderr.write(
                    'Best troop design %s can not be produces in at planet with id: %s\d' % (col_design, build_choices)
                )
            n_bases = math.ceil((p_troops + 1) / troops_per_ship)  # TODO: reconsider this +1 safety factor
            print "Invasion base planning, need %d troops at %d pership, will build %d ships." % ((p_troops + 1), troops_per_ship, n_bases)
            retval = fo.issueEnqueueShipProductionOrder(col_design.id, loc)
            print "Enqueueing %d Troop Bases at %s for %s" % (n_bases, PlanetUtilsAI.planet_name_ids([loc]), PlanetUtilsAI.planet_name_ids([pid]))
            if retval != 0:
                all_invasion_targeted_system_ids.add(planet.systemID)
                reserved_troop_base_targets.append(pid)
                foAI.foAIstate.qualifyingTroopBaseTargets[pid][1] = loc
                fo.issueChangeProductionQuantityOrder(empire.productionQueue.size - 1, 1, int(n_bases))
                fo.issueRequeueProductionOrder(empire.productionQueue.size - 1, 0)

    invasion_timer.start("evaluating target planets")
    # TODO: check if any invasion_targeted_planet_ids need more troops assigned
    evaluated_planet_ids = list(set(invadable_planet_ids) - set(invasion_targeted_planet_ids) - set(reserved_troop_base_targets))
    evaluated_planets = assign_invasion_values(evaluated_planet_ids, empire)

    sorted_planets = [(pid, pscore % 10000, ptroops) for pid, (pscore, ptroops) in evaluated_planets.items()]
    sorted_planets.sort(key=lambda x: x[1], reverse=True)
    sorted_planets = [(pid, pscore % 10000, ptroops) for pid, pscore, ptroops in sorted_planets]

    invasion_table = Table([Text('Planet'), Float('Score'), Text('Species'), Float('Troops')],
                           table_name="Potential Targets for Invasion Turn %d" % fo.currentTurn())

    for pid, pscore, ptroops in sorted_planets:
        planet = universe.getPlanet(pid)
        invasion_table.add_row([
            planet,
            pscore,
            planet and planet.speciesName or "unknown",
            ptroops
        ])
    print
    invasion_table.print_table()

    sorted_planets = filter(lambda x: x[1] > 0, sorted_planets)
    # export opponent planets for other AI modules
    AIstate.opponentPlanetIDs = [pid for pid, _, _ in sorted_planets]
    AIstate.invasionTargets = sorted_planets

    # export invasion targeted systems for other AI modules
    AIstate.invasionTargetedSystemIDs = list(all_invasion_targeted_system_ids)
    invasion_timer.stop(section_name="evaluating %d target planets" % (len(evaluated_planet_ids)))
    invasion_timer.end()