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), ) foci_table.print_table(info) 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(): warning( "Population Warning! -- %s has unsustainable current pop %d -- target %d", name, cp, mp)
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 = {} for priority_type in get_priority_resource_types(): resource_priorities[priority_type] = foAI.foAIstate.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) ]) foci_table.print_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 __init__(self, status_only: bool = False): self._empire = fo.getEmpire() self._universe = fo.getUniverse() self._aistate = get_aistate() # resourceAvailable includes this turns production, but that is wrong for influence self._ip = self._empire.resourceAvailable( fo.resourceType.influence) - self._get_infl_prod() self._adopted = set(self._empire.adoptedPolicies) # When we continue a game in which we just adopted a policy, game state shows the policy as adopted, # but IP still unspent. Correct it here, then calculate anew whether we want to adopt it. if not status_only: for entry in self._empire.turnsPoliciesAdopted: if entry.data() == fo.currentTurn(): debug(f"reverting saved adopt {entry.key()}") fo.issueDeadoptPolicyOrder(entry.key()) self._adopted.remove(entry.key()) self._originally_adopted = copy(self._adopted) empire_owned_planet_ids = PlanetUtilsAI.get_owned_planets_by_empire() self._populated_planet_ids = PlanetUtilsAI.get_populated_planet_ids( empire_owned_planet_ids) self._num_populated = len(self._populated_planet_ids) self._num_outposts = len(empire_owned_planet_ids) - self._num_populated self._max_turn_bureaucracy = self._calculate_max_turn_bureaucracy() self._centralization_cost = fo.getPolicy(centralization).adoptionCost() self._bureaucracy_cost = fo.getPolicy(bureaucracy).adoptionCost() self._wanted_ip = self._wanted_for_bureaucracy() self._adoptable = self._get_adoptable() self._available = set(self._empire.availablePolicies) self._rating_functions = { propaganda: lambda: 20 + self._rate_opinion(propaganda), algo_research: self._rate_algo_research, diversity: self._rate_diversity, artisans: self._rate_artisans, population: self._rate_population, # military policies are mostly chosen by opinion, plus some rule-of-thumb values allied_repair: lambda: self._rate_opinion( charge), # no effect, unless we have allies... charge: lambda: 5 + self._rate_opinion(charge), # A small bonus in battle scanning: lambda: 20 + self._rate_opinion( scanning), # May help us detect ships and planets simplicity: lambda: 20 + self._rate_opinion( simplicity), # Makes simple ships cheaper engineering: self._rate_engineering_corps, exploration: lambda: 10 + self._rate_opinion( exploration), # may give a little research, speeds up scouts flanking: lambda: 5 + self._rate_opinion( flanking), # A small bonus in battle recruitment: lambda: 15 + self._rate_opinion( recruitment), # cheaper troop ships }
def print_resources_priority(): """calculate top resource priority""" universe = fo.getUniverse() empire = fo.getEmpire() empirePlanetIDs = PlanetUtilsAI.get_owned_planets_by_empire( universe.planetIDs) print "Resource Management:" print print "Resource Priorities:" resourcePriorities = {} for priorityType in get_priority_resource_types(): resourcePriorities[priorityType] = foAI.foAIstate.get_priority( priorityType) sortedPriorities = resourcePriorities.items() sortedPriorities.sort(lambda x, y: cmp(x[1], y[1]), reverse=True) topPriority = -1 for evaluationPair in sortedPriorities: if topPriority < 0: topPriority = evaluationPair[0] print " ResourcePriority |Score: %s | %s " % ( AIPriorityTypeNames.name(evaluationPair[0]), evaluationPair[1]) # what is the focus of available resource centers? print warnings = {} print "Planet Resources Foci:" for planetID in empirePlanetIDs: planet = universe.getPlanet(planetID) planetPopulation = planet.currentMeterValue(fo.meterType.population) maxPop = planet.currentMeterValue(fo.meterType.targetPopulation) if maxPop < 1 and planetPopulation > 0: warnings[planet.name] = (planetPopulation, maxPop) statusStr = " ID: " + str(planetID) + " Name: % 18s -- % 6s % 8s " % ( str(planet.name), str(planet.size), str(planet.type)) statusStr += " Focus: % 8s" % ("_".join( str(planet.focus).split("_")[1:])[:8]) + " Species: " + str( planet.speciesName) + " Pop: %2d/%2d" % (planetPopulation, maxPop) print statusStr print "\n\nEmpire Totals:\nPopulation: %5d \nProduction: %5d\nResearch: %5d\n" % ( empire.population(), empire.productionPoints, empire.resourceProduction(fo.resourceType.research)) if warnings != {}: for pname in warnings: mp, cp = warnings[pname] print "Population Warning! -- %s has unsustainable current pop %d -- target %d" % ( pname, cp, mp) print warnings.clear()
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 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 Management:" print print "Resource Priorities:" resource_priorities = {} for priority_type in get_priority_resource_types(): resource_priorities[priority_type] = foAI.foAIstate.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 " ResourcePriority |Score: %s | %s " % ( evaluation_priority, evaluation_score) # what is the focus of available resource centers? print warnings = {} # TODO combine this with previous table to reduce report duplication? print "Planet Resources Foci:" 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) print " ID: %d Name: % 18s -- % 6s % 8s Focus: % 8s Species: %s Pop: %2d/%2d" % ( pid, planet.name, planet.size, planet.type, "_".join( str(planet.focus).split("_")[1:])[:8], planet.speciesName, population, max_population) print "\n\nEmpire Totals:\nPopulation: %5d \nProduction: %5d\nResearch: %5d\n" % ( empire.population(), empire.productionPoints, empire.resourceProduction(fo.resourceType.research)) if warnings != {}: for name in warnings: mp, cp = warnings[name] print "Population Warning! -- %s has unsustainable current pop %d -- target %d" % ( name, cp, mp) print warnings.clear()
def __init__(self): universe = fo.getUniverse() resource_timer.start("getPlanets") planet_ids = list(PlanetUtilsAI.get_owned_planets_by_empire(universe.planetIDs)) resource_timer.start("Targets") self.all_planet_info = {pid: PlanetFocusInfo(universe.getPlanet(pid)) for pid in planet_ids} self.raw_planet_info = dict(self.all_planet_info) self.baked_planet_info = {} for pid, pinfo in self.raw_planet_info.items(): if not pinfo.planet.availableFoci: self.baked_planet_info[pid] = self.raw_planet_info.pop(pid)
def __init__(self): universe = fo.getUniverse() resource_timer.start("getPlanets") planet_ids = list(PlanetUtilsAI.get_owned_planets_by_empire(universe.planetIDs)) resource_timer.start("Targets") self.all_planet_info = {pid: PlanetFocusInfo(universe.getPlanet(pid)) for pid in planet_ids} self.raw_planet_info = dict(self.all_planet_info) self.baked_planet_info = {} for pid, info in self.raw_planet_info.items(): if not info.planet.availableFoci: self.baked_planet_info[pid] = self.raw_planet_info.pop(pid)
def _calculate_industry_priority(): # currently only used to print status """calculates the demand for industry""" universe = fo.getUniverse() empire = fo.getEmpire() # get current industry production & Target industry_production = empire.resourceProduction(fo.resourceType.industry) owned_planet_ids = PlanetUtilsAI.get_owned_planets_by_empire(universe.planetIDs) planets = map(universe.getPlanet, owned_planet_ids) target_pp = sum(map(lambda x: x.currentMeterValue(fo.meterType.targetIndustry), planets)) # currently, previously set to 50 in calculatePriorities(), this is just for reporting industry_priority = foAI.foAIstate.get_priority(PriorityType.RESOURCE_PRODUCTION) print print "Industry Production (current/target) : ( %.1f / %.1f ) at turn %s" % (industry_production, target_pp, fo.currentTurn()) print "Priority for Industry: %s" % industry_priority return industry_priority
def _calculate_industry_priority(): # currently only used to print status """calculates the demand for industry""" universe = fo.getUniverse() empire = fo.getEmpire() # get current industry production & Target industry_production = empire.resourceProduction(fo.resourceType.industry) owned_planet_ids = PlanetUtilsAI.get_owned_planets_by_empire(universe.planetIDs) planets = map(universe.getPlanet, owned_planet_ids) target_pp = sum(map(lambda x: x.currentMeterValue(fo.meterType.targetIndustry), planets)) # currently, previously set to 50 in calculatePriorities(), this is just for reporting industry_priority = foAI.foAIstate.get_priority(PriorityType.RESOURCE_PRODUCTION) print print "Industry Production (current/target) : ( %.1f / %.1f ) at turn %s" % (industry_production, target_pp, fo.currentTurn()) print "Priority for Industry: %s" % industry_priority return industry_priority
def _calculate_industry_priority(): # currently only used to print status """calculates the demand for industry""" universe = fo.getUniverse() empire = fo.getEmpire() # get current industry production & Target industry_production = empire.resourceProduction(fo.resourceType.industry) owned_planet_ids = PlanetUtilsAI.get_owned_planets_by_empire() planets = (universe.getPlanet(x) for x in owned_planet_ids) target_pp = sum( x.currentMeterValue(fo.meterType.targetIndustry) for x in planets) # currently, previously set to 50 in calculatePriorities(), this is just for reporting industry_priority = get_aistate().get_priority( PriorityType.RESOURCE_PRODUCTION) debug("") debug("Industry Production (current/target) : ( %.1f / %.1f ) at turn %s" % (industry_production, target_pp, fo.currentTurn())) debug("Priority for Industry: %s" % industry_priority) return industry_priority
def print_resources_priority(): """calculate top resource priority""" universe = fo.getUniverse() empire = fo.getEmpire() empirePlanetIDs = PlanetUtilsAI.get_owned_planets_by_empire(universe.planetIDs) print "Resource Management:" print print "Resource Priorities:" resourcePriorities = {} for priorityType in get_priority_resource_types(): resourcePriorities[priorityType] = foAI.foAIstate.get_priority(priorityType) sortedPriorities = resourcePriorities.items() sortedPriorities.sort(lambda x, y: cmp(x[1], y[1]), reverse=True) topPriority = -1 for evaluationPair in sortedPriorities: if topPriority < 0: topPriority = evaluationPair[0] print " ResourcePriority |Score: %s | %s " % (AIPriorityTypeNames.name(evaluationPair[0]), evaluationPair[1]) # what is the focus of available resource centers? print warnings = {} print "Planet Resources Foci:" for planetID in empirePlanetIDs: planet = universe.getPlanet(planetID) planetPopulation = planet.currentMeterValue(fo.meterType.population) maxPop = planet.currentMeterValue(fo.meterType.targetPopulation) if maxPop < 1 and planetPopulation > 0: warnings[planet.name] = (planetPopulation, maxPop) statusStr = " ID: " + str(planetID) + " Name: % 18s -- % 6s % 8s " % (str(planet.name), str(planet.size), str(planet.type)) statusStr += " Focus: % 8s" % ("_".join(str(planet.focus).split("_")[1:])[:8]) + " Species: " + str(planet.speciesName) + " Pop: %2d/%2d" % (planetPopulation, maxPop) print statusStr print "\n\nEmpire Totals:\nPopulation: %5d \nProduction: %5d\nResearch: %5d\n" % (empire.population(), empire.productionPoints, empire.resourceProduction(fo.resourceType.research)) if warnings != {}: for pname in warnings: mp, cp = warnings[pname] print "Population Warning! -- %s has unsustainable current pop %d -- target %d" % (pname, cp, mp) print warnings.clear()
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 Management:" print print "Resource Priorities:" resource_priorities = {} for priority_type in get_priority_resource_types(): resource_priorities[priority_type] = foAI.foAIstate.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 " ResourcePriority |Score: %s | %s " % (evaluation_priority, evaluation_score) # what is the focus of available resource centers? print warnings = {} # TODO combine this with previous table to reduce report duplication? print "Planet Resources Foci:" 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) print " ID: %d Name: % 18s -- % 6s % 8s Focus: % 8s Species: %s Pop: %2d/%2d" % (pid, planet.name, planet.size, planet.type, "_".join(str(planet.focus).split("_")[1:])[:8], planet.speciesName, population, max_population) print "\n\nEmpire Totals:\nPopulation: %5d \nProduction: %5d\nResearch: %5d\n" % (empire.population(), empire.productionPoints, empire.resourceProduction(fo.resourceType.research)) if warnings != {}: for name in warnings: mp, cp = warnings[name] print "Population Warning! -- %s has unsustainable current pop %d -- target %d" % (name, cp, mp) print warnings.clear()
def __init__(self): universe = fo.getUniverse() resource_timer.start("getPlanets") planet_ids = list(PlanetUtilsAI.get_owned_planets_by_empire()) resource_timer.start("Targets") self.all_planet_info = { pid: PlanetFocusInfo(universe.getPlanet(pid)) for pid in planet_ids } self.raw_planet_info = dict(self.all_planet_info) self.baked_planet_info = {} for pid, pinfo in list(self.raw_planet_info.items()): if not pinfo.planet.availableFoci: self.baked_planet_info[pid] = self.raw_planet_info.pop(pid) aistate = get_aistate() self.priority = ( aistate.get_priority(PriorityType.RESOURCE_PRODUCTION), aistate.get_priority(PriorityType.RESOURCE_RESEARCH), aistate.get_priority(PriorityType.RESOURCE_INFLUENCE), )
def get_military_fleets(mil_fleets_ids=None, try_reset=True, thisround="Main"): """Get armed military fleets.""" global _military_allocations universe = fo.getUniverse() empire_id = fo.empireID() home_system_id = PlanetUtilsAI.get_capital_sys_id() all_military_fleet_ids = (mil_fleets_ids if mil_fleets_ids is not None else FleetUtilsAI.get_empire_fleet_ids_by_role( MissionType.MILITARY)) # Todo: This block had been originally added to address situations where fleet missions were not properly # terminating, leaving fleets stuck in stale deployments. Assess if this block is still needed at all; delete # if not, otherwise restructure the following code so that in event a reset is occurring greater priority is given # to providing military support to locations where a necessary Secure mission might have just been released (i.e., # at invasion and colony/outpost targets where the troopships and colony ships are on their way), or else allow # only a partial reset which does not reset Secure missions. enable_periodic_mission_reset = False if enable_periodic_mission_reset and try_reset and ( fo.currentTurn() + empire_id) % 30 == 0 and thisround == "Main": debug( "Resetting all Military missions as part of an automatic periodic reset to clear stale missions." ) try_again(all_military_fleet_ids, try_reset=False, thisround=thisround + " Reset") return mil_fleets_ids = list( FleetUtilsAI.extract_fleet_ids_without_mission_types( all_military_fleet_ids)) mil_needing_repair_ids, mil_fleets_ids = avail_mil_needing_repair( mil_fleets_ids, split_ships=True) avail_mil_rating = combine_ratings( get_fleet_rating(x) for x in mil_fleets_ids) if not mil_fleets_ids: if "Main" in thisround: _military_allocations = [] return [] # for each system, get total rating of fleets assigned to it already_assigned_rating = {} already_assigned_rating_vs_planets = {} aistate = get_aistate() systems_status = aistate.systemStatus enemy_sup_factor = {} # enemy supply for sys_id in universe.systemIDs: already_assigned_rating[sys_id] = 0 already_assigned_rating_vs_planets[sys_id] = 0 enemy_sup_factor[sys_id] = min( 2, len( systems_status.get(sys_id, {}).get("enemies_nearly_supplied", []))) for fleet_id in [ fid for fid in all_military_fleet_ids if fid not in mil_fleets_ids ]: ai_fleet_mission = aistate.get_fleet_mission(fleet_id) if not ai_fleet_mission.target: # shouldn't really be possible continue last_sys = ( ai_fleet_mission.target.get_system().id ) # will count this fleet as assigned to last system in target list # TODO last_sys or target sys? this_rating = get_fleet_rating(fleet_id) this_rating_vs_planets = get_fleet_rating_against_planets(fleet_id) already_assigned_rating[last_sys] = combine_ratings( already_assigned_rating.get(last_sys, 0), this_rating) already_assigned_rating_vs_planets[last_sys] = combine_ratings( already_assigned_rating_vs_planets.get(last_sys, 0), this_rating_vs_planets) for sys_id in universe.systemIDs: my_defense_rating = systems_status.get(sys_id, {}).get("mydefenses", {}).get("overall", 0) already_assigned_rating[sys_id] = combine_ratings( my_defense_rating, already_assigned_rating[sys_id]) if _verbose_mil_reporting and already_assigned_rating[sys_id]: debug( "\t System %s already assigned rating %.1f" % (universe.getSystem(sys_id), already_assigned_rating[sys_id])) # get systems to defend capital_id = PlanetUtilsAI.get_capital() if capital_id is not None: capital_planet = universe.getPlanet(capital_id) else: capital_planet = None # TODO: if no owned planets try to capture one! if capital_planet: capital_sys_id = capital_planet.systemID else: # should be rare, but so as to not break code below, pick a randomish mil-centroid system capital_sys_id = None # unless we can find one to use system_dict = {} for fleet_id in all_military_fleet_ids: status = aistate.fleetStatus.get(fleet_id, None) if status is not None: system_id = status["sysID"] if not list(universe.getSystem(system_id).planetIDs): continue system_dict[system_id] = system_dict.get( system_id, 0) + status.get("rating", 0) ranked_systems = sorted([(val, sys_id) for sys_id, val in system_dict.items()]) if ranked_systems: capital_sys_id = ranked_systems[-1][-1] else: try: capital_sys_id = next(iter( aistate.fleetStatus.items()))[1]["sysID"] except: # noqa: E722 pass num_targets = max(10, PriorityAI.allotted_outpost_targets) top_target_planets = ([ pid for pid, pscore, trp in AIstate.invasionTargets[:PriorityAI.allotted_invasion_targets()] if pscore > InvasionAI.MIN_INVASION_SCORE ] + [ pid for pid, (pscore, spec) in list(aistate.colonisableOutpostIDs.items()) [:num_targets] if pscore > InvasionAI.MIN_INVASION_SCORE ] + [ pid for pid, (pscore, spec) in list(aistate.colonisablePlanetIDs.items()) [:num_targets] if pscore > InvasionAI.MIN_INVASION_SCORE ]) top_target_planets.extend(aistate.qualifyingTroopBaseTargets.keys()) base_col_target_systems = PlanetUtilsAI.get_systems(top_target_planets) top_target_systems = [] for sys_id in AIstate.invasionTargetedSystemIDs + base_col_target_systems: if sys_id not in top_target_systems: if aistate.systemStatus[sys_id][ "totalThreat"] > get_tot_mil_rating(): continue top_target_systems.append( sys_id) # doing this rather than set, to preserve order try: # capital defense allocation_helper = AllocationHelper( already_assigned_rating, already_assigned_rating_vs_planets, avail_mil_rating, try_reset) if capital_sys_id is not None: CapitalDefenseAllocator(capital_sys_id, allocation_helper).allocate() # defend other planets empire_planet_ids = PlanetUtilsAI.get_owned_planets_by_empire() empire_occupied_system_ids = list( set(PlanetUtilsAI.get_systems(empire_planet_ids)) - {capital_sys_id}) for sys_id in empire_occupied_system_ids: PlanetDefenseAllocator(sys_id, allocation_helper).allocate() # attack / protect high priority targets for sys_id in top_target_systems: TopTargetAllocator(sys_id, allocation_helper).allocate() # enemy planets other_targeted_system_ids = [ sys_id for sys_id in set( PlanetUtilsAI.get_systems(AIstate.opponentPlanetIDs)) if sys_id not in top_target_systems ] for sys_id in other_targeted_system_ids: TargetAllocator(sys_id, allocation_helper).allocate() # colony / outpost targets other_targeted_system_ids = [ sys_id for sys_id in list( set(AIstate.colonyTargetedSystemIDs + AIstate.outpostTargetedSystemIDs)) if sys_id not in top_target_systems ] for sys_id in other_targeted_system_ids: OutpostTargetAllocator(sys_id, allocation_helper).allocate() # TODO blockade enemy systems # interior systems targetable_ids = set(get_systems_by_supply_tier(0)) current_mil_systems = [ sid for sid, _, _, _, _ in allocation_helper.allocations ] interior_targets1 = targetable_ids.difference(current_mil_systems) interior_targets = [ sid for sid in interior_targets1 if (allocation_helper.threat_bias + systems_status.get(sid, {}).get("totalThreat", 0) > 0.8 * allocation_helper.already_assigned_rating[sid]) ] for sys_id in interior_targets: InteriorTargetsAllocator(sys_id, allocation_helper).allocate() # TODO Exploration targets # border protections visible_system_ids = aistate.visInteriorSystemIDs | aistate.visBorderSystemIDs accessible_system_ids = ([ sys_id for sys_id in visible_system_ids if systems_connected(sys_id, home_system_id) ] if home_system_id != INVALID_ID else []) current_mil_systems = [ sid for sid, alloc, rvp, take_any, _ in allocation_helper.allocations if alloc > 0 ] border_targets1 = [ sid for sid in accessible_system_ids if sid not in current_mil_systems ] border_targets = [ sid for sid in border_targets1 if (allocation_helper.threat_bias + systems_status.get(sid, {}).get("fleetThreat", 0) + systems_status.get(sid, {}).get("planetThreat", 0) > 0.8 * allocation_helper.already_assigned_rating[sid]) ] for sys_id in border_targets: BorderSecurityAllocator(sys_id, allocation_helper).allocate() except ReleaseMilitaryException: try_again(all_military_fleet_ids) return new_allocations = [] remaining_mil_rating = avail_mil_rating # for top categories assign max_alloc right away as available for cat in ["capitol", "occupied", "topTargets"]: for sid, alloc, rvp, take_any, max_alloc in allocation_helper.allocation_by_groups.get( cat, []): if remaining_mil_rating <= 0: break this_alloc = min(remaining_mil_rating, max_alloc) new_allocations.append((sid, this_alloc, alloc, rvp, take_any)) remaining_mil_rating = rating_difference(remaining_mil_rating, this_alloc) base_allocs = set() # for lower priority categories, first assign base_alloc around to all, then top up as available for cat in ["otherTargets", "accessibleTargets", "exploreTargets"]: for sid, alloc, rvp, take_any, max_alloc in allocation_helper.allocation_by_groups.get( cat, []): if remaining_mil_rating <= 0: break alloc = min(remaining_mil_rating, alloc) base_allocs.add(sid) remaining_mil_rating = rating_difference(remaining_mil_rating, alloc) for cat in ["otherTargets", "accessibleTargets", "exploreTargets"]: for sid, alloc, rvp, take_any, max_alloc in allocation_helper.allocation_by_groups.get( cat, []): if sid not in base_allocs: break if remaining_mil_rating <= 0: new_allocations.append((sid, alloc, alloc, rvp, take_any)) else: local_max_avail = combine_ratings(remaining_mil_rating, alloc) new_rating = min(local_max_avail, max_alloc) new_allocations.append((sid, new_rating, alloc, rvp, take_any)) remaining_mil_rating = rating_difference( local_max_avail, new_rating) if "Main" in thisround: _military_allocations = new_allocations if _verbose_mil_reporting or "Main" in thisround: debug( "------------------------------\nFinal %s Round Military Allocations: %s \n-----------------------" % (thisround, dict([(sid, alloc) for sid, alloc, _, _, _ in new_allocations]))) debug("(Apparently) remaining military rating: %.1f" % remaining_mil_rating) return new_allocations
def _calculate_research_priority(): """Calculates the AI empire's demand for research.""" universe = fo.getUniverse() empire = fo.getEmpire() current_turn = fo.currentTurn() enemies_sighted = foAI.foAIstate.misc.get('enemies_sighted', {}) recent_enemies = [x for x in enemies_sighted if x > current_turn - 8] industry_priority = foAI.foAIstate.get_priority(PriorityType.RESOURCE_PRODUCTION) got_algo = tech_is_complete(AIDependencies.LRN_ALGO_ELEGANCE) got_quant = tech_is_complete(AIDependencies.LRN_QUANT_NET) research_queue_list = ResearchAI.get_research_queue_techs() orb_gen_tech = AIDependencies.PRO_ORBITAL_GEN got_orb_gen = tech_is_complete(orb_gen_tech) mgrav_prod_tech = AIDependencies.PRO_MICROGRAV_MAN got_mgrav_prod = tech_is_complete(mgrav_prod_tech) # got_solar_gen = tech_is_complete(AIDependencies.PRO_SOL_ORB_GEN) milestone_techs = ["PRO_SENTIENT_AUTOMATION", "LRN_DISTRIB_THOUGHT", "LRN_QUANT_NET", "SHP_WEAPON_2_4", "SHP_WEAPON_3_2", "SHP_WEAPON_4_2"] milestones_done = [mstone for mstone in milestone_techs if tech_is_complete(mstone)] print "Research Milestones accomplished at turn %d: %s" % (current_turn, milestones_done) total_pp = empire.productionPoints total_rp = empire.resourceProduction(fo.resourceType.research) industry_surge = (foAI.foAIstate.character.may_surge_industry(total_pp, total_rp) and (((orb_gen_tech in research_queue_list[:2] or got_orb_gen) and state.have_gas_giant) or ((mgrav_prod_tech in research_queue_list[:2] or got_mgrav_prod) and state.have_asteroids)) and (state.get_number_of_colonies() < 12)) # get current industry production & Target owned_planet_ids = PlanetUtilsAI.get_owned_planets_by_empire(universe.planetIDs) planets = map(universe.getPlanet, owned_planet_ids) target_rp = sum(map(lambda x: x.currentMeterValue(fo.meterType.targetResearch), planets)) galaxy_is_sparse = ColonisationAI.galaxy_is_sparse() enemies_sighted = foAI.foAIstate.misc.get('enemies_sighted', {}) style_index = foAI.foAIstate.character.preferred_research_cutoff([0, 1]) if foAI.foAIstate.character.may_maximize_research(): style_index += 1 cutoff_sets = [[25, 45, 70, 110], [30, 45, 70, 150], [25, 40, 80, 160]] cutoffs = cutoff_sets[style_index] settings = [[1.3, .7, .5, .4, .35], [1.4, 0.8, 0.6, 0.5, 0.35], [1.4, 0.8, 0.6, 0.5, 0.4]][style_index] if (current_turn < cutoffs[0]) or (not got_algo) or ((style_index == 0) and not got_orb_gen and (current_turn < cutoffs[1])): research_priority = settings[0] * industry_priority # high research at beginning of game to get easy gro tech and to get research booster Algotrithmic Elegance elif (not got_orb_gen) or (current_turn < cutoffs[1]): research_priority = settings[1] * industry_priority # med-high research elif current_turn < cutoffs[2]: research_priority = settings[2] * industry_priority # med-high industry elif current_turn < cutoffs[3]: research_priority = settings[3] * industry_priority # med-high industry else: research_queue = list(empire.researchQueue) research_priority = settings[4] * industry_priority # high industry , low research if len(research_queue) == 0: research_priority = 0 # done with research elif len(research_queue) < 5 and research_queue[-1].allocation > 0: research_priority = len(research_queue) * 0.01 * industry_priority # barely not done with research elif len(research_queue) < 10 and research_queue[-1].allocation > 0: research_priority = (4 + 2 * len(research_queue)) * 0.01 * industry_priority # almost done with research elif len(research_queue) < 20 and research_queue[int(len(research_queue) / 2)].allocation > 0: research_priority *= 0.7 # closing in on end of research if industry_surge: if galaxy_is_sparse and not any(enemies_sighted): research_priority *= 0.5 else: research_priority *= 0.8 if ((tech_is_complete("SHP_WEAPON_2_4") or tech_is_complete("SHP_WEAPON_4_1")) and tech_is_complete(AIDependencies.PROD_AUTO_NAME)): # industry_factor = [ [0.25, 0.2], [0.3, 0.25], [0.3, 0.25] ][style_index ] # researchPriority = min(researchPriority, industry_factor[got_solar_gen]*industryPriority) research_priority *= 0.9 if got_quant: research_priority = min(research_priority + 0.1 * industry_priority, research_priority * 1.3) research_priority = int(research_priority) print "Research Production (current/target) : ( %.1f / %.1f )" % (total_rp, target_rp) print "Priority for Research: %d (new target ~ %d RP)" % (research_priority, total_pp * research_priority / industry_priority) if len(enemies_sighted) < (2 + current_turn/20.0): # TODO: adjust for colonisation priority research_priority *= 1.2 if (current_turn > 20) and (len(recent_enemies) > 3): research_priority *= 0.8 return research_priority
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 = foAI.foAIstate.get_piloting_grades( loc_planet.speciesName) troops_per_ship = foAI.foAIstate.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()
def get_military_fleets(mil_fleets_ids=None, try_reset=True, thisround="Main"): """Get armed military fleets.""" global military_allocations, totMilRating, num_milships universe = fo.getUniverse() empire = fo.getEmpire() empire_id = empire.empireID capital_id = PlanetUtilsAI.get_capital() if capital_id is None: homeworld = None else: homeworld = universe.getPlanet(capital_id) if homeworld: home_system_id = homeworld.systemID else: home_system_id = -1 if mil_fleets_ids is not None: all_military_fleet_ids = mil_fleets_ids else: all_military_fleet_ids = FleetUtilsAI.get_empire_fleet_ids_by_role(MissionType.MILITARY) if try_reset and (fo.currentTurn() + empire_id) % 30 == 0 and thisround == "Main": try_again(all_military_fleet_ids, try_reset=False, thisround=thisround + " Reset") num_milships = 0 for fid in all_military_fleet_ids: num_milships += foAI.foAIstate.fleetStatus.get(fid, {}).get('nships', 0) enemy_rating = foAI.foAIstate.empire_standard_enemy_rating mil_fleets_ids = list(FleetUtilsAI.extract_fleet_ids_without_mission_types(all_military_fleet_ids)) mil_needing_repair_ids, mil_fleets_ids = avail_mil_needing_repair(mil_fleets_ids, split_ships=True) avail_mil_rating = sum(map(lambda x: foAI.foAIstate.get_rating(x).get('overall', 0), mil_fleets_ids)) if "Main" in thisround: print "==================================================" print "%s Round Available Military Rating: %d" % (thisround, avail_mil_rating) print "---------------------------------" remaining_mil_rating = avail_mil_rating allocations = [] allocation_groups = {} if not mil_fleets_ids: if "Main" in thisround: military_allocations = [] return [] # for each system, get total rating of fleets assigned to it already_assigned_rating = {} assigned_attack = {} assigned_hp = {} systems_status = foAI.foAIstate.systemStatus enemy_sup_factor = {} # enemy supply for sys_id in universe.systemIDs: assigned_attack[sys_id] = 0 assigned_hp[sys_id] = 0 enemy_sup_factor[sys_id] = min(2, len(systems_status.get(sys_id, {}).get('enemies_nearly_supplied', []))) for fleet_id in [fid for fid in all_military_fleet_ids if fid not in mil_fleets_ids]: ai_fleet_mission = foAI.foAIstate.get_fleet_mission(fleet_id) if not ai_fleet_mission.target: # shouldn't really be possible continue last_sys = ai_fleet_mission.target.get_system().id # will count this fleet as assigned to last system in target list assigned_attack[last_sys] += foAI.foAIstate.get_rating(fleet_id).get('attack', 0) assigned_hp[last_sys] += foAI.foAIstate.get_rating(fleet_id).get('health', 0) for sys_id in universe.systemIDs: mydefenses = systems_status.get(sys_id, {}).get('mydefenses', {}) mypattack = mydefenses.get('attack', 0) myphealth = mydefenses.get('health', 0) already_assigned_rating[sys_id] = (assigned_attack[sys_id] + mypattack) * (assigned_hp[sys_id] + myphealth) if verbose_mil_reporting and already_assigned_rating[sys_id]: print "\t System %s already assigned rating %.1f" % ( universe.getSystem(sys_id), already_assigned_rating[sys_id]) # get systems to defend capital_id = PlanetUtilsAI.get_capital() if capital_id is not None: capital_planet = universe.getPlanet(capital_id) else: capital_planet = None # TODO: if no owned planets try to capture one! if capital_planet: capital_sys_id = capital_planet.systemID else: # should be rare, but so as to not break code below, pick a randomish mil-centroid system capital_sys_id = None # unless we can find one to use system_dict = {} for fleet_id in all_military_fleet_ids: status = foAI.foAIstate.fleetStatus.get(fleet_id, None) if status is not None: sys_id = status['sysID'] if not list(universe.getSystem(sys_id).planetIDs): continue system_dict[sys_id] = system_dict.get(sys_id, 0) + status.get('rating', {}).get('overall', 0) ranked_systems = sorted([(val, sys_id) for sys_id, val in system_dict.items()]) if ranked_systems: capital_sys_id = ranked_systems[-1][-1] else: try: capital_sys_id = foAI.foAIstate.fleetStatus.items()[0][1]['sysID'] except: pass if False: if fo.currentTurn() < 20: threat_bias = 0 elif fo.currentTurn() < 40: threat_bias = 10 elif fo.currentTurn() < 60: threat_bias = 80 elif fo.currentTurn() < 80: threat_bias = 200 else: threat_bias = 400 else: threat_bias = 0 safety_factor = get_safety_factor() num_targets = max(10, PriorityAI.allotted_outpost_targets) top_target_planets = ([pid for pid, pscore, trp in AIstate.invasionTargets[:PriorityAI.allottedInvasionTargets] if pscore > 20] + [pid for pid, (pscore, spec) in foAI.foAIstate.colonisableOutpostIDs.items()[:num_targets] if pscore > 20] + [pid for pid, (pscore, spec) in foAI.foAIstate.colonisablePlanetIDs.items()[:num_targets] if pscore > 20]) top_target_planets.extend(foAI.foAIstate.qualifyingTroopBaseTargets.keys()) base_col_target_systems = PlanetUtilsAI.get_systems(top_target_planets) top_target_systems = [] for sys_id in AIstate.invasionTargetedSystemIDs + base_col_target_systems: if sys_id not in top_target_systems: if foAI.foAIstate.systemStatus[sys_id]['totalThreat'] > totMilRating: continue top_target_systems.append(sys_id) # doing this rather than set, to preserve order if verbose_mil_reporting: print "----------------------------" # allocation format: ( sysID, newAllocation, takeAny, maxMultiplier ) # ================================ # --------Capital Threat ---------- if capital_sys_id is not None: capital_sys_status = systems_status[capital_sys_id] capital_threat = safety_factor*(2 * threat_bias + combine_ratings_list([capital_sys_status[thrt_key] for thrt_key in ['totalThreat', 'neighborThreat']])) capital_threat += max(0, enemy_sup_factor[sys_id]*enemy_rating - capital_sys_status.get('my_neighbor_rating', 0)) local_support = combine_ratings(already_assigned_rating[capital_sys_id], capital_sys_status['my_neighbor_rating']) base_needed_rating = rating_needed(capital_sys_status['regional_threat'], local_support) needed_rating = max(base_needed_rating, rating_needed(1.4 * capital_threat, already_assigned_rating[capital_sys_id])) max_alloc = max(rating_needed(1.5 * capital_sys_status['regional_threat'], already_assigned_rating[capital_sys_id]), rating_needed(2 * capital_threat, already_assigned_rating[capital_sys_id])) new_alloc = 0 if try_reset: if needed_rating > 0.5*avail_mil_rating: try_again(all_military_fleet_ids) return if needed_rating > 0: new_alloc = min(remaining_mil_rating, needed_rating) allocations.append((capital_sys_id, new_alloc, True, max_alloc)) allocation_groups.setdefault('capitol', []).append((capital_sys_id, new_alloc, True, max_alloc)) if verbose_mil_reporting: report_format = ("\tAt Capital system %s, local threat %.1f, regional threat %.1f, local support %.1f, " "base_needed_rating %.1f, needed_rating %.1f, new allocation %.1f") print report_format % (universe.getSystem(capital_sys_id), capital_threat, capital_sys_status['regional_threat'], local_support, base_needed_rating, needed_rating, new_alloc) remaining_mil_rating -= new_alloc if "Main" in thisround or new_alloc > 0: if verbose_mil_reporting: print "Empire Capital System: (%d) %s -- threat : %d, military allocation: existing: %d ; new: %d" % (capital_sys_id, universe.getSystem(capital_sys_id).name, capital_threat, already_assigned_rating[capital_sys_id], new_alloc) print "-----------------" # ================================ # --------Empire Occupied Systems ---------- empire_planet_ids = PlanetUtilsAI.get_owned_planets_by_empire(universe.planetIDs) empire_occupied_system_ids = list(set(PlanetUtilsAI.get_systems(empire_planet_ids)) - {capital_sys_id}) if "Main" in thisround: if verbose_mil_reporting: print "Empire-Occupied Systems: %s" % (["| %d %s |" % (eo_sys_id, universe.getSystem(eo_sys_id).name) for eo_sys_id in empire_occupied_system_ids]) print "-----------------" new_alloc = 0 if empire_occupied_system_ids: oc_sys_tot_threat_v1 = [(o_s_id, threat_bias + safety_factor*combine_ratings_list( [systems_status.get(o_s_id, {}).get(thrt_key, 0) for thrt_key in ['totalThreat', 'neighborThreat']])) for o_s_id in empire_occupied_system_ids] tot_oc_sys_threat = sum([thrt for _, thrt in oc_sys_tot_threat_v1]) tot_cur_alloc = sum([already_assigned_rating[sid] for sid, _ in oc_sys_tot_threat_v1]) # intentionally after tallies, but perhaps should be before oc_sys_tot_threat = [] threat_details = {} for sys_id, sys_threat in oc_sys_tot_threat_v1: j2_threat = systems_status.get(sys_id, {}).get('jump2_threat', 0) local_defenses = combine_ratings_list([systems_status.get(sys_id, {}).get('my_neighbor_rating', 0), already_assigned_rating[sys_id]]) threat_details[sys_id] = (sys_threat, enemy_sup_factor[sys_id] * 0.5 * enemy_rating, j2_threat, local_defenses) oc_sys_tot_threat.append((sys_id, sys_threat + max(0, enemy_sup_factor[sys_id] * 0.5 * enemy_rating + j2_threat - local_defenses ))) oc_sys_alloc = 0 for sid, thrt in oc_sys_tot_threat: cur_alloc = already_assigned_rating[sid] needed_rating = rating_needed(1.3 * thrt, cur_alloc) max_alloc = rating_needed(2*thrt, cur_alloc) if (needed_rating > 0.8 * remaining_mil_rating) and try_reset: try_again(all_military_fleet_ids) return this_alloc = 0 if needed_rating > 0 and remaining_mil_rating > 0: this_alloc = max(0, min(needed_rating, 0.5 * avail_mil_rating, remaining_mil_rating)) new_alloc += this_alloc allocations.append((sid, this_alloc, True, max_alloc)) allocation_groups.setdefault('occupied', []).append((sid, this_alloc, True, max_alloc)) remaining_mil_rating -= this_alloc oc_sys_alloc += this_alloc if "Main" in thisround or this_alloc > 0: if verbose_mil_reporting: print "Provincial Occupied system %4d ( %10s ) has local threat %8d ; existing military allocation %d and new allocation %8d" % (sid, universe.getSystem(sid).name, thrt, cur_alloc, this_alloc) print "\t base threat was %.1f, supply_threat %.1f, jump2_threat %.1f, and local defenses %.1f" % ( threat_details[sid]) if "Main" in thisround or new_alloc > 0: if verbose_mil_reporting: print "Provincial Empire-Occupied Sytems under total threat: %d -- total mil allocation: existing %d ; new: %d" % (tot_oc_sys_threat, tot_cur_alloc, oc_sys_alloc) print "-----------------" # ================================ # --------Top Targeted Systems ---------- # TODO: do native invasions highest priority other_targeted_system_ids = top_target_systems if "Main" in thisround: if verbose_mil_reporting: print "Top Colony and Invasion Targeted Systems : %s" % (["| %d %s |" % (sys_id, universe.getSystem(sys_id).name) for sys_id in other_targeted_system_ids]) print "-----------------" new_alloc = 0 if other_targeted_system_ids: ot_sys_alloc = 0 ot_sys_threat = [(o_s_id, threat_bias + safety_factor * combine_ratings_list([ systems_status.get(o_s_id, {}).get('totalThreat', 0), 0.75 * systems_status.get(o_s_id, {}).get('neighborThreat', 0), 0.5 * systems_status.get(o_s_id, {}).get('jump2_threat', 0)])) for o_s_id in other_targeted_system_ids] totot_sys_threat = sum([thrt for sid, thrt in ot_sys_threat]) tot_cur_alloc = sum([already_assigned_rating[sid] for sid, thrt in ot_sys_threat]) # intentionally after tallies, but perhaps should be before ot_sys_threat = [(sys_id, sys_threat + enemy_sup_factor[sys_id] * 0.5 * enemy_rating) for sys_id, sys_threat in ot_sys_threat] for sid, thrt in ot_sys_threat: cur_alloc = already_assigned_rating[sid] needed_rating = rating_needed(1.4*thrt, cur_alloc) this_alloc = 0 # only record more allocation for this invasion if we already started or have enough rating available take_any = already_assigned_rating[sid] > 0 if needed_rating > 0 and (remaining_mil_rating > needed_rating or take_any): this_alloc = max(0, min(needed_rating, remaining_mil_rating)) max_alloc = rating_needed(3 * thrt, cur_alloc) new_alloc += this_alloc allocations.append((sid, this_alloc, take_any, max_alloc)) allocation_groups.setdefault('topTargets', []).append((sid, this_alloc, take_any, max_alloc)) remaining_mil_rating -= this_alloc ot_sys_alloc += this_alloc if "Main" in thisround or this_alloc > 0: if verbose_mil_reporting: print "Targeted system %4d ( %10s ) has local threat %8d ; existing military allocation %d and new allocation %8d" % (sid, universe.getSystem(sid).name, thrt, cur_alloc, this_alloc) if "Main" in thisround or new_alloc > 0: if verbose_mil_reporting: print "-----------------" print "Top Colony and Invasion Targeted Systems under total threat: %d -- total mil allocation-- existing: %d ; new: %d" % (totot_sys_threat, tot_cur_alloc, ot_sys_alloc) print "-----------------" # ================================ # --------Targeted Systems ---------- # TODO: do native invasions highest priority other_targeted_system_ids = [sys_id for sys_id in set(PlanetUtilsAI.get_systems(AIstate.opponentPlanetIDs)) if sys_id not in top_target_systems] if "Main" in thisround: if verbose_mil_reporting: print "Other Invasion Targeted Systems : %s" % (["| %d %s |" % (sys_id, universe.getSystem(sys_id).name) for sys_id in other_targeted_system_ids]) print "-----------------" # for these, calc local threat only, no neighbor threat, but use a multiplier for fleet safety new_alloc = 0 if other_targeted_system_ids: ot_sys_alloc = 0 ot_sys_threat = [(o_s_id, threat_bias + safety_factor*combine_ratings_list([ systems_status.get(o_s_id, {}).get('totalThreat', 0), 0.75*systems_status.get(o_s_id, {}).get('neighborThreat', 0), 0.5*systems_status.get(o_s_id, {}).get('jump2_threat', 0)])) for o_s_id in other_targeted_system_ids] totot_sys_threat = sum([thrt for sid, thrt in ot_sys_threat]) tot_cur_alloc = sum([already_assigned_rating[sid] for sid, thrt in ot_sys_threat]) # intentionally after tallies, but perhaps should be before ot_sys_threat = [(sys_id, sys_threat + enemy_sup_factor[sys_id] * 0.5 * enemy_rating) for sys_id, sys_threat in ot_sys_threat] for sid, thrt in ot_sys_threat: cur_alloc = already_assigned_rating[sid] needed_rating = rating_needed(1.4 * thrt, cur_alloc) this_alloc = 0 # only record more allocation for this invasion if we already started or have enough rating available take_any = already_assigned_rating[sid] > 0 if needed_rating > 0 and (remaining_mil_rating > needed_rating or take_any): this_alloc = max(0, min(needed_rating, remaining_mil_rating)) new_alloc += this_alloc max_alloc = rating_needed(2 * thrt, cur_alloc) allocations.append((sid, this_alloc, take_any, max_alloc)) allocation_groups.setdefault('otherTargets', []).append((sid, this_alloc, take_any, max_alloc)) remaining_mil_rating -= this_alloc ot_sys_alloc += this_alloc if "Main" in thisround or this_alloc > 0: if verbose_mil_reporting: print "Targeted system %4d ( %10s ) has local threat %8d ; existing military allocation %d and new allocation %8d" % (sid, universe.getSystem(sid).name, thrt, cur_alloc, this_alloc) if "Main" in thisround or new_alloc > 0: if verbose_mil_reporting: print "-----------------" print "Invasion Targeted Systems under total threat: %d -- total mil allocation-- existing: %d ; new: %d" % (totot_sys_threat, tot_cur_alloc, ot_sys_alloc) print "-----------------" other_targeted_system_ids = [sys_id for sys_id in list(set(AIstate.colonyTargetedSystemIDs + AIstate.outpostTargetedSystemIDs)) if sys_id not in top_target_systems] if "Main" in thisround: if verbose_mil_reporting: print "Other Targeted Systems : %s" % (["| %d %s |" % (sys_id, universe.getSystem(sys_id).name) for sys_id in other_targeted_system_ids]) print "-----------------" if other_targeted_system_ids: ot_sys_alloc = 0 ot_sys_threat = [(o_s_id, threat_bias + safety_factor*combine_ratings_list([ systems_status.get(o_s_id, {}).get('totalThreat', 0), 0.75*systems_status.get(o_s_id, {}).get('neighborThreat', 0), 0.5*systems_status.get(o_s_id, {}).get('jump2_threat', 0)])) for o_s_id in other_targeted_system_ids] totot_sys_threat = sum([thrt for sid, thrt in ot_sys_threat]) # intentionally after tallies, but perhaps should be before ot_sys_threat = [(sys_id, sys_threat + enemy_sup_factor[sys_id] * 0.5 * enemy_rating) for sys_id, sys_threat in ot_sys_threat] tot_cur_alloc = sum([already_assigned_rating[sid] for sid, thrt in ot_sys_threat]) new_alloc = 0 for sid, thrt in ot_sys_threat: cur_alloc = already_assigned_rating[sid] needed_rating = rating_needed(1.4 * thrt, cur_alloc) this_alloc = 0 # only record more allocation for this invasion if we already started or have enough rating available take_any = already_assigned_rating[sid] > 0 if needed_rating > 0 and (remaining_mil_rating > needed_rating or take_any): this_alloc = max(0, min(needed_rating, remaining_mil_rating)) new_alloc += this_alloc max_alloc = rating_needed(3*thrt, cur_alloc) allocations.append((sid, this_alloc, take_any, max_alloc)) allocation_groups.setdefault('otherTargets', []).append((sid, this_alloc, take_any, max_alloc)) remaining_mil_rating -= this_alloc ot_sys_alloc += this_alloc if "Main" in thisround or this_alloc > 0: if verbose_mil_reporting: print "Targeted system %4d ( %10s ) has local threat %8d ; existing military allocation %d and new allocation %8d" % (sid, universe.getSystem(sid).name, thrt, cur_alloc, this_alloc) if "Main" in thisround or new_alloc > 0: if verbose_mil_reporting: print "-----------------" print "Other Targeted Systems under total threat: %d -- total mil allocation-- existing: %d ; new: %d" % (totot_sys_threat, tot_cur_alloc, ot_sys_alloc) print "-----------------" other_targeted_system_ids = [] # targetable_ids = ColonisationAI.annexableSystemIDs.union(empire.fleetSupplyableSystemIDs) targetable_ids = set(ColonisationAI.systems_by_supply_tier.get(0, []) + ColonisationAI.systems_by_supply_tier.get(1, [])) for sys_id in AIstate.opponentSystemIDs: if sys_id in targetable_ids: other_targeted_system_ids.append(sys_id) else: for nID in universe.getImmediateNeighbors(sys_id, empire_id): if nID in targetable_ids: other_targeted_system_ids.append(sys_id) break if "Main" in thisround: if verbose_mil_reporting: print "Blockade Targeted Systems : %s" % (["| %d %s |" % (sys_id, universe.getSystem(sys_id).name) for sys_id in other_targeted_system_ids]) print "-----------------" if other_targeted_system_ids: ot_sys_alloc = 0 ot_sys_threat = [(o_s_id, threat_bias + safety_factor*combine_ratings_list([ systems_status.get(o_s_id, {}).get('totalThreat', 0), 0.75*systems_status.get(o_s_id, {}).get('neighborThreat', 0), 0.5*systems_status.get(o_s_id, {}).get('jump2_threat', 0)])) for o_s_id in other_targeted_system_ids] totot_sys_threat = sum([thrt for sid, thrt in ot_sys_threat]) tot_cur_alloc = sum([already_assigned_rating[sid] for sid, thrt in ot_sys_threat]) # intentionally after tallies, but perhaps should be before # this supply threat calc intentionally uses a lower multiplier 0.25 ot_sys_threat = [(sys_id, sys_threat + enemy_sup_factor[sys_id] * 0.25 * enemy_rating) for sys_id, sys_threat in ot_sys_threat] new_alloc = 0 for sid, thrt in ot_sys_threat: cur_alloc = already_assigned_rating[sid] needed_rating = rating_needed(1.4*thrt, cur_alloc) this_alloc = 0 # only record more allocation for this invasion if we already started or have enough rating available take_any = already_assigned_rating[sid] > 0 if needed_rating > 0 and (remaining_mil_rating > needed_rating or take_any): this_alloc = max(0, min(needed_rating, remaining_mil_rating)) new_alloc += this_alloc max_alloc = 1.5 * this_alloc allocations.append((sid, this_alloc, take_any, max_alloc)) allocation_groups.setdefault('otherTargets', []).append((sid, this_alloc, take_any, max_alloc)) remaining_mil_rating -= this_alloc ot_sys_alloc += this_alloc if "Main" in thisround or this_alloc > 0: if verbose_mil_reporting: print "Blockade Targeted system %4d ( %10s ) has local threat %8d ; existing military allocation %d and new allocation %8d" % (sid, universe.getSystem(sid).name, thrt, cur_alloc, this_alloc) if "Main" in thisround or new_alloc > 0: if verbose_mil_reporting: print "-----------------" print "Blockade Targeted Systems under total threat: %d -- total mil allocation-- existing: %d ; new: %d" % (totot_sys_threat, tot_cur_alloc, ot_sys_alloc) print "-----------------" current_mil_systems = [sid for sid, alloc, take_any, mm in allocations] interior_targets1 = targetable_ids.difference(current_mil_systems) interior_targets = [sid for sid in interior_targets1 if ( threat_bias + systems_status.get(sid, {}).get('totalThreat', 0) > 0.8 * already_assigned_rating[sid])] if "Main" in thisround: if verbose_mil_reporting: print print "Other Empire-Proximal Systems : %s" % (["| %d %s |" % (sys_id, universe.getSystem(sys_id).name) for sys_id in interior_targets1]) print "-----------------" # for these, calc local threat only, no neighbor threat, but use a multiplier for fleet safety new_alloc = 0 if interior_targets: ot_sys_alloc = 0 ot_sys_threat = [(o_s_id, threat_bias + safety_factor*(systems_status.get(o_s_id, {}).get('totalThreat', 0))) for o_s_id in interior_targets] totot_sys_threat = sum([thrt for sid, thrt in ot_sys_threat]) tot_cur_alloc = sum([already_assigned_rating[sid] for sid, thrt in ot_sys_threat]) # do not add enemy supply threat here for sid, thrt in ot_sys_threat: cur_alloc = already_assigned_rating[sid] needed_rating = rating_needed(1.5 * thrt, cur_alloc) this_alloc = 0 # only record more allocation for this invasion if we already started or have enough rating available take_any = already_assigned_rating[sid] > 0 if needed_rating > 0 and (remaining_mil_rating > needed_rating or take_any): this_alloc = max(0, min(needed_rating, remaining_mil_rating)) new_alloc += this_alloc max_alloc = 3 * this_alloc allocations.append((sid, this_alloc, take_any, max_alloc)) allocation_groups.setdefault('otherTargets', []).append((sid, this_alloc, take_any, max_alloc)) remaining_mil_rating -= this_alloc ot_sys_alloc += this_alloc if "Main" in thisround or this_alloc > 0: if verbose_mil_reporting: print "Other interior system %4d ( %10s ) has local threat %8d ; existing military allocation %d and new allocation %8d" % (sid, universe.getSystem(sid).name, thrt, cur_alloc, this_alloc) if "Main" in thisround or new_alloc > 0: if verbose_mil_reporting: print "-----------------" print "Other Interior Systems under total threat: %d -- total mil allocation-- existing: %d ; new: %d" % (totot_sys_threat, tot_cur_alloc, ot_sys_alloc) print "-----------------" elif "Main" in thisround: if verbose_mil_reporting: print "-----------------" print "No Other Interior Systems with fleet threat " print "-----------------" monster_dens = [] # explo_target_ids, _ = ExplorationAI.get_current_exploration_info(verbose=False) explo_target_ids = [] if "Main" in thisround: if verbose_mil_reporting: print print "Exploration-targeted Systems: %s" % (["| %d %s |" % (sys_id, universe.getSystem(sys_id).name) for sys_id in explo_target_ids]) print "-----------------" # for these, calc fleet threat only, no neighbor threat, but use a multiplier for fleet safety new_alloc = 0 if explo_target_ids: ot_sys_alloc = 0 ot_sys_threat = [(o_s_id, safety_factor*combine_ratings(systems_status.get(o_s_id, {}).get('fleetThreat', 0), systems_status.get(o_s_id, {}).get('monsterThreat', 0) + systems_status.get(o_s_id, {}).get('planetThreat', 0))) for o_s_id in explo_target_ids] totot_sys_threat = sum([thrt for sid, thrt in ot_sys_threat]) tot_cur_alloc = sum([0.8*already_assigned_rating[sid] for sid, thrt in ot_sys_threat]) # intentionally after tallies, but perhaps should be before # this supply threat calc intentionally uses a lower multiplier 0.25 ot_sys_threat = [(sys_id, sys_threat + enemy_sup_factor[sys_id] * 0.25 * enemy_rating) for sys_id, sys_threat in ot_sys_threat] for sid, thrt in ot_sys_threat: cur_alloc = already_assigned_rating[sid] needed_rating = rating_needed(1.4 * thrt, cur_alloc) this_alloc = 0 # only record more allocation for this invasion if we already started or have enough rating available take_any = False if needed_rating > 0 and (remaining_mil_rating > needed_rating or take_any): this_alloc = max(0, min(needed_rating, remaining_mil_rating)) new_alloc += this_alloc max_alloc = 2 * this_alloc allocations.append((sid, this_alloc, take_any, max_alloc)) allocation_groups.setdefault('exploreTargets', []).append((sid, this_alloc, take_any, max_alloc)) remaining_mil_rating -= this_alloc ot_sys_alloc += this_alloc if "Main" in thisround or this_alloc > 0: if verbose_mil_reporting: print "Exploration-targeted %4d ( %10s ) has local threat %8d ; existing military allocation %d and new allocation %8d" % (sid, universe.getSystem(sid).name, thrt, cur_alloc, this_alloc) if "Main" in thisround or new_alloc > 0: if verbose_mil_reporting: print "-----------------" print "Exploration-targeted s under total threat: %d -- total mil allocation-- existing: %d ; new: %d" % (totot_sys_threat, tot_cur_alloc, ot_sys_alloc) print "-----------------" visible_system_ids = foAI.foAIstate.visInteriorSystemIDs.keys() + foAI.foAIstate. visBorderSystemIDs.keys() accessible_system_ids = [sys_id for sys_id in visible_system_ids if universe.systemsConnected(sys_id, home_system_id, empire_id)] current_mil_systems = [sid for sid, alloc, take_any, multiplier in allocations if alloc > 0] border_targets1 = [sid for sid in accessible_system_ids if sid not in current_mil_systems] border_targets = [sid for sid in border_targets1 if (threat_bias + systems_status.get(sid, {}).get('fleetThreat', 0) + systems_status.get(sid, {}).get('planetThreat', 0) > 0.8*already_assigned_rating[sid])] if "Main" in thisround: if verbose_mil_reporting: print print "Empire-Accessible Systems not yet allocated military: %s" % (["| %d %s |" % (sys_id, universe.getSystem(sys_id) and universe.getSystem(sys_id).name) for sys_id in border_targets1]) print "-----------------" # for these, calc fleet threat only, no neighbor threat, but use a multiplier for fleet safety new_alloc = 0 if border_targets: ot_sys_alloc = 0 ot_sys_threat = [(o_s_id, threat_bias + safety_factor*combine_ratings(systems_status.get(o_s_id, {}).get('fleetThreat', 0), systems_status.get(o_s_id, {}).get('monsterThreat', 0) + systems_status.get(o_s_id, {}).get('planetThreat', 0))) for o_s_id in border_targets] totot_sys_threat = sum([thrt for sid, thrt in ot_sys_threat]) tot_cur_alloc = sum([0.8*already_assigned_rating[sid] for sid, thrt in ot_sys_threat]) # do not add enemy supply threat here for sid, thrt in ot_sys_threat: cur_alloc = already_assigned_rating[sid] needed_rating = rating_needed(1.2 * thrt, cur_alloc) this_alloc = 0 # only record more allocation for this invasion if we already started or have enough rating available take_any = False if needed_rating > 0 and (remaining_mil_rating > needed_rating or take_any): this_alloc = max(0, min(needed_rating, remaining_mil_rating)) new_alloc += this_alloc max_alloc = safety_factor*2*max(systems_status.get(sid, {}).get('totalThreat', 0), systems_status.get(sid, {}).get('neighborThreat', 0)) allocations.append((sid, this_alloc, take_any, max_alloc)) allocation_groups.setdefault('accessibleTargets', []).append((sid, this_alloc, take_any, max_alloc)) remaining_mil_rating -= this_alloc ot_sys_alloc += this_alloc if "Main" in thisround or this_alloc > 0: if verbose_mil_reporting: print "Other Empire-Accessible system %4d ( %10s ) has local biased threat %8d ; existing military allocation %d and new allocation %8d" % (sid, universe.getSystem(sid).name, thrt, cur_alloc, this_alloc) if "Main" in thisround or new_alloc > 0: if verbose_mil_reporting: print "-----------------" print "Other Empire-Accessible Systems under total biased threat: %d -- total mil allocation-- existing: %d ; new: %d" % (totot_sys_threat, tot_cur_alloc, ot_sys_alloc) print "-----------------" elif "Main" in thisround: if verbose_mil_reporting: print "-----------------" print "No Other Empire-Accessible Systems with biased local threat " print "-----------------" # monster den treatment probably unnecessary now if "Main" in thisround: if verbose_mil_reporting: print print "Big-Monster Dens: %s" % (["| %d %s |" % (sys_id, universe.getSystem(sys_id).name) for sys_id in monster_dens]) print "-----------------" # for these, calc fleet threat only, no neighbor threat, but use a multiplier for fleet safety new_alloc = 0 if monster_dens: ot_sys_alloc = 0 ot_sys_threat = [(o_s_id, safety_factor * combine_ratings_list([systems_status.get(o_s_id, {}).get('fleetThreat', 0), systems_status.get(o_s_id, {}).get('monsterThreat', 0), systems_status.get(o_s_id, {}).get('planetThreat', 0)])) for o_s_id in monster_dens] for sid, thrt in ot_sys_threat: cur_alloc = 0.8 * already_assigned_rating[sid] this_alloc = 0 if (thrt > cur_alloc) and remaining_mil_rating > 2 * thrt: this_alloc = int(0.99999 + (thrt - cur_alloc) * 1.5) new_alloc += this_alloc allocations.append((sid, this_alloc, False, 5)) remaining_mil_rating -= this_alloc ot_sys_alloc += this_alloc if "Main" in thisround or this_alloc > 0: if verbose_mil_reporting: print "Monster Den %4d ( %10s ) has local threat %8d ; existing military allocation %d and new allocation %8d" % (sid, universe.getSystem(sid).name, thrt, cur_alloc, this_alloc) if "Main" in thisround or new_alloc > 0: if verbose_mil_reporting: print "-----------------" new_allocations = [] remaining_mil_rating = avail_mil_rating # for top categories assign max_alloc right away as available for cat in ['capitol', 'occupied', 'topTargets']: for sid, alloc, take_any, max_alloc in allocation_groups.get(cat, []): if remaining_mil_rating <= 0: break this_alloc = min(remaining_mil_rating, max_alloc) new_allocations.append((sid, this_alloc, alloc, take_any)) remaining_mil_rating -= this_alloc base_allocs = set() # for lower priority categories, first assign base_alloc around to all, then top up as available for cat in ['otherTargets', 'accessibleTargets', 'exploreTargets']: for sid, alloc, take_any, max_alloc in allocation_groups.get(cat, []): if remaining_mil_rating <= 0: break base_allocs.add(sid) remaining_mil_rating -= alloc for cat in ['otherTargets', 'accessibleTargets', 'exploreTargets']: for sid, alloc, take_any, max_alloc in allocation_groups.get(cat, []): if sid not in base_allocs: break if remaining_mil_rating <= 0: new_allocations.append((sid, alloc, alloc, take_any)) else: new_rating = min(remaining_mil_rating + alloc, max_alloc) new_allocations.append((sid, new_rating, alloc, take_any)) remaining_mil_rating -= (new_rating - alloc) if "Main" in thisround: military_allocations = new_allocations minMilAllocations.clear() minMilAllocations.update([(sid, alloc) for sid, alloc, take_any, mm in allocations]) if verbose_mil_reporting or "Main" in thisround: print "------------------------------\nFinal %s Round Military Allocations: %s \n-----------------------" % (thisround, dict([(sid, alloc) for sid, alloc, minalloc, take_any in new_allocations])) print "(Apparently) remaining military rating: %.1f" % remaining_mil_rating # export military systems for other AI modules if "Main" in thisround: AIstate.militarySystemIDs = list(set([sid for sid, alloc, minalloc, take_any in new_allocations]).union([sid for sid in already_assigned_rating if already_assigned_rating[sid] > 0])) else: AIstate.militarySystemIDs = list(set([sid for sid, alloc, minalloc, take_any in new_allocations]).union(AIstate.militarySystemIDs)) return new_allocations
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()
def _calculate_research_priority(): """Calculates the AI empire's demand for research.""" universe = fo.getUniverse() empire = fo.getEmpire() empire_id = empire.empireID current_turn = fo.currentTurn() enemies_sighted = foAI.foAIstate.misc.get('enemies_sighted', {}) recent_enemies = [x for x in enemies_sighted if x > current_turn - 8] industry_priority = foAI.foAIstate.get_priority(PriorityType.RESOURCE_PRODUCTION) got_algo = tech_is_complete(AIDependencies.LRN_ALGO_ELEGANCE) got_quant = tech_is_complete(AIDependencies.LRN_QUANT_NET) research_queue_list = ResearchAI.get_research_queue_techs() orb_gen_tech = AIDependencies.PRO_ORBITAL_GEN got_orb_gen = tech_is_complete(orb_gen_tech) mgrav_prod_tech = AIDependencies.PRO_MICROGRAV_MAN got_mgrav_prod = tech_is_complete(mgrav_prod_tech) # got_solar_gen = tech_is_complete(AIDependencies.PRO_SOL_ORB_GEN) milestone_techs = ["PRO_SENTIENT_AUTOMATION", "LRN_DISTRIB_THOUGHT", "LRN_QUANT_NET", "SHP_WEAPON_2_4", "SHP_WEAPON_3_2", "SHP_WEAPON_4_2"] milestones_done = [mstone for mstone in milestone_techs if tech_is_complete(mstone)] print "Research Milestones accomplished at turn %d: %s" % (current_turn, milestones_done) total_pp = empire.productionPoints total_rp = empire.resourceProduction(fo.resourceType.research) industry_surge = (foAI.foAIstate.character.may_surge_industry(total_pp, total_rp) and (((orb_gen_tech in research_queue_list[:2] or got_orb_gen) and state.have_gas_giant) or ((mgrav_prod_tech in research_queue_list[:2] or got_mgrav_prod) and state.have_asteroids)) and (not (len(AIstate.popCtrIDs) >= 12))) # get current industry production & Target owned_planet_ids = PlanetUtilsAI.get_owned_planets_by_empire(universe.planetIDs) planets = map(universe.getPlanet, owned_planet_ids) target_rp = sum(map(lambda x: x.currentMeterValue(fo.meterType.targetResearch), planets)) galaxy_is_sparse = ColonisationAI.galaxy_is_sparse() enemies_sighted = foAI.foAIstate.misc.get('enemies_sighted', {}) style_index = foAI.foAIstate.character.preferred_research_cutoff([0, 1]) if foAI.foAIstate.character.may_maximize_research(): style_index += 1 cutoff_sets = [[25, 45, 70, 110], [30, 45, 70, 150], [25, 40, 80, 160]] cutoffs = cutoff_sets[style_index] settings = [[1.3, .7, .5, .4, .35], [1.4, 0.8, 0.6, 0.5, 0.35], [1.4, 0.8, 0.6, 0.5, 0.4]][style_index] if (current_turn < cutoffs[0]) or (not got_algo) or ((style_index == 0) and not got_orb_gen and (current_turn < cutoffs[1])): research_priority = settings[0] * industry_priority # high research at beginning of game to get easy gro tech and to get research booster Algotrithmic Elegance elif (not got_orb_gen) or (current_turn < cutoffs[1]): research_priority = settings[1] * industry_priority # med-high research elif current_turn < cutoffs[2]: research_priority = settings[2] * industry_priority # med-high industry elif current_turn < cutoffs[3]: research_priority = settings[3] * industry_priority # med-high industry else: research_queue = list(empire.researchQueue) research_priority = settings[4] * industry_priority # high industry , low research if len(research_queue) == 0: research_priority = 0 # done with research elif len(research_queue) < 5 and research_queue[-1].allocation > 0: research_priority = len(research_queue) * 0.01 * industry_priority # barely not done with research elif len(research_queue) < 10 and research_queue[-1].allocation > 0: research_priority = (4 + 2 * len(research_queue)) * 0.01 * industry_priority # almost done with research elif len(research_queue) < 20 and research_queue[int(len(research_queue) / 2)].allocation > 0: research_priority *= 0.7 # closing in on end of research if industry_surge: if galaxy_is_sparse and not any(enemies_sighted): research_priority *= 0.5 else: research_priority *= 0.8 if ((tech_is_complete("SHP_WEAPON_2_4") or tech_is_complete("SHP_WEAPON_4_1")) and tech_is_complete(AIDependencies.PROD_AUTO_NAME)): # industry_factor = [ [0.25, 0.2], [0.3, 0.25], [0.3, 0.25] ][style_index ] # researchPriority = min(researchPriority, industry_factor[got_solar_gen]*industryPriority) research_priority *= 0.9 if got_quant: research_priority = min(research_priority + 0.1 * industry_priority, research_priority * 1.3) research_priority = int(research_priority) print "Research Production (current/target) : ( %.1f / %.1f )" % (total_rp, target_rp) print "Priority for Research: %d (new target ~ %d RP)" % (research_priority, total_pp * research_priority / industry_priority) if len(enemies_sighted) < (2 + current_turn/20.0): # TODO: adjust for colonisation priority research_priority *= 1.2 if (current_turn > 20) and (len(recent_enemies) > 3): research_priority *= 0.8 return research_priority
def get_invasion_fleets(): invasion_timer.start("gathering initial info") all_invasion_fleet_ids = FleetUtilsAI.get_empire_fleet_ids_by_role(EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION) AIstate.invasionFleetIDs = FleetUtilsAI.extract_fleet_ids_without_mission_types(all_invasion_fleet_ids) # get suppliable planets universe = fo.getUniverse() empire = fo.getEmpire() empire_id = empire.empireID capital_id = PlanetUtilsAI.get_capital() homeworld=None if capital_id: homeworld = universe.getPlanet(capital_id) if homeworld: home_system_id = homeworld.systemID else: home_system_id = -1 fleet_suppliable_system_ids = empire.fleetSupplyableSystemIDs fleet_suppliable_planet_ids = PlanetUtilsAI.get_planets_in__systems_ids(fleet_suppliable_system_ids) prime_invadable_system_ids = set(ColonisationAI.annexable_system_ids) prime_invadable_planet_ids = PlanetUtilsAI.get_planets_in__systems_ids(prime_invadable_system_ids) 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 "Invasion Warning: this empire has no identifiable homeworld, will therefor treat all visible planets as accessible." accessible_system_ids = visible_system_ids # TODO: check if any troop ships still owned, use their system as home system acessible_planet_ids = PlanetUtilsAI.get_planets_in__systems_ids(accessible_system_ids) print "Accessible Systems: ", ", ".join(PlanetUtilsAI.sys_name_ids(accessible_system_ids)) print all_owned_planet_ids = PlanetUtilsAI.get_all_owned_planet_ids(acessible_planet_ids) # need these for unpopulated outposts all_populated_planets = PlanetUtilsAI.get_populated_planet_ids(acessible_planet_ids) # need this for natives print "All Visible and accessible Populated PlanetIDs (including this empire's): ", ", ".join(PlanetUtilsAI.planet_name_ids(all_populated_planets)) print print "Prime Invadable Target Systems: ", ", ".join(PlanetUtilsAI.sys_name_ids(prime_invadable_system_ids)) print empire_owned_planet_ids = PlanetUtilsAI.get_owned_planets_by_empire(universe.planetIDs) invadable_planet_ids = set(prime_invadable_planet_ids).intersection(set(all_owned_planet_ids).union(all_populated_planets) - set(empire_owned_planet_ids)) print "Prime Invadable PlanetIDs: ", ", ".join(PlanetUtilsAI.planet_name_ids(invadable_planet_ids)) print print "Current Invasion Targeted SystemIDs: ", ", ".join(PlanetUtilsAI.sys_name_ids(AIstate.invasionTargetedSystemIDs)) invasion_targeted_planet_ids = get_invasion_targeted_planet_ids(universe.planetIDs, EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION) invasion_targeted_planet_ids.extend(get_invasion_targeted_planet_ids(universe.planetIDs, EnumsAI.AIFleetMissionType.FLEET_MISSION_ORBITAL_INVASION)) all_invasion_targeted_system_ids = set(PlanetUtilsAI.get_systems(invasion_targeted_planet_ids)) print "Current Invasion Targeted PlanetIDs: ", ", ".join(PlanetUtilsAI.planet_name_ids(invasion_targeted_planet_ids)) invasion_fleet_ids = FleetUtilsAI.get_empire_fleet_ids_by_role(EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION) if not invasion_fleet_ids: print "Available Invasion Fleets: 0" else: print "Invasion FleetIDs: %s" % FleetUtilsAI.get_empire_fleet_ids_by_role(EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION) num_invasion_fleets = len(FleetUtilsAI.extract_fleet_ids_without_mission_types(invasion_fleet_ids)) 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 ColonisationAI.empire_species_systems.get(sys_id, {}).get('pids', []): 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([EnumsAI.AIFleetMissionType.FLEET_MISSION_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.getBestShipInfo(EnumsAI.AIPriorityType.PRIORITY_PRODUCTION_ORBITAL_INVASION, loc)[1] if best_base_trooper_here == None: # shouldn't be possible at this point, but just to be safe continue # TODO: have TroopShipDesigner give the expected number of troops including species effects troops_per_ship = best_base_trooper_here.troopCapacity if not troops_per_ship: continue this_score, p_troops = evaluate_invasion_planet(pid, empire, secure_ai_fleet_missions, False) best_ship, col_design, build_choices = ProductionAI.getBestShipInfo(EnumsAI.AIPriorityType.PRIORITY_PRODUCTION_ORBITAL_INVASION, loc) if not best_ship: continue 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(best_ship, 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)) print "Evaluating potential invasions, PlanetIDs: %s" % evaluated_planet_ids evaluated_planets = assign_invasion_values(evaluated_planet_ids, EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION, fleet_suppliable_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] print if sorted_planets: print "Invadable planets:\n%-6s | %-6s | %-16s | %-16s | Troops" % ('ID', 'Score', 'Name', 'Race') for pid, pscore, ptroops in sorted_planets: planet = universe.getPlanet(pid) if planet: print "%6d | %6d | %16s | %16s | %d" % (pid, pscore, planet.name, planet.speciesName, ptroops) else: print "%6d | %6d | Error: invalid planet ID" % (pid, pscore) else: print "No Invadable planets identified" 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()
def get_invasion_fleets(): invasion_timer.start("gathering initial info") all_invasion_fleet_ids = FleetUtilsAI.get_empire_fleet_ids_by_role(EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION) AIstate.invasionFleetIDs = FleetUtilsAI.extract_fleet_ids_without_mission_types(all_invasion_fleet_ids) # get suppliable planets universe = fo.getUniverse() empire = fo.getEmpire() empire_id = empire.empireID capital_id = PlanetUtilsAI.get_capital() homeworld=None if capital_id: homeworld = universe.getPlanet(capital_id) if homeworld: home_system_id = homeworld.systemID else: home_system_id = -1 fleet_suppliable_system_ids = empire.fleetSupplyableSystemIDs fleet_suppliable_planet_ids = PlanetUtilsAI.get_planets_in__systems_ids(fleet_suppliable_system_ids) prime_invadable_system_ids = set(ColonisationAI.annexable_system_ids) prime_invadable_planet_ids = PlanetUtilsAI.get_planets_in__systems_ids(prime_invadable_system_ids) 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 "Invasion Warning: this empire has no identifiable homeworld, will therefor treat all visible planets as accessible." accessible_system_ids = visible_system_ids # TODO: check if any troop ships still owned, use their system as home system acessible_planet_ids = PlanetUtilsAI.get_planets_in__systems_ids(accessible_system_ids) print "Accessible Systems: ", ", ".join(PlanetUtilsAI.sys_name_ids(accessible_system_ids)) print all_owned_planet_ids = PlanetUtilsAI.get_all_owned_planet_ids(acessible_planet_ids) # need these for unpopulated outposts all_populated_planets = PlanetUtilsAI.get_populated_planet_ids(acessible_planet_ids) # need this for natives print "All Visible and accessible Populated PlanetIDs (including this empire's): ", ", ".join(PlanetUtilsAI.planet_name_ids(all_populated_planets)) print print "Prime Invadable Target Systems: ", ", ".join(PlanetUtilsAI.sys_name_ids(prime_invadable_system_ids)) print empire_owned_planet_ids = PlanetUtilsAI.get_owned_planets_by_empire(universe.planetIDs) invadable_planet_ids = set(prime_invadable_planet_ids).intersection(set(all_owned_planet_ids).union(all_populated_planets) - set(empire_owned_planet_ids)) print "Prime Invadable PlanetIDs: ", ", ".join(PlanetUtilsAI.planet_name_ids(invadable_planet_ids)) print print "Current Invasion Targeted SystemIDs: ", ", ".join(PlanetUtilsAI.sys_name_ids(AIstate.invasionTargetedSystemIDs)) invasion_targeted_planet_ids = get_invasion_targeted_planet_ids(universe.planetIDs, EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION) invasion_targeted_planet_ids.extend(get_invasion_targeted_planet_ids(universe.planetIDs, EnumsAI.AIFleetMissionType.FLEET_MISSION_ORBITAL_INVASION)) all_invasion_targeted_system_ids = set(PlanetUtilsAI.get_systems(invasion_targeted_planet_ids)) print "Current Invasion Targeted PlanetIDs: ", ", ".join(PlanetUtilsAI.planet_name_ids(invasion_targeted_planet_ids)) invasion_fleet_ids = FleetUtilsAI.get_empire_fleet_ids_by_role(EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION) if not invasion_fleet_ids: print "Available Invasion Fleets: 0" else: print "Invasion FleetIDs: %s" % FleetUtilsAI.get_empire_fleet_ids_by_role(EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION) num_invasion_fleets = len(FleetUtilsAI.extract_fleet_ids_without_mission_types(invasion_fleet_ids)) 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 ColonisationAI.empire_species_systems.get(sys_id, {}).get('pids', []): 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([EnumsAI.AIFleetMissionType.FLEET_MISSION_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] this_score, p_troops = evaluate_invasion_planet(pid, empire, secure_ai_fleet_missions, False) best_ship, col_design, build_choices = ProductionAI.getBestShipInfo(EnumsAI.AIPriorityType.PRIORITY_PRODUCTION_ORBITAL_INVASION, loc) if not best_ship: continue n_bases = math.ceil((p_troops+1) / 2) # TODO: reconsider this +1 safety factor retval = fo.issueEnqueueShipProductionOrder(best_ship, 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)) print "Evaluating potential invasions, PlanetIDs: %s" % evaluated_planet_ids evaluated_planets = assign_invasion_values(evaluated_planet_ids, EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION, fleet_suppliable_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] print if sorted_planets: print "Invadable planets:\n%-6s | %-6s | %-16s | %-16s | Troops" % ('ID', 'Score', 'Name', 'Race') for pid, pscore, ptroops in sorted_planets: planet = universe.getPlanet(pid) if planet: print "%6d | %6d | %16s | %16s | %d" % (pid, pscore, planet.name, planet.speciesName, ptroops) else: print "%6d | %6d | Error: invalid planet ID" % (pid, pscore) else: print "No Invadable planets identified" 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()
def set_planet_resource_foci(): """set resource focus of planets """ newFoci = {} print "\n============================" print "Collecting info to assess Planet Focus Changes\n" universe = fo.getUniverse() empire = fo.getEmpire() currentTurn = fo.currentTurn() # set the random seed (based on galaxy seed, empire ID and current turn) # for game-reload consistency freq = min(3, (max(5, currentTurn - 80)) / 4.0) ** (1.0 / 3) if not (limitAssessments and (abs(currentTurn - lastFociCheck[0]) < 1.5 * freq) and (random.random() < 1.0 / freq)): lastFociCheck[0] = currentTurn resource_timer.start("getPlanets") empirePlanetIDs = list(PlanetUtilsAI.get_owned_planets_by_empire(universe.planetIDs)) resource_timer.start("Filter") resource_timer.start("Priority") # TODO: take into acct splintering of resource groups # fleetSupplyableSystemIDs = empire.fleetSupplyableSystemIDs # fleetSupplyablePlanetIDs = PlanetUtilsAI.get_planets_in__systems_ids(fleetSupplyableSystemIDs) ppPrio = foAI.foAIstate.get_priority(AIPriorityType.PRIORITY_RESOURCE_PRODUCTION) rpPrio = foAI.foAIstate.get_priority(AIPriorityType.PRIORITY_RESOURCE_RESEARCH) priorityRatio = float(rpPrio) / (ppPrio + 0.0001) resource_timer.start("Shuffle") # not supporting Growth for general planets until also adding code to make sure would actually benefit # shuffle(generalPlanetIDs) resource_timer.start("Targets") planets = map(universe.getPlanet, empirePlanetIDs) planetMap.clear() planetMap.update(zip(empirePlanetIDs, planets)) if useGrowth: for metab, metabIncPop in ColonisationAI.empire_metabolisms.items(): for special in [aspec for aspec in AIDependencies.metabolismBoostMap.get(metab, []) if aspec in ColonisationAI.available_growth_specials]: rankedPlanets = [] for pid in ColonisationAI.available_growth_specials[special]: planet = planetMap[pid] cur_focus = planet.focus pop = planet.currentMeterValue(fo.meterType.population) if (pop > metabIncPop - 2 * planet.size) or (GFocus not in planet.availableFoci): # not enough benefit to lose local production, or can't put growth focus here continue for special2 in ["COMPUTRONIUM_SPECIAL"]: if special2 in planet.specials: break else: # didn't have any specials that would override interest in growth special print "Considering Growth Focus for %s (%d) with special %s; planet has pop %.1f and %s metabolism incremental pop is %.1f" % ( planet.name, pid, special, pop, metab, metabIncPop) if cur_focus == GFocus: pop -= 4 # discourage changing current focus to minimize focus-changing penalties rankedPlanets.append((pop, pid, cur_focus)) if not rankedPlanets: continue rankedPlanets.sort() print "Considering Growth Focus choice for special %s; possible planet pop, id pairs are %s" % (metab, rankedPlanets) for spSize, spPID, cur_focus in rankedPlanets: # index 0 should be able to set focus, but just in case... result = 1 if cur_focus != GFocus: result = fo.issueChangeFocusOrder(spPID, GFocus) if result == 1: newFoci[spPID] = GFocus if spPID in empirePlanetIDs: del empirePlanetIDs[empirePlanetIDs.index(spPID)] print "%s focus of planet %s (%d) at Growth Focus" % (["set", "left"][cur_focus == GFocus], planetMap[spPID].name, spPID) break else: print "failed setting focus of planet %s (%d) at Growth Focus; focus left at %s" % (planetMap[spPID].name, spPID, planetMap[spPID].focus) already_have_comp_moon = False for pid in empirePlanetIDs: planet = planetMap[pid] if "COMPUTRONIUM_SPECIAL" in planet.specials and RFocus in planet.availableFoci and not already_have_comp_moon: curFocus = planet.focus newFoci[pid] = RFocus result = 0 if curFocus != RFocus: result = fo.issueChangeFocusOrder(pid, RFocus) if result == 1: universe.updateMeterEstimates(empirePlanetIDs) if curFocus == RFocus or result == 1: already_have_comp_moon = True print "%s focus of planet %s (%d) (with Computronium Moon) at Research Focus" % (["set", "left"][curFocus == RFocus], planetMap[pid].name, pid) if pid in empirePlanetIDs: del empirePlanetIDs[empirePlanetIDs.index(pid)] continue if ((([bld.buildingTypeName for bld in map(universe.getObject, planet.buildingIDs) if bld.buildingTypeName in ["BLD_CONC_CAMP", "BLD_CONC_CAMP_REMNANT"]] != []) or ([ccspec for ccspec in planet.specials if ccspec in ["CONC_CAMP_MASTER_SPECIAL", "CONC_CAMP_SLAVE_SPECIAL"]] != [])) and IFocus in planet.availableFoci): curFocus = planet.focus newFoci[pid] = IFocus result = 0 if curFocus != IFocus: result = fo.issueChangeFocusOrder(pid, IFocus) if result == 1: print ("Tried setting %s for Concentration Camp planet %s (%d) with species %s and current focus %s, got result %d and focus %s" % (newFoci[pid], planet.name, pid, planet.speciesName, curFocus, result, planetMap[pid].focus)) universe.updateMeterEstimates(empirePlanetIDs) if (result != 1) or planetMap[pid].focus != IFocus: newplanet = universe.getPlanet(pid) print ("Error: Failed setting %s for Concentration Camp planet %s (%d) with species %s and current focus %s, but new planet copy shows %s" % (newFoci[pid], planetMap[pid].name, pid, planetMap[pid].speciesName, planetMap[pid].focus, newplanet.focus)) if curFocus == IFocus or result == 1: print "%s focus of planet %s (%d) (with Concentration Camps/Remnants) at Industry Focus" % (["set", "left"][curFocus == IFocus], planetMap[pid].name, pid) if pid in empirePlanetIDs: del empirePlanetIDs[empirePlanetIDs.index(pid)] continue # pp, rp = get_resource_target_totals(empirePlanetIDs, planetMap) pp, rp = get_resource_target_totals(planetMap.keys()) for pid in empirePlanetIDs: planet = planetMap[pid] if PFocus in planet.availableFoci and assess_protection_focus(pid): curFocus = planet.focus newFoci[pid] = PFocus result = 0 if curFocus != PFocus: result = fo.issueChangeFocusOrder(pid, PFocus) if result == 1: print ("Tried setting %s for planet %s (%d) with species %s and current focus %s, got result %d and focus %s" % (newFoci[pid], planet.name, pid, planet.speciesName, curFocus, result, planet.focus)) universe.updateMeterEstimates(empirePlanetIDs) if (result != 1) or planet.focus != PFocus: newplanet = universe.getPlanet(pid) print ("Error: Failed setting %s for planet %s (%d) with species %s and current focus %s, but new planet copy shows %s" % (newFoci[pid], planet.name, pid, planet.speciesName, planet.focus, newplanet.focus)) if curFocus == PFocus or result == 1: print "%s focus of planet %s (%d) at Protection(Defense) Focus" % (["set", "left"][curFocus == PFocus], planet.name, pid) if pid in empirePlanetIDs: del empirePlanetIDs[empirePlanetIDs.index(pid)] continue print "\n-----------------------------------------" print "Making Planet Focus Change Determinations\n" ratios = [] # for each planet, calculate RP:PP value ratio at which industry/Mining focus and research focus would have the same total value, & sort by that # include a bias to slightly discourage changing foci curTargetPP = 0.001 curTargetRP = 0.001 resource_timer.start("Loop") # loop has_force = tech_is_complete("CON_FRC_ENRG_STRC") preset_ids = set(planetMap.keys()) - set(empirePlanetIDs) ctPP0, ctRP0 = 0, 0 for pid in preset_ids: nPP, nRP = newTargets.get(pid, {}).get(planetMap[pid].focus, [0, 0]) curTargetPP += nPP curTargetRP += nRP iPP, iRP = newTargets.get(pid, {}).get(IFocus, [0, 0]) ctPP0 += iPP ctRP0 += iRP id_set = set(empirePlanetIDs) for adj_round in [1, 2, 3, 4]: maxi_ratio = ctRP0 / max(0.01, ctPP0) # should only change between rounds 1 and 2 for pid in list(id_set): if adj_round == 1: # tally max Industry iPP, iRP = newTargets.get(pid, {}).get(IFocus, [0, 0]) ctPP0 += iPP ctRP0 += iRP continue II, IR = newTargets[pid][IFocus] RI, RR = newTargets[pid][RFocus] CI, CR = currentOutput[pid][IFocus], currentOutput[pid][RFocus] research_penalty = (currentFocus[pid] != RFocus) # calculate factor F at which II + F * IR == RI + F * RR =====> F = ( II-RI ) / (RR-IR) thisFactor = (II - RI) / max(0.01, RR - IR) # don't let denominator be zero for planets where focus doesn't change RP planet = planetMap[pid] if adj_round == 2: # take research at planets with very cheap research if (maxi_ratio < priorityRatio) and (curTargetRP < priorityRatio * ctPP0) and (thisFactor <= 1.0): curTargetPP += RI curTargetRP += RR newFoci[pid] = RFocus id_set.discard(pid) continue if adj_round == 3: # take research at planets where can do reasonable balance if has_force or (foAI.foAIstate.aggression < fo.aggression.aggressive) or (curTargetRP >= priorityRatio * ctPP0): continue pop = planet.currentMeterValue(fo.meterType.population) t_pop = planet.currentMeterValue(fo.meterType.targetPopulation) # if AI is aggressive+, and this planet in range where temporary Research focus can get an additional RP at cost of 1 PP, and still need some RP, then do it if pop < t_pop - 5: continue if (CI > II + 8) or (((RR > II) or ((RR - CR) >= 1 + 2 * research_penalty)) and ((RR - IR) >= 3) and ((CR - IR) >= 0.7 * ((II - CI) * (1 + 0.1 * research_penalty)))): curTargetPP += CI - 1 - research_penalty curTargetRP += CR + 1 newFoci[pid] = RFocus id_set.discard(pid) continue # adj_round == 4 assume default IFocus curTargetPP += II # icurTargets initially calculated by Industry focus, which will be our default focus curTargetRP += IR newFoci[pid] = IFocus ratios.append((thisFactor, pid)) ratios.sort() printedHeader = False fociMap = {IFocus: "Industry", RFocus: "Research", MFocus: "Mining", GFocus: "Growth", PFocus: "Defense"} gotAlgo = tech_is_complete("LRN_ALGO_ELEGANCE") for ratio, pid in ratios: do_research = False # (newFoci[pid]==RFocus) if (priorityRatio < (curTargetRP / (curTargetPP + 0.0001))) and not do_research: # we have enough RP if ratio < 1.1 and foAI.foAIstate.aggression > fo.aggression.cautious: # but wait, RP is still super cheap relative to PP, maybe will take more RP if priorityRatio < 1.5 * (curTargetRP / (curTargetPP + 0.0001)): # yeah, really a glut of RP, stop taking RP break else: # RP not super cheap & we have enough, stop taking it break II, IR = newTargets[pid][IFocus] RI, RR = newTargets[pid][RFocus] # if currentFocus[pid] == MFocus: # II = max( II, newTargets[pid][MFocus][0] ) if do_research or (gotAlgo and ( (ratio > 2.0 and curTargetPP < 15) or (ratio > 2.5 and curTargetPP < 25 and II > 5) or (ratio > 3.0 and curTargetPP < 40 and II > 5) or (ratio > 4.0 and curTargetPP < 100 and II > 10) or ((curTargetRP + RR - IR) / max(0.001, curTargetPP - II + RI) > 2 * priorityRatio))): # we already have algo elegance and more RP would be too expensive, or overkill if not printedHeader: printedHeader = True print "Rejecting further Research Focus choices as too expensive:" print "%34s|%20s|%15s |%15s|%15s |%15s |%15s" % (" Planet ", " current RP/PP ", " current target RP/PP ", "current Focus ", " rejectedFocus ", " rejected target RP/PP ", "rejected RP-PP EQF") oldFocus = currentFocus[pid] cPP, cRP = currentOutput[pid][IFocus], currentOutput[pid][RFocus] otPP, otRP = newTargets[pid].get(oldFocus, (0, 0)) ntPP, ntRP = newTargets[pid].get(RFocus, (0, 0)) print "pID (%3d) %22s | c: %5.1f / %5.1f | cT: %5.1f / %5.1f | cF: %8s | nF: %8s | cT: %5.1f / %5.1f | %.2f" % (pid, planetMap[pid].name, cRP, cPP, otRP, otPP, fociMap.get(oldFocus, 'unknown'), fociMap[RFocus], ntRP, ntPP, ratio) continue # RP is getting too expensive, but might be willing to still allocate from a planet with less PP to lose # if planetMap[pid].currentMeterValue(fo.meterType.targetPopulation) >0: #only set to research if pop won't die out newFoci[pid] = RFocus curTargetRP += (RR - IR) curTargetPP -= (II - RI) print "============================" print "Planet Focus Assignments to achieve target RP/PP ratio of %.2f from current ratio of %.2f ( %.1f / %.1f )" % (priorityRatio, rp / (pp + 0.0001), rp, pp) print "Max Industry assignments would result in target RP/PP ratio of %.2f ( %.1f / %.1f )" % (ctRP0 / (ctPP0 + 0.0001), ctRP0, ctPP0) print "-------------------------------------" print "%34s|%20s|%15s |%15s|%15s |%15s " % (" Planet ", " current RP/PP ", " current target RP/PP ", "current Focus ", " newFocus ", " new target RP/PP ") totalChanged = 0 for id_set in empirePlanetIDs, preset_ids: for pid in id_set: canFocus = planetMap[pid].currentMeterValue(fo.meterType.targetPopulation) > 0 oldFocus = currentFocus[pid] newFocus = newFoci.get(pid, IFocus) cPP, cRP = currentOutput[pid][IFocus], currentOutput[pid][RFocus] otPP, otRP = newTargets[pid].get(oldFocus, (0, 0)) ntPP, ntRP = otPP, otRP if newFocus != oldFocus and newFocus in planetMap[pid].availableFoci: # planetMap[pid].focus totalChanged += 1 if newFocus != planetMap[pid].focus: result = fo.issueChangeFocusOrder(pid, newFocus) if result == 1: ntPP, ntRP = newTargets[pid].get(newFocus, (0, 0)) else: print "Trouble changing focus of planet %s (%d) to %s" % (planetMap[pid].name, pid, newFocus) print "pID (%3d) %22s | c: %5.1f / %5.1f | cT: %5.1f / %5.1f | cF: %8s | nF: %8s | cT: %5.1f / %5.1f " % (pid, planetMap[pid].name, cRP, cPP, otRP, otPP, fociMap.get(oldFocus, 'unknown'), fociMap[newFocus], ntRP, ntPP) print "-------------------------------------" print "-------------------------------------" print "Final Ratio Target (turn %4d) RP/PP : %.2f ( %.1f / %.1f ) after %d Focus changes" % (fo.currentTurn(), curTargetRP / (curTargetPP + 0.0001), curTargetRP, curTargetPP, totalChanged) resource_timer.end() aPP, aRP = empire.productionPoints, empire.resourceProduction(fo.resourceType.research) # Next string used in charts. Don't modify it! print "Current Output (turn %4d) RP/PP : %.2f ( %.1f / %.1f )" % (fo.currentTurn(), aRP / (aPP + 0.0001), aRP, aPP) print "------------------------" print "ResourcesAI Time Requirements:"
def get_invasion_fleets(): """get invasion fleets""" invasion_timer.start("gathering initial info") all_invasion_fleet_ids = FleetUtilsAI.get_empire_fleet_ids_by_role(EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION) AIstate.invasionFleetIDs = FleetUtilsAI.extract_fleet_ids_without_mission_types(all_invasion_fleet_ids) # get supplyable planets universe = fo.getUniverse() empire = fo.getEmpire() empire_id = empire.empireID capital_id = PlanetUtilsAI.get_capital() homeworld=None if capital_id: homeworld = universe.getPlanet(capital_id) if homeworld: home_system_id = homeworld.systemID else: home_system_id = -1 fleet_supplyable_system_ids = empire.fleetSupplyableSystemIDs fleet_supplyable_planet_ids = PlanetUtilsAI.get_planets_in__systems_ids(fleet_supplyable_system_ids) prime_invadable_system_ids = set(ColonisationAI.annexableSystemIDs) prime_invadable_planet_ids = PlanetUtilsAI.get_planets_in__systems_ids(prime_invadable_system_ids) 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 "Invasion Warning: this empire has no identifiable homeworld, will therefor treat all visible planets as accessible." accessible_system_ids = visible_system_ids #TODO: check if any troop ships still owned, use their system as home system acessible_planet_ids = PlanetUtilsAI.get_planets_in__systems_ids(accessible_system_ids) print "Accessible Systems: ", ", ".join(PlanetUtilsAI.sys_name_ids(accessible_system_ids)) print #all_owned_planet_ids = PlanetUtilsAI.get_all_owned_planet_ids(exploredPlanetIDs) all_owned_planet_ids = PlanetUtilsAI.get_all_owned_planet_ids(acessible_planet_ids)#need these for unpopulated outposts # print "All Owned and Populated PlanetIDs: " + str(all_owned_planet_ids) all_populated_planets = PlanetUtilsAI.get_populated_planet_ids(acessible_planet_ids)#need this for natives print "All Visible and accessible Populated PlanetIDs (including this empire's): ", ", ".join(PlanetUtilsAI.planet_name_ids(all_populated_planets )) print print "Prime Invadable Target Systems: ", ", ".join(PlanetUtilsAI.sys_name_ids(prime_invadable_system_ids)) print empire_owned_planet_ids = PlanetUtilsAI.get_owned_planets_by_empire(universe.planetIDs) # print "Empire Owned PlanetIDs: " + str(empire_owned_planet_ids) invadable_planet_ids = set(prime_invadable_planet_ids).intersection(set(all_owned_planet_ids).union(all_populated_planets ) - set(empire_owned_planet_ids)) print "Prime Invadable PlanetIDs: ", ", ".join(PlanetUtilsAI.planet_name_ids(invadable_planet_ids)) print print "Current Invasion Targeted SystemIDs: ", ", ".join(PlanetUtilsAI.sys_name_ids(AIstate.invasionTargetedSystemIDs)) invasion_targeted_planet_ids = get_invasion_targeted_planet_ids(universe.planetIDs, EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION, empire_id) invasion_targeted_planet_ids.extend( get_invasion_targeted_planet_ids(universe.planetIDs, EnumsAI.AIFleetMissionType.FLEET_MISSION_ORBITAL_INVASION, empire_id)) all_invasion_targeted_system_ids = set(PlanetUtilsAI.get_systems(invasion_targeted_planet_ids)) print "Current Invasion Targeted PlanetIDs: ", ", ".join(PlanetUtilsAI.planet_name_ids(invasion_targeted_planet_ids)) invasion_fleet_ids = FleetUtilsAI.get_empire_fleet_ids_by_role(EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION) if not invasion_fleet_ids: print "Available Invasion Fleets: 0" else: print "Invasion FleetIDs: " + str(FleetUtilsAI.get_empire_fleet_ids_by_role(EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION)) num_invasion_fleets = len(FleetUtilsAI.extract_fleet_ids_without_mission_types(invasion_fleet_ids)) print "Invasion Fleets Without Missions: " + str(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 if len (invadable_planet_ids) > 0: #print "Evaluating Troop Bases (SpaceInvaders) for %s"%(invadable_planet_ids) pass for pid in invadable_planet_ids: #TODO: reorganize planet = universe.getPlanet(pid) if not planet: continue sys_id = planet.systemID sys_partial_vis_turn = dict_from_map(universe.getVisibilityTurnsMap(planet.systemID, empire_id)).get(fo.visibility.partial, -9999) planet_partial_vis_turn = dict_from_map(universe.getVisibilityTurnsMap(pid, empire_id)).get(fo.visibility.partial, -9999) if planet_partial_vis_turn < sys_partial_vis_turn: #print "rejecting %s due to stealth"%planet.name continue for pid2 in ColonisationAI.empireSpeciesSystems.get(sys_id, {}).get('pids', []): if available_pp.get(pid2, 0) < 2: #TODO: improve troop base PP sufficiency determination #print "rejecting %s due to insufficient avail PP"%planet.name break planet2 = universe.getPlanet(pid2) if not planet2: continue if (pid not in foAI.foAIstate.qualifyingTroopBaseTargets) and (planet2.speciesName in ColonisationAI.empireShipBuilders): #print "Adding %s to Troop Bases (SpaceInvaders) potential target list, from %s"%(planet.name, planet2.name) 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] secureAIFleetMissions = foAI.foAIstate.get_fleet_missions_with_any_mission_types([EnumsAI.AIFleetMissionType.FLEET_MISSION_SECURE]) #print "considering possible troop bases at %s" % (foAI.foAIstate.qualifyingTroopBaseTargets.keys()) 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] this_score, p_troops = evaluate_invasion_planet(pid, EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION, fleet_supplyable_planet_ids, empire, secureAIFleetMissions, False) bestShip, colDesign, buildChoices = ProductionAI.getBestShipInfo(EnumsAI.AIPriorityType.PRIORITY_PRODUCTION_ORBITAL_INVASION, loc) if not bestShip: #print "Error: no troop base can be built at ", PlanetUtilsAI.planet_name_ids([loc]) continue #print "selecting ", PlanetUtilsAI.planet_name_ids([loc]), " to build Orbital troop bases" n_bases = math.ceil((p_troops+1) / 2)#TODO: reconsider this +1 safety factor retval = fo.issueEnqueueShipProductionOrder(bestShip, 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)) res=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 evaluatedPlanetIDs = list(set(invadable_planet_ids) - set(invasion_targeted_planet_ids) - set(reserved_troop_base_targets) ) print "Evaluating potential invasions, PlanetIDs: " + str(evaluatedPlanetIDs) evaluatedPlanets = assign_invasion_values(evaluatedPlanetIDs, EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION, fleet_supplyable_planet_ids, empire) sortedPlanets = [(pid, pscore, ptroops) for (pid, (pscore, ptroops)) in evaluatedPlanets.items() ] sortedPlanets.sort(lambda x, y: cmp(x[1], y[1]), reverse=True) sortedPlanets = [(pid, pscore%10000, ptroops) for (pid, pscore, ptroops) in sortedPlanets ] print if sortedPlanets: print "Invadable planets\nIDs, ID | Score | Name | Race | Troops" for pid, pscore, ptroops in sortedPlanets: planet = universe.getPlanet(pid) if planet: print "%6d | %6d | %16s | %16s | %d"%(pid, pscore, planet.name, planet.speciesName, ptroops) else: print "%6d | %6d | Error: invalid planet ID"%(pid, pscore) else: print "No Invadable planets identified" sortedPlanets = [(pid, pscore, ptroops) for (pid, pscore, ptroops) in sortedPlanets if pscore > 0] # export opponent planets for other AI modules AIstate.opponentPlanetIDs = [pid for pid, pscore, trp in sortedPlanets] AIstate.invasionTargets = sortedPlanets # 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(evaluatedPlanetIDs))) invasion_timer.end()
def get_military_fleets(mil_fleets_ids=None, try_reset=True, thisround="Main"): """Get armed military fleets.""" global _military_allocations universe = fo.getUniverse() empire_id = fo.empireID() home_system_id = PlanetUtilsAI.get_capital_sys_id() all_military_fleet_ids = (mil_fleets_ids if mil_fleets_ids is not None else FleetUtilsAI.get_empire_fleet_ids_by_role(MissionType.MILITARY)) if try_reset and (fo.currentTurn() + empire_id) % 30 == 0 and thisround == "Main": try_again(all_military_fleet_ids, try_reset=False, thisround=thisround + " Reset") return mil_fleets_ids = list(FleetUtilsAI.extract_fleet_ids_without_mission_types(all_military_fleet_ids)) mil_needing_repair_ids, mil_fleets_ids = avail_mil_needing_repair(mil_fleets_ids, split_ships=True) avail_mil_rating = sum(map(CombatRatingsAI.get_fleet_rating, mil_fleets_ids)) if not mil_fleets_ids: if "Main" in thisround: _military_allocations = [] return [] # for each system, get total rating of fleets assigned to it already_assigned_rating = {} systems_status = foAI.foAIstate.systemStatus enemy_sup_factor = {} # enemy supply for sys_id in universe.systemIDs: already_assigned_rating[sys_id] = 0 enemy_sup_factor[sys_id] = min(2, len(systems_status.get(sys_id, {}).get('enemies_nearly_supplied', []))) for fleet_id in [fid for fid in all_military_fleet_ids if fid not in mil_fleets_ids]: ai_fleet_mission = foAI.foAIstate.get_fleet_mission(fleet_id) if not ai_fleet_mission.target: # shouldn't really be possible continue last_sys = ai_fleet_mission.target.get_system().id # will count this fleet as assigned to last system in target list # TODO last_sys or target sys? this_rating = CombatRatingsAI.get_fleet_rating(fleet_id) already_assigned_rating[last_sys] = CombatRatingsAI.combine_ratings(already_assigned_rating.get(last_sys, 0), this_rating) for sys_id in universe.systemIDs: my_defense_rating = systems_status.get(sys_id, {}).get('mydefenses', {}).get('overall', 0) already_assigned_rating[sys_id] = CombatRatingsAI.combine_ratings(my_defense_rating, already_assigned_rating[sys_id]) if _verbose_mil_reporting and already_assigned_rating[sys_id]: print "\t System %s already assigned rating %.1f" % ( universe.getSystem(sys_id), already_assigned_rating[sys_id]) # get systems to defend capital_id = PlanetUtilsAI.get_capital() if capital_id is not None: capital_planet = universe.getPlanet(capital_id) else: capital_planet = None # TODO: if no owned planets try to capture one! if capital_planet: capital_sys_id = capital_planet.systemID else: # should be rare, but so as to not break code below, pick a randomish mil-centroid system capital_sys_id = None # unless we can find one to use system_dict = {} for fleet_id in all_military_fleet_ids: status = foAI.foAIstate.fleetStatus.get(fleet_id, None) if status is not None: sys_id = status['sysID'] if not list(universe.getSystem(sys_id).planetIDs): continue system_dict[sys_id] = system_dict.get(sys_id, 0) + status.get('rating', 0) ranked_systems = sorted([(val, sys_id) for sys_id, val in system_dict.items()]) if ranked_systems: capital_sys_id = ranked_systems[-1][-1] else: try: capital_sys_id = foAI.foAIstate.fleetStatus.items()[0][1]['sysID'] except: pass num_targets = max(10, PriorityAI.allotted_outpost_targets) top_target_planets = ([pid for pid, pscore, trp in AIstate.invasionTargets[:PriorityAI.allottedInvasionTargets] if pscore > 20] + [pid for pid, (pscore, spec) in foAI.foAIstate.colonisableOutpostIDs.items()[:num_targets] if pscore > 20] + [pid for pid, (pscore, spec) in foAI.foAIstate.colonisablePlanetIDs.items()[:num_targets] if pscore > 20]) top_target_planets.extend(foAI.foAIstate.qualifyingTroopBaseTargets.keys()) base_col_target_systems = PlanetUtilsAI.get_systems(top_target_planets) top_target_systems = [] for sys_id in AIstate.invasionTargetedSystemIDs + base_col_target_systems: if sys_id not in top_target_systems: if foAI.foAIstate.systemStatus[sys_id]['totalThreat'] > get_tot_mil_rating(): continue top_target_systems.append(sys_id) # doing this rather than set, to preserve order try: # capital defense allocation_helper = AllocationHelper(already_assigned_rating, avail_mil_rating, try_reset) if capital_sys_id is not None: CapitalDefenseAllocator(capital_sys_id, allocation_helper).allocate() # defend other planets empire_planet_ids = PlanetUtilsAI.get_owned_planets_by_empire(universe.planetIDs) empire_occupied_system_ids = list(set(PlanetUtilsAI.get_systems(empire_planet_ids)) - {capital_sys_id}) for sys_id in empire_occupied_system_ids: PlanetDefenseAllocator(sys_id, allocation_helper).allocate() # attack / protect high priority targets for sys_id in top_target_systems: TopTargetAllocator(sys_id, allocation_helper).allocate() # enemy planets other_targeted_system_ids = [sys_id for sys_id in set(PlanetUtilsAI.get_systems(AIstate.opponentPlanetIDs)) if sys_id not in top_target_systems] for sys_id in other_targeted_system_ids: TargetAllocator(sys_id, allocation_helper).allocate() # colony / outpost targets other_targeted_system_ids = [sys_id for sys_id in list(set(AIstate.colonyTargetedSystemIDs + AIstate.outpostTargetedSystemIDs)) if sys_id not in top_target_systems] for sys_id in other_targeted_system_ids: OutpostTargetAllocator(sys_id, allocation_helper).allocate() # TODO blockade enemy systems # interior systems targetable_ids = set(ColonisationAI.systems_by_supply_tier.get(0, []) + ColonisationAI.systems_by_supply_tier.get(1, [])) current_mil_systems = [sid for sid, _, _, _ in allocation_helper.allocations] interior_targets1 = targetable_ids.difference(current_mil_systems) interior_targets = [sid for sid in interior_targets1 if ( allocation_helper.threat_bias + systems_status.get(sid, {}).get('totalThreat', 0) > 0.8 * allocation_helper.already_assigned_rating[sid])] for sys_id in interior_targets: InteriorTargetsAllocator(sys_id, allocation_helper).allocate() # TODO Exploration targets # border protections visible_system_ids = foAI.foAIstate.visInteriorSystemIDs.keys() + foAI.foAIstate.visBorderSystemIDs.keys() accessible_system_ids = [sys_id for sys_id in visible_system_ids if universe.systemsConnected(sys_id, home_system_id, empire_id)] current_mil_systems = [sid for sid, alloc, take_any, _ in allocation_helper.allocations if alloc > 0] border_targets1 = [sid for sid in accessible_system_ids if sid not in current_mil_systems] border_targets = [sid for sid in border_targets1 if ( allocation_helper.threat_bias + systems_status.get(sid, {}).get('fleetThreat', 0) + systems_status.get(sid, {}).get( 'planetThreat', 0) > 0.8 * allocation_helper.already_assigned_rating[sid])] for sys_id in border_targets: BorderSecurityAllocator(sys_id, allocation_helper).allocate() except ReleaseMilitaryException: try_again(all_military_fleet_ids) return allocation_groups = allocation_helper.allocation_by_groups allocations = allocation_helper.allocations new_allocations = [] remaining_mil_rating = avail_mil_rating # for top categories assign max_alloc right away as available for cat in ['capitol', 'occupied', 'topTargets']: for sid, alloc, take_any, max_alloc in allocation_groups.get(cat, []): if remaining_mil_rating <= 0: break this_alloc = min(remaining_mil_rating, max_alloc) new_allocations.append((sid, this_alloc, alloc, take_any)) remaining_mil_rating -= this_alloc base_allocs = set() # for lower priority categories, first assign base_alloc around to all, then top up as available for cat in ['otherTargets', 'accessibleTargets', 'exploreTargets']: for sid, alloc, take_any, max_alloc in allocation_groups.get(cat, []): if remaining_mil_rating <= 0: break base_allocs.add(sid) remaining_mil_rating -= alloc for cat in ['otherTargets', 'accessibleTargets', 'exploreTargets']: for sid, alloc, take_any, max_alloc in allocation_groups.get(cat, []): if sid not in base_allocs: break if remaining_mil_rating <= 0: new_allocations.append((sid, alloc, alloc, take_any)) else: new_rating = min(remaining_mil_rating + alloc, max_alloc) new_allocations.append((sid, new_rating, alloc, take_any)) remaining_mil_rating -= (new_rating - alloc) if "Main" in thisround: _military_allocations = new_allocations _min_mil_allocations.clear() _min_mil_allocations.update([(sid, alloc) for sid, alloc, take_any, _ in allocations]) if _verbose_mil_reporting or "Main" in thisround: print "------------------------------\nFinal %s Round Military Allocations: %s \n-----------------------" % (thisround, dict([(sid, alloc) for sid, alloc, minalloc, take_any in new_allocations])) print "(Apparently) remaining military rating: %.1f" % remaining_mil_rating # export military systems for other AI modules if "Main" in thisround: AIstate.militarySystemIDs = list(set([sid for sid, alloc, minalloc, take_any in new_allocations]).union( [sid for sid in allocation_helper.already_assigned_rating if allocation_helper.already_assigned_rating[sid] > 0])) else: AIstate.militarySystemIDs = list(set([sid for sid, alloc, minalloc, take_any in new_allocations]).union(AIstate.militarySystemIDs)) return new_allocations
def get_military_fleets(milFleetIDs=None, tryReset=True, thisround="Main"): """get armed military fleets""" global MilitaryAllocations, totMilRating, num_milships universe = fo.getUniverse() empire = fo.getEmpire() empireID = empire.empireID capitalID = PlanetUtilsAI.get_capital() if capitalID is None: homeworld=None else: homeworld = universe.getPlanet(capitalID) if homeworld: homeSystemID = homeworld.systemID else: homeSystemID=-1 if milFleetIDs is not None: allMilitaryFleetIDs = milFleetIDs else: allMilitaryFleetIDs = FleetUtilsAI.get_empire_fleet_ids_by_role(AIFleetMissionType.FLEET_MISSION_MILITARY ) if tryReset and ((fo.currentTurn()+empireID) % 30 ==0) and thisround=="Main": try_again(allMilitaryFleetIDs, try_reset=False, thisround = thisround+" Reset") num_milships = 0 for fid in allMilitaryFleetIDs: num_milships += foAI.foAIstate.fleetStatus.get(fid, {}).get('nships', 0) thisTotMilRating = sum( map(lambda x: foAI.foAIstate.get_rating(x).get('overall', 0), allMilitaryFleetIDs ) ) if "Main" in thisround: totMilRating = thisTotMilRating print "==================================================" print "%s Round Total Military Rating: %d"%(thisround, totMilRating) print "---------------------------------" foAI.foAIstate.militaryRating=totMilRating milFleetIDs = list( FleetUtilsAI.extract_fleet_ids_without_mission_types(allMilitaryFleetIDs)) mil_needing_repair_ids, milFleetIDs = avail_mil_needing_repair(milFleetIDs, split_ships=True) availMilRating = sum( map(lambda x: foAI.foAIstate.get_rating(x).get('overall', 0), milFleetIDs ) ) if "Main" in thisround: print "==================================================" print "%s Round Available Military Rating: %d"%(thisround, availMilRating) print "---------------------------------" remainingMilRating = availMilRating allocations = [] allocationGroups={} if not milFleetIDs: if "Main" in thisround: MilitaryAllocations = [] return [] #for each system, get total rating of fleets assigned to it alreadyAssignedRating={} assignedAttack={} assignedHP={} for sysID in universe.systemIDs: assignedAttack[sysID]=0 assignedHP[sysID]=0 for fleetID in [fid for fid in allMilitaryFleetIDs if fid not in milFleetIDs]: aiFleetMission = foAI.foAIstate.get_fleet_mission(fleetID) sysTargets= [] for aiFleetMissionType in aiFleetMission.get_mission_types(): aiTargets = aiFleetMission.get_targets(aiFleetMissionType) for aiTarget in aiTargets: sysTargets.extend(aiTarget.get_required_system_ai_targets()) if not sysTargets: #shouldn't really be possible continue lastSys = sysTargets[-1].target_id # will count this fleet as assigned to last system in target list assignedAttack[lastSys] += foAI.foAIstate.get_rating(fleetID).get('attack', 0) assignedHP[lastSys] += foAI.foAIstate.get_rating(fleetID).get('health', 0) for sysID in universe.systemIDs: mydefenses = foAI.foAIstate.systemStatus.get(sysID, {}).get( 'mydefenses', {} ) mypattack = mydefenses.get('attack', 0) myphealth = mydefenses.get('health', 0) alreadyAssignedRating[sysID] = ( assignedAttack[sysID] + mypattack ) * ( assignedHP[sysID] + myphealth ) # get systems to defend capitalID = PlanetUtilsAI.get_capital() if capitalID is not None: capitalPlanet = universe.getPlanet(capitalID) else: capitalPlanet=None #TODO: if no owned planets try to capture one! if capitalPlanet: capitalSysID = capitalPlanet.systemID else: # should be rare, but so as to not break code below, pick a randomish mil-centroid system capitalSysID=None #unless we can find one to use systemDict = {} for fleetID in allMilitaryFleetIDs: status = foAI.foAIstate.fleetStatus.get(fleetID, None) if status is not None: sysID = status['sysID'] if len( list( universe.getSystem(sysID).planetIDs ) ) ==0: continue systemDict[sysID] = systemDict.get( sysID, 0) + status.get('rating', {}).get('overall', 0) rankedSystems = sorted( [(val, sysID) for sysID, val in systemDict.items() ] ) if rankedSystems: capitalSysID = rankedSystems[-1][-1] else: try: capitalSysID = foAI.foAIstate.fleetStatus.items()[0][1]['sysID'] except: pass if False: if fo.currentTurn() < 20: threatBias = 0 elif fo.currentTurn() < 40: threatBias = 10 elif fo.currentTurn() < 60: threatBias = 80 elif fo.currentTurn() < 80: threatBias = 200 else: threatBias = 400 else: threatBias = 0 safetyFactor = [ 4.0, 3.0, 2.0, 1.5, 1.2, 1.0 ][foAI.foAIstate.aggression] topTargetPlanets = [pid for pid, pscore, trp in AIstate.invasionTargets[:PriorityAI.allottedInvasionTargets] if pscore > 20] + [pid for pid, pscore in foAI.foAIstate.colonisablePlanetIDs[:10] if pscore > 20] topTargetPlanets.extend( foAI.foAIstate.qualifyingTroopBaseTargets.keys() ) topTargetSystems = [] for sysID in AIstate.invasionTargetedSystemIDs + PlanetUtilsAI.get_systems( topTargetPlanets ): if sysID not in topTargetSystems: topTargetSystems.append(sysID) #doing this rather than set, to preserve order # allocation format: ( sysID, newAllocation, takeAny, maxMultiplier ) #================================ #--------Capital Threat ---------- capitalThreat = safetyFactor*(2* threatBias +sum( [ foAI.foAIstate.systemStatus[capitalSysID][thrtKey] for thrtKey in ['totalThreat', 'neighborThreat']] )) neededRating = rating_needed(1.4*capitalThreat, alreadyAssignedRating[capitalSysID]) newAlloc=0 if tryReset: if neededRating > 0.5*availMilRating: try_again(allMilitaryFleetIDs) return if neededRating > 0: newAlloc = min(remainingMilRating, neededRating ) allocations.append( ( capitalSysID, newAlloc, True, 1.6*capitalThreat) ) allocationGroups.setdefault('capitol', []).append( ( capitalSysID, newAlloc, True, 2*capitalThreat) ) remainingMilRating -= newAlloc if "Main" in thisround or newAlloc >0: if verboseMilReporting: print "Empire Capital System: (%d) %s -- threat : %d, military allocation: existing: %d ; new: %d"%(capitalSysID, universe.getSystem(capitalSysID).name , capitalThreat, alreadyAssignedRating[capitalSysID], newAlloc) print "-----------------" #================================ #--------Empire Occupied Systems ---------- empirePlanetIDs = PlanetUtilsAI.get_owned_planets_by_empire(universe.planetIDs) empireOccupiedSystemIDs = list(set(PlanetUtilsAI.get_systems(empirePlanetIDs)) - {capitalSysID}) if "Main" in thisround: if verboseMilReporting: print "Empire-Occupied Systems: %s"%( [ "| %d %s |"%(eoSysID, universe.getSystem(eoSysID).name) for eoSysID in empireOccupiedSystemIDs ] ) print "-----------------" newAlloc=0 if len( empireOccupiedSystemIDs ) > 0: ocSysTotThreat = [ ( oSID, threatBias +safetyFactor*sum( [ foAI.foAIstate.systemStatus.get(oSID, {}).get(thrtKey, 0) for thrtKey in ['totalThreat', 'neighborThreat']] )) for oSID in empireOccupiedSystemIDs ] totocSysThreat = sum( [thrt for sid, thrt in ocSysTotThreat] ) totCurAlloc = sum( [alreadyAssignedRating[sid] for sid, thrt in ocSysTotThreat] ) allocationFactor = min( 1.5, remainingMilRating /max(0.01, ( totocSysThreat -totCurAlloc) )) ocSysAlloc = 0 for sid, thrt in ocSysTotThreat: curAlloc=alreadyAssignedRating[sid] neededRating = rating_needed( 1.3*thrt, curAlloc) if (neededRating > 0.8* remainingMilRating) and tryReset: try_again(allMilitaryFleetIDs) return thisAlloc=0 if ( neededRating>0 ) and remainingMilRating > 0: thisAlloc = max(0, min( neededRating, 0.5*availMilRating, remainingMilRating)) newAlloc+=thisAlloc allocations.append( (sid, thisAlloc, True, 1.6*thrt) ) allocationGroups.setdefault('occupied', []).append( (sid, thisAlloc, True, 2*thrt) ) remainingMilRating -= thisAlloc ocSysAlloc += thisAlloc if "Main" in thisround or thisAlloc >0: if verboseMilReporting: print "Provincial Occupied system %4d ( %10s ) has local threat %8d ; existing military allocation %d and new allocation %8d"%(sid, universe.getSystem(sid).name, thrt, curAlloc, thisAlloc) if "Main" in thisround or newAlloc >0: if verboseMilReporting: print "Provincial Empire-Occupied Sytems under total threat: %d -- total mil allocation: existing %d ; new: %d"%(totocSysThreat, totCurAlloc, ocSysAlloc ) print "-----------------" #================================ #--------Top Targeted Systems ---------- #TODO: do native invasions highest priority otherTargetedSystemIDs = topTargetSystems if "Main" in thisround: if verboseMilReporting: print "Top Colony and Invasion Targeted Systems : %s"%( [ "| %d %s |"%(sysID, universe.getSystem(sysID).name) for sysID in otherTargetedSystemIDs ] ) print "-----------------" # for these, calc local threat only, no neighbor threat, but use a multiplier for fleet safety newAlloc=0 if len( otherTargetedSystemIDs ) > 0: otSysAlloc = 0 otSysThreat = [ ( oSID, threatBias +safetyFactor*(foAI.foAIstate.systemStatus.get(oSID, {}).get('totalThreat', 0)+0.5*foAI.foAIstate.systemStatus.get(oSID, {}).get('neightborThreat', 0) ) ) for oSID in otherTargetedSystemIDs ] tototSysThreat = sum( [thrt for sid, thrt in otSysThreat] ) totCurAlloc = sum( [alreadyAssignedRating[sid] for sid, thrt in otSysThreat] ) for sid, thrt in otSysThreat: curAlloc=alreadyAssignedRating[sid] neededRating = rating_needed( 1.4*thrt, curAlloc) thisAlloc=0 #only record more allocation for this invasion if we already started or have enough rating available takeAny= alreadyAssignedRating[sid] > 0 if ( neededRating>0 ) and (remainingMilRating > neededRating or takeAny): thisAlloc = max(0, min( neededRating, remainingMilRating)) maxAlloc = safetyFactor*3*max( foAI.foAIstate.systemStatus.get(sid, {}).get('totalThreat', 0), foAI.foAIstate.systemStatus.get(sid, {}).get('neightborThreat', 0)) newAlloc+=thisAlloc allocations.append( (sid, thisAlloc, takeAny , maxAlloc) ) allocationGroups.setdefault('topTargets', []).append( (sid, thisAlloc, takeAny , maxAlloc) ) remainingMilRating -= thisAlloc otSysAlloc += thisAlloc if "Main" in thisround or thisAlloc >0: if verboseMilReporting: print "Targeted system %4d ( %10s ) has local threat %8d ; existing military allocation %d and new allocation %8d"%(sid, universe.getSystem(sid).name, thrt, curAlloc, thisAlloc) if "Main" in thisround or newAlloc >0: if verboseMilReporting: print "-----------------" print "Top Colony and Invasion Targeted Systems under total threat: %d -- total mil allocation-- existing: %d ; new: %d"%(tototSysThreat, totCurAlloc, otSysAlloc ) print "-----------------" #================================ #--------Targeted Systems ---------- #TODO: do native invasions highest priority otherTargetedSystemIDs = [sysID for sysID in set( PlanetUtilsAI.get_systems(AIstate.opponentPlanetIDs)) if sysID not in topTargetSystems] if "Main" in thisround: if verboseMilReporting: print "Other Invasion Targeted Systems : %s"%( [ "| %d %s |"%(sysID, universe.getSystem(sysID).name) for sysID in otherTargetedSystemIDs ] ) print "-----------------" # for these, calc local threat only, no neighbor threat, but use a multiplier for fleet safety newAlloc=0 if len( otherTargetedSystemIDs ) > 0: otSysAlloc = 0 otSysThreat = [ ( oSID, threatBias +safetyFactor*(foAI.foAIstate.systemStatus.get(oSID, {}).get('totalThreat', 0)+0.5*foAI.foAIstate.systemStatus.get(oSID, {}).get('neighborThreat', 0) ) ) for oSID in otherTargetedSystemIDs ] tototSysThreat = sum( [thrt for sid, thrt in otSysThreat] ) totCurAlloc = sum( [alreadyAssignedRating[sid] for sid, thrt in otSysThreat] ) for sid, thrt in otSysThreat: curAlloc=alreadyAssignedRating[sid] neededRating = rating_needed( 1.4*thrt, curAlloc) thisAlloc=0 #only record more allocation for this invasion if we already started or have enough rating available takeAny= alreadyAssignedRating[sid] > 0 if ( neededRating>0 ) and (remainingMilRating > neededRating or takeAny): thisAlloc = max(0, min( neededRating, remainingMilRating)) newAlloc+=thisAlloc maxAlloc = safetyFactor*3*max( foAI.foAIstate.systemStatus.get(sid, {}).get('totalThreat', 0), foAI.foAIstate.systemStatus.get(sid, {}).get('neightborThreat', 0)) allocations.append( (sid, thisAlloc, takeAny , maxAlloc) ) allocationGroups.setdefault('otherTargets', []).append( (sid, thisAlloc, takeAny , maxAlloc) ) remainingMilRating -= thisAlloc otSysAlloc += thisAlloc if "Main" in thisround or thisAlloc >0: if verboseMilReporting: print "Targeted system %4d ( %10s ) has local threat %8d ; existing military allocation %d and new allocation %8d"%(sid, universe.getSystem(sid).name, thrt, curAlloc, thisAlloc) if "Main" in thisround or newAlloc >0: if verboseMilReporting: print "-----------------" print "Invasion Targeted Systems under total threat: %d -- total mil allocation-- existing: %d ; new: %d"%(tototSysThreat, totCurAlloc, otSysAlloc ) print "-----------------" otherTargetedSystemIDs = [sysID for sysID in list(set(AIstate.colonyTargetedSystemIDs + AIstate.outpostTargetedSystemIDs)) if sysID not in topTargetSystems] if "Main" in thisround: if verboseMilReporting: print "Other Targeted Systems : %s"%( [ "| %d %s |"%(sysID, universe.getSystem(sysID).name) for sysID in otherTargetedSystemIDs ] ) print "-----------------" if len( otherTargetedSystemIDs ) > 0: otSysAlloc = 0 otSysThreat = [ ( oSID, safetyFactor*(threatBias +foAI.foAIstate.systemStatus.get(oSID, {}).get('totalThreat', 0)+0.5*foAI.foAIstate.systemStatus.get(oSID, {}).get('neighborThreat', 0) ) ) for oSID in otherTargetedSystemIDs ] tototSysThreat = sum( [thrt for sid, thrt in otSysThreat] ) totCurAlloc = sum( [alreadyAssignedRating[sid] for sid, thrt in otSysThreat] ) newAlloc=0 for sid, thrt in otSysThreat: curAlloc=alreadyAssignedRating[sid] neededRating = rating_needed( 1.2*thrt, curAlloc) thisAlloc=0 #only record more allocation for this invasion if we already started or have enough rating available takeAny= alreadyAssignedRating[sid] > 0 if ( neededRating>0 ) and (remainingMilRating > neededRating or takeAny): thisAlloc = max(0, min( neededRating, remainingMilRating)) newAlloc+=thisAlloc maxAlloc = safetyFactor*3*max( foAI.foAIstate.systemStatus.get(sid, {}).get('totalThreat', 0), foAI.foAIstate.systemStatus.get(sid, {}).get('neightborThreat', 0)) allocations.append( (sid, thisAlloc, takeAny , maxAlloc) ) allocationGroups.setdefault('otherTargets', []).append( (sid, thisAlloc, takeAny , maxAlloc) ) remainingMilRating -= thisAlloc otSysAlloc += thisAlloc if "Main" in thisround or thisAlloc >0: if verboseMilReporting: print "Targeted system %4d ( %10s ) has local threat %8d ; existing military allocation %d and new allocation %8d"%(sid, universe.getSystem(sid).name, thrt, curAlloc, thisAlloc) if "Main" in thisround or newAlloc >0: if verboseMilReporting: print "-----------------" print "Other Targeted Systems under total threat: %d -- total mil allocation-- existing: %d ; new: %d"%(tototSysThreat, totCurAlloc, otSysAlloc ) print "-----------------" otherTargetedSystemIDs = [] #targetableIDs = ColonisationAI.annexableSystemIDs.union( empire.fleetSupplyableSystemIDs ) targetableIDs = set(ColonisationAI.systems_by_supply_tier.get(0, []) + ColonisationAI.systems_by_supply_tier.get(1, [])) for sysID in AIstate.opponentSystemIDs: if sysID in targetableIDs: otherTargetedSystemIDs.append(sysID) else: for nID in universe.getImmediateNeighbors(sysID, empireID): if nID in targetableIDs: otherTargetedSystemIDs.append(sysID) break if "Main" in thisround: if verboseMilReporting: print "Blockade Targeted Systems : %s"%( [ "| %d %s |"%(sysID, universe.getSystem(sysID).name) for sysID in otherTargetedSystemIDs ] ) print "-----------------" if len( otherTargetedSystemIDs ) > 0: otSysAlloc = 0 otSysThreat = [ ( oSID, threatBias +safetyFactor*(foAI.foAIstate.systemStatus.get(oSID, {}).get('totalThreat', 0)+ 0.5*foAI.foAIstate.systemStatus.get(oSID, {}).get('neighborThreat', 0) ) ) for oSID in otherTargetedSystemIDs ] tototSysThreat = sum( [thrt for sid, thrt in otSysThreat] ) totCurAlloc = sum( [alreadyAssignedRating[sid] for sid, thrt in otSysThreat] ) newAlloc=0 for sid, thrt in otSysThreat: curAlloc=alreadyAssignedRating[sid] neededRating = rating_needed( 1.2*thrt, curAlloc) thisAlloc=0 #only record more allocation for this invasion if we already started or have enough rating available takeAny= alreadyAssignedRating[sid] > 0 if ( neededRating>0 ) and (remainingMilRating > neededRating or takeAny): thisAlloc = max(0, min( neededRating, remainingMilRating)) newAlloc+=thisAlloc maxAlloc = safetyFactor*2*max( foAI.foAIstate.systemStatus.get(sid, {}).get('totalThreat', 0), foAI.foAIstate.systemStatus.get(sid, {}).get('neightborThreat', 0)) allocations.append( (sid, thisAlloc, takeAny , maxAlloc) ) allocationGroups.setdefault('otherTargets', []).append( (sid, thisAlloc, takeAny , maxAlloc) ) remainingMilRating -= thisAlloc otSysAlloc += thisAlloc if "Main" in thisround or thisAlloc >0: if verboseMilReporting: print "Blockade Targeted system %4d ( %10s ) has local threat %8d ; existing military allocation %d and new allocation %8d"%(sid, universe.getSystem(sid).name, thrt, curAlloc, thisAlloc) if "Main" in thisround or newAlloc >0: if verboseMilReporting: print "-----------------" print "Blockade Targeted Systems under total threat: %d -- total mil allocation-- existing: %d ; new: %d"%(tototSysThreat, totCurAlloc, otSysAlloc ) print "-----------------" currentMilSystems = [sid for sid, alloc, takeAny, mm in allocations ] interiorIDs = list( foAI.foAIstate.expInteriorSystemIDs) interiorTargets1 = (targetableIDs.union(interiorIDs)).difference( currentMilSystems ) interiorTargets = [sid for sid in interiorTargets1 if ( threatBias + foAI.foAIstate.systemStatus.get(sid, {}).get('totalThreat', 0) >0.8*alreadyAssignedRating[sid] ) ] if "Main" in thisround: if verboseMilReporting: print print "Other Empire-Proximal Systems : %s"%( [ "| %d %s |"%(sysID, universe.getSystem(sysID).name) for sysID in interiorTargets1 ] ) print "-----------------" # for these, calc fleet threat only, no neighbor threat, but use a multiplier for fleet safety newAlloc=0 if len(interiorTargets) >0: otSysAlloc = 0 otSysThreat = [ ( oSID, threatBias +safetyFactor*(foAI.foAIstate.systemStatus.get(oSID, {}).get('totalThreat', 0)) ) for oSID in interiorTargets ] tototSysThreat = sum( [thrt for sid, thrt in otSysThreat] ) totCurAlloc = sum( [alreadyAssignedRating[sid] for sid, thrt in otSysThreat] ) for sid, thrt in otSysThreat: curAlloc=alreadyAssignedRating[sid] neededRating = rating_needed( 1.2*thrt, curAlloc) thisAlloc=0 #only record more allocation for this invasion if we already started or have enough rating available takeAny= alreadyAssignedRating[sid] > 0 if ( neededRating>0 ) and (remainingMilRating > neededRating or takeAny): thisAlloc = max(0, min( neededRating, remainingMilRating)) newAlloc+=thisAlloc maxAlloc = safetyFactor*2*max( foAI.foAIstate.systemStatus.get(sid, {}).get('totalThreat', 0), foAI.foAIstate.systemStatus.get(sid, {}).get('neightborThreat', 0)) allocations.append( (sid, thisAlloc, takeAny , maxAlloc) ) allocationGroups.setdefault('otherTargets', []).append( (sid, thisAlloc, takeAny , maxAlloc) ) remainingMilRating -= thisAlloc otSysAlloc += thisAlloc if "Main" in thisround or thisAlloc >0: if verboseMilReporting: print "Other interior system %4d ( %10s ) has local threat %8d ; existing military allocation %d and new allocation %8d"%(sid, universe.getSystem(sid).name, thrt, curAlloc, thisAlloc) if "Main" in thisround or newAlloc >0: if verboseMilReporting: print "-----------------" print "Other Interior Systems under total threat: %d -- total mil allocation-- existing: %d ; new: %d"%(tototSysThreat, totCurAlloc, otSysAlloc ) print "-----------------" elif "Main" in thisround: if verboseMilReporting: print "-----------------" print "No Other Interior Systems with fleet threat " print "-----------------" monsterDens=[] #exploTargetIDs, _ = ExplorationAI.get_current_exploration_info(verbose=False) exploTargetIDs=[] if "Main" in thisround: if verboseMilReporting: print print "Exploration-targeted Systems: %s"%( [ "| %d %s |"%(sysID, universe.getSystem(sysID).name) for sysID in exploTargetIDs ] ) print "-----------------" # for these, calc fleet threat only, no neighbor threat, but use a multiplier for fleet safety newAlloc=0 if len(exploTargetIDs) > 0: otSysAlloc = 0 otSysThreat = [ ( oSID, safetyFactor*(foAI.foAIstate.systemStatus.get(oSID, {}).get('fleetThreat', 0) + foAI.foAIstate.systemStatus.get(oSID, {}).get('monsterThreat', 0)+ foAI.foAIstate.systemStatus.get(oSID, {}).get('planetThreat', 0) )) for oSID in exploTargetIDs ] tototSysThreat = sum( [thrt for sid, thrt in otSysThreat] ) totCurAlloc = sum( [0.8*alreadyAssignedRating[sid] for sid, thrt in otSysThreat] ) if availMilRating <1125: maxMilRating = availMilRating else: maxMilRating = 0.5*availMilRating for sid, thrt in otSysThreat: curAlloc=alreadyAssignedRating[sid] neededRating = rating_needed( 1.2*thrt, curAlloc) thisAlloc=0 #only record more allocation for this invasion if we already started or have enough rating available takeAny= False if ( neededRating>0 ) and (remainingMilRating > neededRating or takeAny): thisAlloc = max(0, min( neededRating, remainingMilRating)) newAlloc+=thisAlloc maxAlloc = safetyFactor*2*max( foAI.foAIstate.systemStatus.get(sid, {}).get('totalThreat', 0), foAI.foAIstate.systemStatus.get(sid, {}).get('neightborThreat', 0)) allocations.append( (sid, thisAlloc, takeAny , maxAlloc) ) allocationGroups.setdefault('exploreTargets', []).append( (sid, thisAlloc, takeAny , maxAlloc) ) remainingMilRating -= thisAlloc otSysAlloc += thisAlloc if "Main" in thisround or thisAlloc >0: if verboseMilReporting: print "Exploration-targeted %4d ( %10s ) has local threat %8d ; existing military allocation %d and new allocation %8d"%(sid, universe.getSystem(sid).name, thrt, curAlloc, thisAlloc) if "Main" in thisround or newAlloc >0: if verboseMilReporting: print "-----------------" print "Exploration-targeted s under total threat: %d -- total mil allocation-- existing: %d ; new: %d"%(tototSysThreat, totCurAlloc, otSysAlloc ) print "-----------------" visibleSystemIDs = foAI.foAIstate.visInteriorSystemIDs.keys() + foAI.foAIstate. visBorderSystemIDs.keys() accessibleSystemIDs = [sysID for sysID in visibleSystemIDs if universe.systemsConnected(sysID, homeSystemID, empireID) ] currentMilSystems = [sid for sid, alloc, takeAny, multiplier in allocations if alloc > 0 ] borderTargets1 = [sid for sid in accessibleSystemIDs if ( sid not in currentMilSystems) ] borderTargets = [sid for sid in borderTargets1 if (threatBias +foAI.foAIstate.systemStatus.get(sid, {}).get('fleetThreat', 0) + foAI.foAIstate.systemStatus.get(sid, {}).get('planetThreat', 0) > 0.8*alreadyAssignedRating[sid]) ] if "Main" in thisround: if verboseMilReporting: print print "Empire-Accessible Systems not yet allocated military: %s"%( [ "| %d %s |"%(sysID, universe.getSystem(sysID) and universe.getSystem(sysID).name) for sysID in borderTargets1 ] ) print "-----------------" # for these, calc fleet threat only, no neighbor threat, but use a multiplier for fleet safety newAlloc=0 if len(borderTargets) > 0: otSysAlloc = 0 otSysThreat = [ ( oSID, threatBias +safetyFactor*(foAI.foAIstate.systemStatus.get(oSID, {}).get('fleetThreat', 0) + foAI.foAIstate.systemStatus.get(oSID, {}).get('monsterThreat', 0)+ foAI.foAIstate.systemStatus.get(oSID, {}).get('planetThreat', 0)) ) for oSID in borderTargets ] tototSysThreat = sum( [thrt for sid, thrt in otSysThreat] ) totCurAlloc = sum( [0.8*alreadyAssignedRating[sid] for sid, thrt in otSysThreat] ) for sid, thrt in otSysThreat: curAlloc=alreadyAssignedRating[sid] neededRating = rating_needed( 1.2*thrt, curAlloc) thisAlloc=0 #only record more allocation for this invasion if we already started or have enough rating available takeAny= False if ( neededRating>0 ) and (remainingMilRating > neededRating or takeAny): thisAlloc = max(0, min( neededRating, remainingMilRating)) newAlloc+=thisAlloc maxAlloc = safetyFactor*2*max( foAI.foAIstate.systemStatus.get(sid, {}).get('totalThreat', 0), foAI.foAIstate.systemStatus.get(sid, {}).get('neightborThreat', 0)) allocations.append( (sid, thisAlloc, takeAny , maxAlloc) ) allocationGroups.setdefault('accessibleTargets', []).append( (sid, thisAlloc, takeAny , maxAlloc) ) remainingMilRating -= thisAlloc otSysAlloc += thisAlloc if "Main" in thisround or thisAlloc >0: if verboseMilReporting: print "Other Empire-Accessible system %4d ( %10s ) has local biased threat %8d ; existing military allocation %d and new allocation %8d"%(sid, universe.getSystem(sid).name, thrt, curAlloc, thisAlloc) if "Main" in thisround or newAlloc >0: if verboseMilReporting: print "-----------------" print "Other Empire-Accessible Systems under total biased threat: %d -- total mil allocation-- existing: %d ; new: %d"%(tototSysThreat, totCurAlloc, otSysAlloc ) print "-----------------" elif "Main" in thisround: if verboseMilReporting: print "-----------------" print "No Other Empire-Accessible Systems with biased local threat " print "-----------------" #monster den treatment probably unnecessary now if "Main" in thisround: if verboseMilReporting: print print "Big-Monster Dens: %s"%( [ "| %d %s |"%(sysID, universe.getSystem(sysID).name) for sysID in monsterDens ] ) print "-----------------" # for these, calc fleet threat only, no neighbor threat, but use a multiplier for fleet safety newAlloc=0 if len(monsterDens) > 0: otSysAlloc = 0 otSysThreat = [ ( oSID, safetyFactor*(foAI.foAIstate.systemStatus.get(oSID, {}).get('fleetThreat', 0)+foAI.foAIstate.systemStatus.get(oSID, {}).get('monsterThreat', 0) + foAI.foAIstate.systemStatus.get(oSID, {}).get('planetThreat', 0) ) ) for oSID in monsterDens ] tototSysThreat = sum( [thrt for sid, thrt in otSysThreat] ) totCurAlloc = sum( [0.8*alreadyAssignedRating[sid] for sid, thrt in otSysThreat] ) for sid, thrt in otSysThreat: curAlloc=0.8*alreadyAssignedRating[sid] thisAlloc=0 if (thrt > curAlloc) and remainingMilRating > 2* thrt: thisAlloc = int(0.99999 + (thrt-curAlloc)*1.5) newAlloc+=thisAlloc allocations.append( (sid, thisAlloc, False, 5) ) remainingMilRating -= thisAlloc otSysAlloc += thisAlloc if "Main" in thisround or thisAlloc >0: if verboseMilReporting: print "Monster Den %4d ( %10s ) has local threat %8d ; existing military allocation %d and new allocation %8d"%(sid, universe.getSystem(sid).name, thrt, curAlloc, thisAlloc) if "Main" in thisround or newAlloc >0: if verboseMilReporting: print "-----------------" if remainingMilRating <=6: newAllocations = [ (sid, alc, alc, ta) for (sid, alc, ta, mm) in allocations ] else: #oldAllocations = dict( [ (entry[0], entry ) for entry in allocations ] ) try: totAlloc = sum( [alloc for sid, alloc, takeAny, maxAlloc in allocations ] ) except: print "error unpacking sid, alloc, takeAny, maxAlloc from ", allocations factor =(2.0* remainingMilRating ) / ( totAlloc + 0.1) #print "Remaining military strength allocation %d will be allocated as %.1f %% surplus allocation to top current priorities"%(remainingMilRating, 100*factor) print "%s Round Remaining military strength allocation %d will be allocated as surplus allocation to top current priorities"%(thisround, remainingMilRating) newAllocations = [] for cat in ['capitol', 'topTargets', 'otherTargets', 'accessibleTargets', 'occupied', 'exploreTargets']: for sid, alloc, takeAny, maxAlloc in allocationGroups.get(cat, []): if remainingMilRating <= 0 : newAllocations.append( ( sid, alloc, alloc, takeAny ) ) else: newRating = min(remainingMilRating+alloc, max(alloc, rating_needed( maxAlloc, alreadyAssignedRating[sid]) ) ) newAllocations.append( ( sid, newRating, alloc, takeAny ) ) remainingMilRating -= ( newRating - alloc ) if "Main" in thisround: MilitaryAllocations = newAllocations minMilAllocations.clear() minMilAllocations.update( [ (sid, alloc) for sid, alloc, takeAny, mm in allocations ] ) if verboseMilReporting or "Main" in thisround: print "------------------------------\nFinal %s Round Military Allocations: %s \n-----------------------"%(thisround, dict( [ (sid, alloc) for sid, alloc, minalloc, takeAny in newAllocations ] ) ) # export military systems for other AI modules if "Main" in thisround: AIstate.militarySystemIDs = list( set([sid for sid, alloc, minalloc, takeAny in newAllocations]).union( [sid for sid in alreadyAssignedRating if alreadyAssignedRating[sid]>0 ] )) else: AIstate.militarySystemIDs = list( set([sid for sid, alloc, minalloc, takeAny in newAllocations]).union( AIstate.militarySystemIDs) ) return newAllocations
def get_military_fleets(milFleetIDs=None, tryReset=True, thisround="Main"): """get armed military fleets""" global military_allocations, totMilRating, num_milships universe = fo.getUniverse() empire = fo.getEmpire() empire_id = empire.empireID capital_id = PlanetUtilsAI.get_capital() if capital_id is None: homeworld = None else: homeworld = universe.getPlanet(capital_id) if homeworld: home_system_id = homeworld.systemID else: home_system_id = -1 if milFleetIDs is not None: all_military_fleet_ids = milFleetIDs else: all_military_fleet_ids = FleetUtilsAI.get_empire_fleet_ids_by_role( AIFleetMissionType.FLEET_MISSION_MILITARY) if tryReset and (fo.currentTurn() + empire_id) % 30 == 0 and thisround == "Main": try_again(all_military_fleet_ids, try_reset=False, thisround=thisround + " Reset") num_milships = 0 for fid in all_military_fleet_ids: num_milships += foAI.foAIstate.fleetStatus.get(fid, {}).get('nships', 0) this_tot_mil_rating = sum( map(lambda x: foAI.foAIstate.get_rating(x).get('overall', 0), all_military_fleet_ids)) if "Main" in thisround: totMilRating = this_tot_mil_rating print "==================================================" print "%s Round Total Military Rating: %d" % (thisround, totMilRating) print "---------------------------------" foAI.foAIstate.militaryRating = totMilRating milFleetIDs = list( FleetUtilsAI.extract_fleet_ids_without_mission_types( all_military_fleet_ids)) mil_needing_repair_ids, milFleetIDs = avail_mil_needing_repair( milFleetIDs, split_ships=True) avail_mil_rating = sum( map(lambda x: foAI.foAIstate.get_rating(x).get('overall', 0), milFleetIDs)) if "Main" in thisround: print "==================================================" print "%s Round Available Military Rating: %d" % (thisround, avail_mil_rating) print "---------------------------------" remaining_mil_rating = avail_mil_rating allocations = [] allocation_groups = {} if not milFleetIDs: if "Main" in thisround: military_allocations = [] return [] # for each system, get total rating of fleets assigned to it already_assigned_rating = {} assigned_attack = {} assigned_hp = {} for sys_id in universe.systemIDs: assigned_attack[sys_id] = 0 assigned_hp[sys_id] = 0 for fleet_id in [ fid for fid in all_military_fleet_ids if fid not in milFleetIDs ]: ai_fleet_mission = foAI.foAIstate.get_fleet_mission(fleet_id) sys_targets = [] for ai_fleet_mission_type in ai_fleet_mission.get_mission_types(): ai_targets = ai_fleet_mission.get_targets(ai_fleet_mission_type) for aiTarget in ai_targets: sys_targets.extend(aiTarget.get_required_system_ai_targets()) if not sys_targets: # shouldn't really be possible continue last_sys = sys_targets[ -1].target_id # will count this fleet as assigned to last system in target list assigned_attack[last_sys] += foAI.foAIstate.get_rating(fleet_id).get( 'attack', 0) assigned_hp[last_sys] += foAI.foAIstate.get_rating(fleet_id).get( 'health', 0) for sys_id in universe.systemIDs: mydefenses = foAI.foAIstate.systemStatus.get(sys_id, {}).get('mydefenses', {}) mypattack = mydefenses.get('attack', 0) myphealth = mydefenses.get('health', 0) already_assigned_rating[sys_id] = (assigned_attack[sys_id] + mypattack) * (assigned_hp[sys_id] + myphealth) # get systems to defend capital_id = PlanetUtilsAI.get_capital() if capital_id is not None: capital_planet = universe.getPlanet(capital_id) else: capital_planet = None # TODO: if no owned planets try to capture one! if capital_planet: capital_sys_id = capital_planet.systemID else: # should be rare, but so as to not break code below, pick a randomish mil-centroid system capital_sys_id = None # unless we can find one to use system_dict = {} for fleet_id in all_military_fleet_ids: status = foAI.foAIstate.fleetStatus.get(fleet_id, None) if status is not None: sys_id = status['sysID'] if not list(universe.getSystem(sys_id).planetIDs): continue system_dict[sys_id] = system_dict.get(sys_id, 0) + status.get( 'rating', {}).get('overall', 0) ranked_systems = sorted([(val, sys_id) for sys_id, val in system_dict.items()]) if ranked_systems: capital_sys_id = ranked_systems[-1][-1] else: try: capital_sys_id = foAI.foAIstate.fleetStatus.items( )[0][1]['sysID'] except: pass if False: if fo.currentTurn() < 20: threat_bias = 0 elif fo.currentTurn() < 40: threat_bias = 10 elif fo.currentTurn() < 60: threat_bias = 80 elif fo.currentTurn() < 80: threat_bias = 200 else: threat_bias = 400 else: threat_bias = 0 safety_factor = get_safety_factor() top_target_planets = [ pid for pid, pscore, trp in AIstate. invasionTargets[:PriorityAI.allottedInvasionTargets] if pscore > 20 ] + [ pid for pid, (pscore, spec) in foAI.foAIstate.colonisablePlanetIDs.items()[:10] if pscore > 20 ] top_target_planets.extend(foAI.foAIstate.qualifyingTroopBaseTargets.keys()) top_target_systems = [] for sys_id in AIstate.invasionTargetedSystemIDs + PlanetUtilsAI.get_systems( top_target_planets): if sys_id not in top_target_systems: top_target_systems.append( sys_id) # doing this rather than set, to preserve order # allocation format: ( sysID, newAllocation, takeAny, maxMultiplier ) # ================================ # --------Capital Threat ---------- capital_threat = safety_factor * (2 * threat_bias + sum([ foAI.foAIstate.systemStatus[capital_sys_id][thrt_key] for thrt_key in ['totalThreat', 'neighborThreat'] ])) needed_rating = rating_needed(1.4 * capital_threat, already_assigned_rating[capital_sys_id]) new_alloc = 0 if tryReset: if needed_rating > 0.5 * avail_mil_rating: try_again(all_military_fleet_ids) return if needed_rating > 0: new_alloc = min(remaining_mil_rating, needed_rating) allocations.append( (capital_sys_id, new_alloc, True, 1.6 * capital_threat)) allocation_groups.setdefault('capitol', []).append( (capital_sys_id, new_alloc, True, 2 * capital_threat)) remaining_mil_rating -= new_alloc if "Main" in thisround or new_alloc > 0: if verbose_mil_reporting: print "Empire Capital System: (%d) %s -- threat : %d, military allocation: existing: %d ; new: %d" % ( capital_sys_id, universe.getSystem(capital_sys_id).name, capital_threat, already_assigned_rating[capital_sys_id], new_alloc) print "-----------------" # ================================ # --------Empire Occupied Systems ---------- empire_planet_ids = PlanetUtilsAI.get_owned_planets_by_empire( universe.planetIDs) empire_occupied_system_ids = list( set(PlanetUtilsAI.get_systems(empire_planet_ids)) - {capital_sys_id}) if "Main" in thisround: if verbose_mil_reporting: print "Empire-Occupied Systems: %s" % ([ "| %d %s |" % (eo_sys_id, universe.getSystem(eo_sys_id).name) for eo_sys_id in empire_occupied_system_ids ]) print "-----------------" new_alloc = 0 if empire_occupied_system_ids: oc_sys_tot_threat = [(o_s_id, threat_bias + safety_factor * sum([ foAI.foAIstate.systemStatus.get(o_s_id, {}).get(thrt_key, 0) for thrt_key in ['totalThreat', 'neighborThreat'] ])) for o_s_id in empire_occupied_system_ids] totoc_sys_threat = sum([thrt for sid, thrt in oc_sys_tot_threat]) tot_cur_alloc = sum( [already_assigned_rating[sid] for sid, thrt in oc_sys_tot_threat]) oc_sys_alloc = 0 for sid, thrt in oc_sys_tot_threat: cur_alloc = already_assigned_rating[sid] needed_rating = rating_needed(1.3 * thrt, cur_alloc) if (needed_rating > 0.8 * remaining_mil_rating) and tryReset: try_again(all_military_fleet_ids) return this_alloc = 0 if needed_rating > 0 and remaining_mil_rating > 0: this_alloc = max( 0, min(needed_rating, 0.5 * avail_mil_rating, remaining_mil_rating)) new_alloc += this_alloc allocations.append((sid, this_alloc, True, 1.6 * thrt)) allocation_groups.setdefault('occupied', []).append( (sid, this_alloc, True, 2 * thrt)) remaining_mil_rating -= this_alloc oc_sys_alloc += this_alloc if "Main" in thisround or this_alloc > 0: if verbose_mil_reporting: print "Provincial Occupied system %4d ( %10s ) has local threat %8d ; existing military allocation %d and new allocation %8d" % ( sid, universe.getSystem(sid).name, thrt, cur_alloc, this_alloc) if "Main" in thisround or new_alloc > 0: if verbose_mil_reporting: print "Provincial Empire-Occupied Sytems under total threat: %d -- total mil allocation: existing %d ; new: %d" % ( totoc_sys_threat, tot_cur_alloc, oc_sys_alloc) print "-----------------" # ================================ # --------Top Targeted Systems ---------- # TODO: do native invasions highest priority other_targeted_system_ids = top_target_systems if "Main" in thisround: if verbose_mil_reporting: print "Top Colony and Invasion Targeted Systems : %s" % ([ "| %d %s |" % (sys_id, universe.getSystem(sys_id).name) for sys_id in other_targeted_system_ids ]) print "-----------------" # for these, calc local threat only, no neighbor threat, but use a multiplier for fleet safety new_alloc = 0 if other_targeted_system_ids: ot_sys_alloc = 0 ot_sys_threat = [ (o_s_id, threat_bias + safety_factor * (foAI.foAIstate.systemStatus.get(o_s_id, {}).get( 'totalThreat', 0) + 0.5 * foAI.foAIstate.systemStatus.get( o_s_id, {}).get('neightborThreat', 0))) for o_s_id in other_targeted_system_ids ] totot_sys_threat = sum([thrt for sid, thrt in ot_sys_threat]) tot_cur_alloc = sum( [already_assigned_rating[sid] for sid, thrt in ot_sys_threat]) for sid, thrt in ot_sys_threat: cur_alloc = already_assigned_rating[sid] needed_rating = rating_needed(1.4 * thrt, cur_alloc) this_alloc = 0 # only record more allocation for this invasion if we already started or have enough rating available take_any = already_assigned_rating[sid] > 0 if needed_rating > 0 and (remaining_mil_rating > needed_rating or take_any): this_alloc = max(0, min(needed_rating, remaining_mil_rating)) max_alloc = safety_factor * 3 * max( foAI.foAIstate.systemStatus.get(sid, {}).get( 'totalThreat', 0), foAI.foAIstate.systemStatus.get(sid, {}).get( 'neightborThreat', 0)) new_alloc += this_alloc allocations.append((sid, this_alloc, take_any, max_alloc)) allocation_groups.setdefault('topTargets', []).append( (sid, this_alloc, take_any, max_alloc)) remaining_mil_rating -= this_alloc ot_sys_alloc += this_alloc if "Main" in thisround or this_alloc > 0: if verbose_mil_reporting: print "Targeted system %4d ( %10s ) has local threat %8d ; existing military allocation %d and new allocation %8d" % ( sid, universe.getSystem(sid).name, thrt, cur_alloc, this_alloc) if "Main" in thisround or new_alloc > 0: if verbose_mil_reporting: print "-----------------" print "Top Colony and Invasion Targeted Systems under total threat: %d -- total mil allocation-- existing: %d ; new: %d" % ( totot_sys_threat, tot_cur_alloc, ot_sys_alloc) print "-----------------" # ================================ # --------Targeted Systems ---------- # TODO: do native invasions highest priority other_targeted_system_ids = [ sys_id for sys_id in set(PlanetUtilsAI.get_systems(AIstate.opponentPlanetIDs)) if sys_id not in top_target_systems ] if "Main" in thisround: if verbose_mil_reporting: print "Other Invasion Targeted Systems : %s" % ([ "| %d %s |" % (sys_id, universe.getSystem(sys_id).name) for sys_id in other_targeted_system_ids ]) print "-----------------" # for these, calc local threat only, no neighbor threat, but use a multiplier for fleet safety new_alloc = 0 if other_targeted_system_ids: ot_sys_alloc = 0 ot_sys_threat = [ (o_s_id, threat_bias + safety_factor * (foAI.foAIstate.systemStatus.get(o_s_id, {}).get( 'totalThreat', 0) + 0.5 * foAI.foAIstate.systemStatus.get( o_s_id, {}).get('neighborThreat', 0))) for o_s_id in other_targeted_system_ids ] totot_sys_threat = sum([thrt for sid, thrt in ot_sys_threat]) tot_cur_alloc = sum( [already_assigned_rating[sid] for sid, thrt in ot_sys_threat]) for sid, thrt in ot_sys_threat: cur_alloc = already_assigned_rating[sid] needed_rating = rating_needed(1.4 * thrt, cur_alloc) this_alloc = 0 # only record more allocation for this invasion if we already started or have enough rating available take_any = already_assigned_rating[sid] > 0 if needed_rating > 0 and (remaining_mil_rating > needed_rating or take_any): this_alloc = max(0, min(needed_rating, remaining_mil_rating)) new_alloc += this_alloc max_alloc = safety_factor * 3 * max( foAI.foAIstate.systemStatus.get(sid, {}).get( 'totalThreat', 0), foAI.foAIstate.systemStatus.get(sid, {}).get( 'neightborThreat', 0)) allocations.append((sid, this_alloc, take_any, max_alloc)) allocation_groups.setdefault('otherTargets', []).append( (sid, this_alloc, take_any, max_alloc)) remaining_mil_rating -= this_alloc ot_sys_alloc += this_alloc if "Main" in thisround or this_alloc > 0: if verbose_mil_reporting: print "Targeted system %4d ( %10s ) has local threat %8d ; existing military allocation %d and new allocation %8d" % ( sid, universe.getSystem(sid).name, thrt, cur_alloc, this_alloc) if "Main" in thisround or new_alloc > 0: if verbose_mil_reporting: print "-----------------" print "Invasion Targeted Systems under total threat: %d -- total mil allocation-- existing: %d ; new: %d" % ( totot_sys_threat, tot_cur_alloc, ot_sys_alloc) print "-----------------" other_targeted_system_ids = [ sys_id for sys_id in list( set(AIstate.colonyTargetedSystemIDs + AIstate.outpostTargetedSystemIDs)) if sys_id not in top_target_systems ] if "Main" in thisround: if verbose_mil_reporting: print "Other Targeted Systems : %s" % ([ "| %d %s |" % (sys_id, universe.getSystem(sys_id).name) for sys_id in other_targeted_system_ids ]) print "-----------------" if other_targeted_system_ids: ot_sys_alloc = 0 ot_sys_threat = [ (o_s_id, safety_factor * (threat_bias + foAI.foAIstate.systemStatus.get(o_s_id, {}).get( 'totalThreat', 0) + 0.5 * foAI.foAIstate.systemStatus.get( o_s_id, {}).get('neighborThreat', 0))) for o_s_id in other_targeted_system_ids ] totot_sys_threat = sum([thrt for sid, thrt in ot_sys_threat]) tot_cur_alloc = sum( [already_assigned_rating[sid] for sid, thrt in ot_sys_threat]) new_alloc = 0 for sid, thrt in ot_sys_threat: cur_alloc = already_assigned_rating[sid] needed_rating = rating_needed(1.2 * thrt, cur_alloc) this_alloc = 0 # only record more allocation for this invasion if we already started or have enough rating available take_any = already_assigned_rating[sid] > 0 if needed_rating > 0 and (remaining_mil_rating > needed_rating or take_any): this_alloc = max(0, min(needed_rating, remaining_mil_rating)) new_alloc += this_alloc max_alloc = safety_factor * 3 * max( foAI.foAIstate.systemStatus.get(sid, {}).get( 'totalThreat', 0), foAI.foAIstate.systemStatus.get(sid, {}).get( 'neightborThreat', 0)) allocations.append((sid, this_alloc, take_any, max_alloc)) allocation_groups.setdefault('otherTargets', []).append( (sid, this_alloc, take_any, max_alloc)) remaining_mil_rating -= this_alloc ot_sys_alloc += this_alloc if "Main" in thisround or this_alloc > 0: if verbose_mil_reporting: print "Targeted system %4d ( %10s ) has local threat %8d ; existing military allocation %d and new allocation %8d" % ( sid, universe.getSystem(sid).name, thrt, cur_alloc, this_alloc) if "Main" in thisround or new_alloc > 0: if verbose_mil_reporting: print "-----------------" print "Other Targeted Systems under total threat: %d -- total mil allocation-- existing: %d ; new: %d" % ( totot_sys_threat, tot_cur_alloc, ot_sys_alloc) print "-----------------" other_targeted_system_ids = [] # targetable_ids = ColonisationAI.annexableSystemIDs.union(empire.fleetSupplyableSystemIDs) targetable_ids = set( ColonisationAI.systems_by_supply_tier.get(0, []) + ColonisationAI.systems_by_supply_tier.get(1, [])) for sys_id in AIstate.opponentSystemIDs: if sys_id in targetable_ids: other_targeted_system_ids.append(sys_id) else: for nID in universe.getImmediateNeighbors(sys_id, empire_id): if nID in targetable_ids: other_targeted_system_ids.append(sys_id) break if "Main" in thisround: if verbose_mil_reporting: print "Blockade Targeted Systems : %s" % ([ "| %d %s |" % (sys_id, universe.getSystem(sys_id).name) for sys_id in other_targeted_system_ids ]) print "-----------------" if other_targeted_system_ids: ot_sys_alloc = 0 ot_sys_threat = [ (o_s_id, threat_bias + safety_factor * (foAI.foAIstate.systemStatus.get(o_s_id, {}).get( 'totalThreat', 0) + 0.5 * foAI.foAIstate.systemStatus.get( o_s_id, {}).get('neighborThreat', 0))) for o_s_id in other_targeted_system_ids ] totot_sys_threat = sum([thrt for sid, thrt in ot_sys_threat]) tot_cur_alloc = sum( [already_assigned_rating[sid] for sid, thrt in ot_sys_threat]) new_alloc = 0 for sid, thrt in ot_sys_threat: cur_alloc = already_assigned_rating[sid] needed_rating = rating_needed(1.2 * thrt, cur_alloc) this_alloc = 0 # only record more allocation for this invasion if we already started or have enough rating available take_any = already_assigned_rating[sid] > 0 if needed_rating > 0 and (remaining_mil_rating > needed_rating or take_any): this_alloc = max(0, min(needed_rating, remaining_mil_rating)) new_alloc += this_alloc max_alloc = safety_factor * 2 * max( foAI.foAIstate.systemStatus.get(sid, {}).get( 'totalThreat', 0), foAI.foAIstate.systemStatus.get(sid, {}).get( 'neightborThreat', 0)) allocations.append((sid, this_alloc, take_any, max_alloc)) allocation_groups.setdefault('otherTargets', []).append( (sid, this_alloc, take_any, max_alloc)) remaining_mil_rating -= this_alloc ot_sys_alloc += this_alloc if "Main" in thisround or this_alloc > 0: if verbose_mil_reporting: print "Blockade Targeted system %4d ( %10s ) has local threat %8d ; existing military allocation %d and new allocation %8d" % ( sid, universe.getSystem(sid).name, thrt, cur_alloc, this_alloc) if "Main" in thisround or new_alloc > 0: if verbose_mil_reporting: print "-----------------" print "Blockade Targeted Systems under total threat: %d -- total mil allocation-- existing: %d ; new: %d" % ( totot_sys_threat, tot_cur_alloc, ot_sys_alloc) print "-----------------" current_mil_systems = [sid for sid, alloc, take_any, mm in allocations] interior_ids = list(foAI.foAIstate.expInteriorSystemIDs) interior_targets1 = ( targetable_ids.union(interior_ids)).difference(current_mil_systems) interior_targets = [ sid for sid in interior_targets1 if (threat_bias + foAI.foAIstate.systemStatus.get(sid, {}).get('totalThreat', 0) > 0.8 * already_assigned_rating[sid]) ] if "Main" in thisround: if verbose_mil_reporting: print print "Other Empire-Proximal Systems : %s" % ([ "| %d %s |" % (sys_id, universe.getSystem(sys_id).name) for sys_id in interior_targets1 ]) print "-----------------" # for these, calc fleet threat only, no neighbor threat, but use a multiplier for fleet safety new_alloc = 0 if interior_targets: ot_sys_alloc = 0 ot_sys_threat = [ (o_s_id, threat_bias + safety_factor * (foAI.foAIstate.systemStatus.get( o_s_id, {}).get('totalThreat', 0))) for o_s_id in interior_targets ] totot_sys_threat = sum([thrt for sid, thrt in ot_sys_threat]) tot_cur_alloc = sum( [already_assigned_rating[sid] for sid, thrt in ot_sys_threat]) for sid, thrt in ot_sys_threat: cur_alloc = already_assigned_rating[sid] needed_rating = rating_needed(1.2 * thrt, cur_alloc) this_alloc = 0 # only record more allocation for this invasion if we already started or have enough rating available take_any = already_assigned_rating[sid] > 0 if needed_rating > 0 and (remaining_mil_rating > needed_rating or take_any): this_alloc = max(0, min(needed_rating, remaining_mil_rating)) new_alloc += this_alloc max_alloc = safety_factor * 2 * max( foAI.foAIstate.systemStatus.get(sid, {}).get( 'totalThreat', 0), foAI.foAIstate.systemStatus.get(sid, {}).get( 'neightborThreat', 0)) allocations.append((sid, this_alloc, take_any, max_alloc)) allocation_groups.setdefault('otherTargets', []).append( (sid, this_alloc, take_any, max_alloc)) remaining_mil_rating -= this_alloc ot_sys_alloc += this_alloc if "Main" in thisround or this_alloc > 0: if verbose_mil_reporting: print "Other interior system %4d ( %10s ) has local threat %8d ; existing military allocation %d and new allocation %8d" % ( sid, universe.getSystem(sid).name, thrt, cur_alloc, this_alloc) if "Main" in thisround or new_alloc > 0: if verbose_mil_reporting: print "-----------------" print "Other Interior Systems under total threat: %d -- total mil allocation-- existing: %d ; new: %d" % ( totot_sys_threat, tot_cur_alloc, ot_sys_alloc) print "-----------------" elif "Main" in thisround: if verbose_mil_reporting: print "-----------------" print "No Other Interior Systems with fleet threat " print "-----------------" monster_dens = [] # explo_target_ids, _ = ExplorationAI.get_current_exploration_info(verbose=False) explo_target_ids = [] if "Main" in thisround: if verbose_mil_reporting: print print "Exploration-targeted Systems: %s" % ([ "| %d %s |" % (sys_id, universe.getSystem(sys_id).name) for sys_id in explo_target_ids ]) print "-----------------" # for these, calc fleet threat only, no neighbor threat, but use a multiplier for fleet safety new_alloc = 0 if explo_target_ids: ot_sys_alloc = 0 ot_sys_threat = [( o_s_id, safety_factor * (foAI.foAIstate.systemStatus.get(o_s_id, {}).get('fleetThreat', 0) + foAI.foAIstate.systemStatus.get(o_s_id, {}).get( 'monsterThreat', 0) + foAI.foAIstate.systemStatus.get( o_s_id, {}).get('planetThreat', 0))) for o_s_id in explo_target_ids] totot_sys_threat = sum([thrt for sid, thrt in ot_sys_threat]) tot_cur_alloc = sum([ 0.8 * already_assigned_rating[sid] for sid, thrt in ot_sys_threat ]) for sid, thrt in ot_sys_threat: cur_alloc = already_assigned_rating[sid] needed_rating = rating_needed(1.2 * thrt, cur_alloc) this_alloc = 0 # only record more allocation for this invasion if we already started or have enough rating available take_any = False if needed_rating > 0 and (remaining_mil_rating > needed_rating or take_any): this_alloc = max(0, min(needed_rating, remaining_mil_rating)) new_alloc += this_alloc max_alloc = safety_factor * 2 * max( foAI.foAIstate.systemStatus.get(sid, {}).get( 'totalThreat', 0), foAI.foAIstate.systemStatus.get(sid, {}).get( 'neightborThreat', 0)) allocations.append((sid, this_alloc, take_any, max_alloc)) allocation_groups.setdefault('exploreTargets', []).append( (sid, this_alloc, take_any, max_alloc)) remaining_mil_rating -= this_alloc ot_sys_alloc += this_alloc if "Main" in thisround or this_alloc > 0: if verbose_mil_reporting: print "Exploration-targeted %4d ( %10s ) has local threat %8d ; existing military allocation %d and new allocation %8d" % ( sid, universe.getSystem(sid).name, thrt, cur_alloc, this_alloc) if "Main" in thisround or new_alloc > 0: if verbose_mil_reporting: print "-----------------" print "Exploration-targeted s under total threat: %d -- total mil allocation-- existing: %d ; new: %d" % ( totot_sys_threat, tot_cur_alloc, ot_sys_alloc) print "-----------------" visible_system_ids = foAI.foAIstate.visInteriorSystemIDs.keys( ) + foAI.foAIstate.visBorderSystemIDs.keys() accessible_system_ids = [ sys_id for sys_id in visible_system_ids if universe.systemsConnected(sys_id, home_system_id, empire_id) ] current_mil_systems = [ sid for sid, alloc, take_any, multiplier in allocations if alloc > 0 ] border_targets1 = [ sid for sid in accessible_system_ids if sid not in current_mil_systems ] border_targets = [ sid for sid in border_targets1 if (threat_bias + foAI.foAIstate.systemStatus.get(sid, {}).get('fleetThreat', 0) + foAI.foAIstate.systemStatus.get(sid, {}).get('planetThreat', 0) > 0.8 * already_assigned_rating[sid]) ] if "Main" in thisround: if verbose_mil_reporting: print print "Empire-Accessible Systems not yet allocated military: %s" % ( [ "| %d %s |" % (sys_id, universe.getSystem(sys_id) and universe.getSystem(sys_id).name) for sys_id in border_targets1 ]) print "-----------------" # for these, calc fleet threat only, no neighbor threat, but use a multiplier for fleet safety new_alloc = 0 if border_targets: ot_sys_alloc = 0 ot_sys_threat = [( o_s_id, threat_bias + safety_factor * (foAI.foAIstate.systemStatus.get(o_s_id, {}).get('fleetThreat', 0) + foAI.foAIstate.systemStatus.get(o_s_id, {}).get( 'monsterThreat', 0) + foAI.foAIstate.systemStatus.get( o_s_id, {}).get('planetThreat', 0))) for o_s_id in border_targets] totot_sys_threat = sum([thrt for sid, thrt in ot_sys_threat]) tot_cur_alloc = sum([ 0.8 * already_assigned_rating[sid] for sid, thrt in ot_sys_threat ]) for sid, thrt in ot_sys_threat: cur_alloc = already_assigned_rating[sid] needed_rating = rating_needed(1.2 * thrt, cur_alloc) this_alloc = 0 # only record more allocation for this invasion if we already started or have enough rating available take_any = False if needed_rating > 0 and (remaining_mil_rating > needed_rating or take_any): this_alloc = max(0, min(needed_rating, remaining_mil_rating)) new_alloc += this_alloc max_alloc = safety_factor * 2 * max( foAI.foAIstate.systemStatus.get(sid, {}).get( 'totalThreat', 0), foAI.foAIstate.systemStatus.get(sid, {}).get( 'neightborThreat', 0)) allocations.append((sid, this_alloc, take_any, max_alloc)) allocation_groups.setdefault('accessibleTargets', []).append( (sid, this_alloc, take_any, max_alloc)) remaining_mil_rating -= this_alloc ot_sys_alloc += this_alloc if "Main" in thisround or this_alloc > 0: if verbose_mil_reporting: print "Other Empire-Accessible system %4d ( %10s ) has local biased threat %8d ; existing military allocation %d and new allocation %8d" % ( sid, universe.getSystem(sid).name, thrt, cur_alloc, this_alloc) if "Main" in thisround or new_alloc > 0: if verbose_mil_reporting: print "-----------------" print "Other Empire-Accessible Systems under total biased threat: %d -- total mil allocation-- existing: %d ; new: %d" % ( totot_sys_threat, tot_cur_alloc, ot_sys_alloc) print "-----------------" elif "Main" in thisround: if verbose_mil_reporting: print "-----------------" print "No Other Empire-Accessible Systems with biased local threat " print "-----------------" # monster den treatment probably unnecessary now if "Main" in thisround: if verbose_mil_reporting: print print "Big-Monster Dens: %s" % ([ "| %d %s |" % (sys_id, universe.getSystem(sys_id).name) for sys_id in monster_dens ]) print "-----------------" # for these, calc fleet threat only, no neighbor threat, but use a multiplier for fleet safety new_alloc = 0 if monster_dens: ot_sys_alloc = 0 ot_sys_threat = [( o_s_id, safety_factor * (foAI.foAIstate.systemStatus.get(o_s_id, {}).get('fleetThreat', 0) + foAI.foAIstate.systemStatus.get(o_s_id, {}).get( 'monsterThreat', 0) + foAI.foAIstate.systemStatus.get( o_s_id, {}).get('planetThreat', 0))) for o_s_id in monster_dens] for sid, thrt in ot_sys_threat: cur_alloc = 0.8 * already_assigned_rating[sid] this_alloc = 0 if (thrt > cur_alloc) and remaining_mil_rating > 2 * thrt: this_alloc = int(0.99999 + (thrt - cur_alloc) * 1.5) new_alloc += this_alloc allocations.append((sid, this_alloc, False, 5)) remaining_mil_rating -= this_alloc ot_sys_alloc += this_alloc if "Main" in thisround or this_alloc > 0: if verbose_mil_reporting: print "Monster Den %4d ( %10s ) has local threat %8d ; existing military allocation %d and new allocation %8d" % ( sid, universe.getSystem(sid).name, thrt, cur_alloc, this_alloc) if "Main" in thisround or new_alloc > 0: if verbose_mil_reporting: print "-----------------" if remaining_mil_rating <= 6: new_allocations = [(sid, alc, alc, ta) for (sid, alc, ta, mm) in allocations] else: print "%s Round Remaining military strength allocation %d will be allocated as surplus allocation to top current priorities" % ( thisround, remaining_mil_rating) new_allocations = [] for cat in [ 'capitol', 'topTargets', 'otherTargets', 'accessibleTargets', 'occupied', 'exploreTargets' ]: for sid, alloc, take_any, max_alloc in allocation_groups.get( cat, []): if remaining_mil_rating <= 0: new_allocations.append((sid, alloc, alloc, take_any)) else: new_rating = min( remaining_mil_rating + alloc, max( alloc, rating_needed(max_alloc, already_assigned_rating[sid]))) new_allocations.append((sid, new_rating, alloc, take_any)) remaining_mil_rating -= (new_rating - alloc) if "Main" in thisround: military_allocations = new_allocations minMilAllocations.clear() minMilAllocations.update([(sid, alloc) for sid, alloc, take_any, mm in allocations]) if verbose_mil_reporting or "Main" in thisround: print "------------------------------\nFinal %s Round Military Allocations: %s \n-----------------------" % ( thisround, dict([(sid, alloc) for sid, alloc, minalloc, take_any in new_allocations])) # export military systems for other AI modules if "Main" in thisround: AIstate.militarySystemIDs = list( set([sid for sid, alloc, minalloc, take_any in new_allocations ]).union([ sid for sid in already_assigned_rating if already_assigned_rating[sid] > 0 ])) else: AIstate.militarySystemIDs = list( set([sid for sid, alloc, minalloc, take_any in new_allocations ]).union(AIstate.militarySystemIDs)) return new_allocations
def get_military_fleets(mil_fleets_ids=None, try_reset=True, thisround="Main"): """Get armed military fleets.""" global _military_allocations universe = fo.getUniverse() empire_id = fo.empireID() home_system_id = PlanetUtilsAI.get_capital_sys_id() all_military_fleet_ids = (mil_fleets_ids if mil_fleets_ids is not None else FleetUtilsAI.get_empire_fleet_ids_by_role(MissionType.MILITARY)) if try_reset and (fo.currentTurn() + empire_id) % 30 == 0 and thisround == "Main": try_again(all_military_fleet_ids, try_reset=False, thisround=thisround + " Reset") return mil_fleets_ids = list(FleetUtilsAI.extract_fleet_ids_without_mission_types(all_military_fleet_ids)) mil_needing_repair_ids, mil_fleets_ids = avail_mil_needing_repair(mil_fleets_ids, split_ships=True) avail_mil_rating = sum(map(CombatRatingsAI.get_fleet_rating, mil_fleets_ids)) if not mil_fleets_ids: if "Main" in thisround: _military_allocations = [] return [] # for each system, get total rating of fleets assigned to it already_assigned_rating = {} already_assigned_rating_vs_planets = {} systems_status = foAI.foAIstate.systemStatus enemy_sup_factor = {} # enemy supply for sys_id in universe.systemIDs: already_assigned_rating[sys_id] = 0 already_assigned_rating_vs_planets[sys_id] = 0 enemy_sup_factor[sys_id] = min(2, len(systems_status.get(sys_id, {}).get('enemies_nearly_supplied', []))) for fleet_id in [fid for fid in all_military_fleet_ids if fid not in mil_fleets_ids]: ai_fleet_mission = foAI.foAIstate.get_fleet_mission(fleet_id) if not ai_fleet_mission.target: # shouldn't really be possible continue last_sys = ai_fleet_mission.target.get_system().id # will count this fleet as assigned to last system in target list # TODO last_sys or target sys? this_rating = CombatRatingsAI.get_fleet_rating(fleet_id) this_rating_vs_planets = CombatRatingsAI.get_fleet_rating_against_planets(fleet_id) already_assigned_rating[last_sys] = CombatRatingsAI.combine_ratings( already_assigned_rating.get(last_sys, 0), this_rating) already_assigned_rating_vs_planets[last_sys] = CombatRatingsAI.combine_ratings( already_assigned_rating_vs_planets.get(last_sys, 0), this_rating_vs_planets) for sys_id in universe.systemIDs: my_defense_rating = systems_status.get(sys_id, {}).get('mydefenses', {}).get('overall', 0) already_assigned_rating[sys_id] = CombatRatingsAI.combine_ratings(my_defense_rating, already_assigned_rating[sys_id]) if _verbose_mil_reporting and already_assigned_rating[sys_id]: print "\t System %s already assigned rating %.1f" % ( universe.getSystem(sys_id), already_assigned_rating[sys_id]) # get systems to defend capital_id = PlanetUtilsAI.get_capital() if capital_id is not None: capital_planet = universe.getPlanet(capital_id) else: capital_planet = None # TODO: if no owned planets try to capture one! if capital_planet: capital_sys_id = capital_planet.systemID else: # should be rare, but so as to not break code below, pick a randomish mil-centroid system capital_sys_id = None # unless we can find one to use system_dict = {} for fleet_id in all_military_fleet_ids: status = foAI.foAIstate.fleetStatus.get(fleet_id, None) if status is not None: system_id = status['sysID'] if not list(universe.getSystem(system_id).planetIDs): continue system_dict[system_id] = system_dict.get(system_id, 0) + status.get('rating', 0) ranked_systems = sorted([(val, sys_id) for sys_id, val in system_dict.items()]) if ranked_systems: capital_sys_id = ranked_systems[-1][-1] else: try: capital_sys_id = foAI.foAIstate.fleetStatus.items()[0][1]['sysID'] except: pass num_targets = max(10, PriorityAI.allotted_outpost_targets) top_target_planets = ([pid for pid, pscore, trp in AIstate.invasionTargets[:PriorityAI.allotted_invasion_targets()] if pscore > MIN_INVASION_SCORE] + [pid for pid, (pscore, spec) in foAI.foAIstate.colonisableOutpostIDs.items()[:num_targets] if pscore > MIN_INVASION_SCORE] + [pid for pid, (pscore, spec) in foAI.foAIstate.colonisablePlanetIDs.items()[:num_targets] if pscore > MIN_INVASION_SCORE]) top_target_planets.extend(foAI.foAIstate.qualifyingTroopBaseTargets.keys()) base_col_target_systems = PlanetUtilsAI.get_systems(top_target_planets) top_target_systems = [] for sys_id in AIstate.invasionTargetedSystemIDs + base_col_target_systems: if sys_id not in top_target_systems: if foAI.foAIstate.systemStatus[sys_id]['totalThreat'] > get_tot_mil_rating(): continue top_target_systems.append(sys_id) # doing this rather than set, to preserve order try: # capital defense allocation_helper = AllocationHelper(already_assigned_rating, already_assigned_rating_vs_planets, avail_mil_rating, try_reset) if capital_sys_id is not None: CapitalDefenseAllocator(capital_sys_id, allocation_helper).allocate() # defend other planets empire_planet_ids = PlanetUtilsAI.get_owned_planets_by_empire(universe.planetIDs) empire_occupied_system_ids = list(set(PlanetUtilsAI.get_systems(empire_planet_ids)) - {capital_sys_id}) for sys_id in empire_occupied_system_ids: PlanetDefenseAllocator(sys_id, allocation_helper).allocate() # attack / protect high priority targets for sys_id in top_target_systems: TopTargetAllocator(sys_id, allocation_helper).allocate() # enemy planets other_targeted_system_ids = [sys_id for sys_id in set(PlanetUtilsAI.get_systems(AIstate.opponentPlanetIDs)) if sys_id not in top_target_systems] for sys_id in other_targeted_system_ids: TargetAllocator(sys_id, allocation_helper).allocate() # colony / outpost targets other_targeted_system_ids = [sys_id for sys_id in list(set(AIstate.colonyTargetedSystemIDs + AIstate.outpostTargetedSystemIDs)) if sys_id not in top_target_systems] for sys_id in other_targeted_system_ids: OutpostTargetAllocator(sys_id, allocation_helper).allocate() # TODO blockade enemy systems # interior systems targetable_ids = set(state.get_systems_by_supply_tier(0)) current_mil_systems = [sid for sid, _, _, _, _ in allocation_helper.allocations] interior_targets1 = targetable_ids.difference(current_mil_systems) interior_targets = [sid for sid in interior_targets1 if ( allocation_helper.threat_bias + systems_status.get(sid, {}).get('totalThreat', 0) > 0.8 * allocation_helper.already_assigned_rating[sid])] for sys_id in interior_targets: InteriorTargetsAllocator(sys_id, allocation_helper).allocate() # TODO Exploration targets # border protections visible_system_ids = foAI.foAIstate.visInteriorSystemIDs | foAI.foAIstate.visBorderSystemIDs accessible_system_ids = ([sys_id for sys_id in visible_system_ids if universe.systemsConnected(sys_id, home_system_id, empire_id)] if home_system_id != INVALID_ID else []) current_mil_systems = [sid for sid, alloc, rvp, take_any, _ in allocation_helper.allocations if alloc > 0] border_targets1 = [sid for sid in accessible_system_ids if sid not in current_mil_systems] border_targets = [sid for sid in border_targets1 if ( allocation_helper.threat_bias + systems_status.get(sid, {}).get('fleetThreat', 0) + systems_status.get(sid, {}).get( 'planetThreat', 0) > 0.8 * allocation_helper.already_assigned_rating[sid])] for sys_id in border_targets: BorderSecurityAllocator(sys_id, allocation_helper).allocate() except ReleaseMilitaryException: try_again(all_military_fleet_ids) return new_allocations = [] remaining_mil_rating = avail_mil_rating # for top categories assign max_alloc right away as available for cat in ['capitol', 'occupied', 'topTargets']: for sid, alloc, rvp, take_any, max_alloc in allocation_helper.allocation_by_groups.get(cat, []): if remaining_mil_rating <= 0: break this_alloc = min(remaining_mil_rating, max_alloc) new_allocations.append((sid, this_alloc, alloc, rvp, take_any)) remaining_mil_rating -= this_alloc base_allocs = set() # for lower priority categories, first assign base_alloc around to all, then top up as available for cat in ['otherTargets', 'accessibleTargets', 'exploreTargets']: for sid, alloc, rvp, take_any, max_alloc in allocation_helper.allocation_by_groups.get(cat, []): if remaining_mil_rating <= 0: break base_allocs.add(sid) remaining_mil_rating -= alloc for cat in ['otherTargets', 'accessibleTargets', 'exploreTargets']: for sid, alloc, rvp, take_any, max_alloc in allocation_helper.allocation_by_groups.get(cat, []): if sid not in base_allocs: break if remaining_mil_rating <= 0: new_allocations.append((sid, alloc, alloc, rvp, take_any)) else: new_rating = min(remaining_mil_rating + alloc, max_alloc) new_allocations.append((sid, new_rating, alloc, rvp, take_any)) remaining_mil_rating -= (new_rating - alloc) if "Main" in thisround: _military_allocations = new_allocations if _verbose_mil_reporting or "Main" in thisround: print "------------------------------\nFinal %s Round Military Allocations: %s \n-----------------------" % (thisround, dict([(sid, alloc) for sid, alloc, _, _, _ in new_allocations])) print "(Apparently) remaining military rating: %.1f" % remaining_mil_rating return new_allocations
def set_planet_resource_foci(): """set resource focus of planets """ newFoci = {} print "\n============================" print "Collecting info to assess Planet Focus Changes\n" universe = fo.getUniverse() empire = fo.getEmpire() currentTurn = fo.currentTurn() # set the random seed (based on galaxy seed, empire ID and current turn) # for game-reload consistency freq = min(3, (max(5, currentTurn - 80)) / 4.0)**(1.0 / 3) if not (limitAssessments and (abs(currentTurn - lastFociCheck[0]) < 1.5 * freq) and (random.random() < 1.0 / freq)): lastFociCheck[0] = currentTurn resource_timer.start("getPlanets") empirePlanetIDs = list( PlanetUtilsAI.get_owned_planets_by_empire(universe.planetIDs)) resource_timer.start("Filter") resource_timer.start("Priority") # TODO: take into acct splintering of resource groups # fleetSupplyableSystemIDs = empire.fleetSupplyableSystemIDs # fleetSupplyablePlanetIDs = PlanetUtilsAI.get_planets_in__systems_ids(fleetSupplyableSystemIDs) ppPrio = foAI.foAIstate.get_priority( AIPriorityType.PRIORITY_RESOURCE_PRODUCTION) rpPrio = foAI.foAIstate.get_priority( AIPriorityType.PRIORITY_RESOURCE_RESEARCH) priorityRatio = float(rpPrio) / (ppPrio + 0.0001) resource_timer.start("Shuffle") # not supporting Growth for general planets until also adding code to make sure would actually benefit # shuffle(generalPlanetIDs) resource_timer.start("Targets") planets = map(universe.getPlanet, empirePlanetIDs) planetMap.clear() planetMap.update(zip(empirePlanetIDs, planets)) if useGrowth: for metab, metabIncPop in ColonisationAI.empire_metabolisms.items( ): for special in [ aspec for aspec in AIDependencies.metabolismBoostMap.get( metab, []) if aspec in ColonisationAI.available_growth_specials ]: rankedPlanets = [] for pid in ColonisationAI.available_growth_specials[ special]: planet = planetMap[pid] cur_focus = planet.focus pop = planet.currentMeterValue(fo.meterType.population) if (pop > metabIncPop - 2 * planet.size) or ( GFocus not in planet.availableFoci ): # not enough benefit to lose local production, or can't put growth focus here continue for special2 in ["COMPUTRONIUM_SPECIAL"]: if special2 in planet.specials: break else: # didn't have any specials that would override interest in growth special print "Considering Growth Focus for %s (%d) with special %s; planet has pop %.1f and %s metabolism incremental pop is %.1f" % ( planet.name, pid, special, pop, metab, metabIncPop) if cur_focus == GFocus: pop -= 4 # discourage changing current focus to minimize focus-changing penalties rankedPlanets.append((pop, pid, cur_focus)) if not rankedPlanets: continue rankedPlanets.sort() print "Considering Growth Focus choice for special %s; possible planet pop, id pairs are %s" % ( metab, rankedPlanets) for spSize, spPID, cur_focus in rankedPlanets: # index 0 should be able to set focus, but just in case... result = 1 if cur_focus != GFocus: result = fo.issueChangeFocusOrder(spPID, GFocus) if result == 1: newFoci[spPID] = GFocus if spPID in empirePlanetIDs: del empirePlanetIDs[empirePlanetIDs.index( spPID)] print "%s focus of planet %s (%d) at Growth Focus" % ( ["set", "left"][cur_focus == GFocus], planetMap[spPID].name, spPID) break else: print "failed setting focus of planet %s (%d) at Growth Focus; focus left at %s" % ( planetMap[spPID].name, spPID, planetMap[spPID].focus) for pid in empirePlanetIDs: planet = planetMap[pid] if "COMPUTRONIUM_SPECIAL" in planet.specials: # TODO: ensure only one (extremely rarely needed) curFocus = planet.focus if RFocus not in planet.availableFoci: continue newFoci[pid] = RFocus result = 0 if curFocus != RFocus: result = fo.issueChangeFocusOrder(pid, RFocus) if result == 1: universe.updateMeterEstimates(empirePlanetIDs) if curFocus == RFocus or result == 1: print "%s focus of planet %s (%d) (with Computronium Moon) at Research Focus" % ( ["set", "left" ][curFocus == RFocus], planetMap[pid].name, pid) if pid in empirePlanetIDs: del empirePlanetIDs[empirePlanetIDs.index(pid)] elif (([ bld.buildingTypeName for bld in map(universe.getObject, planet.buildingIDs) if bld.buildingTypeName in ["BLD_CONC_CAMP", "BLD_CONC_CAMP_REMNANT"] ] != []) or ([ ccspec for ccspec in planet.specials if ccspec in ["CONC_CAMP_MASTER_SPECIAL", "CONC_CAMP_SLAVE_SPECIAL"] ] != [])): if IFocus not in planet.availableFoci: continue curFocus = planet.focus newFoci[pid] = IFocus result = 0 if curFocus != IFocus: result = fo.issueChangeFocusOrder(pid, IFocus) if result == 1: print( "Tried setting %s for Concentration Camp planet %s (%d) with species %s and current focus %s, got result %d and focus %s" % (newFoci[pid], planet.name, pid, planet.speciesName, curFocus, result, planetMap[pid].focus)) universe.updateMeterEstimates(empirePlanetIDs) if (result != 1) or planetMap[pid].focus != IFocus: newplanet = universe.getPlanet(pid) print( "Error: Failed setting %s for Concentration Camp planet %s (%d) with species %s and current focus %s, but new planet copy shows %s" % (newFoci[pid], planetMap[pid].name, pid, planetMap[pid].speciesName, planetMap[pid].focus, newplanet.focus)) if curFocus == IFocus or result == 1: print "%s focus of planet %s (%d) (with Concentration Camps/Remnants) at Industry Focus" % ( ["set", "left" ][curFocus == IFocus], planetMap[pid].name, pid) if pid in empirePlanetIDs: del empirePlanetIDs[empirePlanetIDs.index(pid)] # pp, rp = get_resource_target_totals(empirePlanetIDs, planetMap) pp, rp = get_resource_target_totals(planetMap.keys()) print "\n-----------------------------------------" print "Making Planet Focus Change Determinations\n" ratios = [] # for each planet, calculate RP:PP value ratio at which industry/Mining focus and research focus would have the same total value, & sort by that # include a bias to slightly discourage changing foci curTargetPP = 0.001 curTargetRP = 0.001 resource_timer.start("Loop") # loop has_force = tech_is_complete("CON_FRC_ENRG_STRC") preset_ids = set(planetMap.keys()) - set(empirePlanetIDs) ctPP0, ctRP0 = 0, 0 for pid in preset_ids: nPP, nRP = newTargets.get(pid, {}).get(planetMap[pid].focus, [0, 0]) curTargetPP += nPP curTargetRP += nRP iPP, iRP = newTargets.get(pid, {}).get(IFocus, [0, 0]) ctPP0 += iPP ctRP0 += iRP id_set = set(empirePlanetIDs) for adj_round in [1, 2, 3, 4]: maxi_ratio = ctRP0 / max( 0.01, ctPP0) # should only change between rounds 1 and 2 for pid in list(id_set): if adj_round == 1: # tally max Industry iPP, iRP = newTargets.get(pid, {}).get(IFocus, [0, 0]) ctPP0 += iPP ctRP0 += iRP continue II, IR = newTargets[pid][IFocus] RI, RR = newTargets[pid][RFocus] CI, CR = currentOutput[pid][IFocus], currentOutput[pid][RFocus] research_penalty = (currentFocus[pid] != RFocus) # calculate factor F at which II + F * IR == RI + F * RR =====> F = ( II-RI ) / (RR-IR) thisFactor = (II - RI) / max( 0.01, RR - IR ) # don't let denominator be zero for planets where focus doesn't change RP planet = planetMap[pid] if adj_round == 2: # take research at planets with very cheap research if (maxi_ratio < priorityRatio) and ( curTargetRP < priorityRatio * ctPP0) and (thisFactor <= 1.0): curTargetPP += RI curTargetRP += RR newFoci[pid] = RFocus id_set.discard(pid) continue if adj_round == 3: # take research at planets where can do reasonable balance if has_force or (foAI.foAIstate.aggression < fo.aggression.aggressive) or ( curTargetRP >= priorityRatio * ctPP0): continue pop = planet.currentMeterValue(fo.meterType.population) t_pop = planet.currentMeterValue( fo.meterType.targetPopulation) # if AI is aggressive+, and this planet in range where temporary Research focus can get an additional RP at cost of 1 PP, and still need some RP, then do it if pop < t_pop - 5: continue if (CI > II + 8) or (((RR > II) or ( (RR - CR) >= 1 + 2 * research_penalty)) and ((RR - IR) >= 3) and ((CR - IR) >= 0.7 * ((II - CI) * (1 + 0.1 * research_penalty)))): curTargetPP += CI - 1 - research_penalty curTargetRP += CR + 1 newFoci[pid] = RFocus id_set.discard(pid) continue # adj_round == 4 assume default IFocus curTargetPP += II # icurTargets initially calculated by Industry focus, which will be our default focus curTargetRP += IR newFoci[pid] = IFocus ratios.append((thisFactor, pid)) ratios.sort() printedHeader = False fociMap = { IFocus: "Industry", RFocus: "Research", MFocus: "Mining", GFocus: "Growth" } gotAlgo = tech_is_complete("LRN_ALGO_ELEGANCE") for ratio, pid in ratios: do_research = False # (newFoci[pid]==RFocus) if (priorityRatio < (curTargetRP / (curTargetPP + 0.0001)) ) and not do_research: # we have enough RP if ratio < 1.1 and foAI.foAIstate.aggression > fo.aggression.cautious: # but wait, RP is still super cheap relative to PP, maybe will take more RP if priorityRatio < 1.5 * ( curTargetRP / (curTargetPP + 0.0001) ): # yeah, really a glut of RP, stop taking RP break else: # RP not super cheap & we have enough, stop taking it break II, IR = newTargets[pid][IFocus] RI, RR = newTargets[pid][RFocus] # if currentFocus[pid] == MFocus: # II = max( II, newTargets[pid][MFocus][0] ) if do_research or ( gotAlgo and ((ratio > 2.0 and curTargetPP < 15) or (ratio > 2.5 and curTargetPP < 25 and II > 5) or (ratio > 3.0 and curTargetPP < 40 and II > 5) or (ratio > 4.0 and curTargetPP < 100 and II > 10) or ((curTargetRP + RR - IR) / max(0.001, curTargetPP - II + RI) > 2 * priorityRatio)) ): # we already have algo elegance and more RP would be too expensive, or overkill if not printedHeader: printedHeader = True print "Rejecting further Research Focus choices as too expensive:" print "%34s|%20s|%15s |%15s|%15s |%15s |%15s" % ( " Planet ", " current RP/PP ", " current target RP/PP ", "current Focus ", " rejectedFocus ", " rejected target RP/PP ", "rejected RP-PP EQF") oldFocus = currentFocus[pid] cPP, cRP = currentOutput[pid][IFocus], currentOutput[pid][ RFocus] otPP, otRP = newTargets[pid].get(oldFocus, (0, 0)) ntPP, ntRP = newTargets[pid].get(RFocus, (0, 0)) print "pID (%3d) %22s | c: %5.1f / %5.1f | cT: %5.1f / %5.1f | cF: %8s | nF: %8s | cT: %5.1f / %5.1f | %.2f" % ( pid, planetMap[pid].name, cRP, cPP, otRP, otPP, fociMap.get(oldFocus, 'unknown'), fociMap[RFocus], ntRP, ntPP, ratio) continue # RP is getting too expensive, but might be willing to still allocate from a planet with less PP to lose # if planetMap[pid].currentMeterValue(fo.meterType.targetPopulation) >0: #only set to research if pop won't die out newFoci[pid] = RFocus curTargetRP += (RR - IR) curTargetPP -= (II - RI) print "============================" print "Planet Focus Assignments to achieve target RP/PP ratio of %.2f from current ratio of %.2f ( %.1f / %.1f )" % ( priorityRatio, rp / (pp + 0.0001), rp, pp) print "Max Industry assignments would result in target RP/PP ratio of %.2f ( %.1f / %.1f )" % ( ctRP0 / (ctPP0 + 0.0001), ctRP0, ctPP0) print "-------------------------------------" print "%34s|%20s|%15s |%15s|%15s |%15s " % ( " Planet ", " current RP/PP ", " current target RP/PP ", "current Focus ", " newFocus ", " new target RP/PP ") totalChanged = 0 for id_set in empirePlanetIDs, preset_ids: for pid in id_set: canFocus = planetMap[pid].currentMeterValue( fo.meterType.targetPopulation) > 0 oldFocus = currentFocus[pid] newFocus = newFoci.get(pid, IFocus) cPP, cRP = currentOutput[pid][IFocus], currentOutput[pid][ RFocus] otPP, otRP = newTargets[pid].get(oldFocus, (0, 0)) ntPP, ntRP = otPP, otRP if newFocus != oldFocus and newFocus in planetMap[ pid].availableFoci: # planetMap[pid].focus totalChanged += 1 if newFocus != planetMap[pid].focus: result = fo.issueChangeFocusOrder(pid, newFocus) if result == 1: ntPP, ntRP = newTargets[pid].get(newFocus, (0, 0)) else: print "Trouble changing focus of planet %s (%d) to %s" % ( planetMap[pid].name, pid, newFocus) print "pID (%3d) %22s | c: %5.1f / %5.1f | cT: %5.1f / %5.1f | cF: %8s | nF: %8s | cT: %5.1f / %5.1f " % ( pid, planetMap[pid].name, cRP, cPP, otRP, otPP, fociMap.get(oldFocus, 'unknown'), fociMap[newFocus], ntRP, ntPP) print "-------------------------------------" print "-------------------------------------" print "Final Ratio Target (turn %4d) RP/PP : %.2f ( %.1f / %.1f ) after %d Focus changes" % ( fo.currentTurn(), curTargetRP / (curTargetPP + 0.0001), curTargetRP, curTargetPP, totalChanged) resource_timer.end() aPP, aRP = empire.productionPoints, empire.resourceProduction( fo.resourceType.research) # Next string used in charts. Don't modify it! print "Current Output (turn %4d) RP/PP : %.2f ( %.1f / %.1f )" % ( fo.currentTurn(), aRP / (aPP + 0.0001), aRP, aPP) print "------------------------" print "ResourcesAI Time Requirements:"
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()
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()