def issue_order(self): if not super(OrderResupply, self).issue_order(): return fleet_id = self.fleet.id system_id = self.target.get_system().id fleet = self.fleet.get_object() if system_id not in [fleet.systemID, fleet.nextSystemID]: # if self.order_type == AIFleetOrderType.ORDER_MOVE: # dest_id = system_id # else: # if self.order_type == AIFleetOrderType.ORDER_REPAIR: # fo.issueAggressionOrder(fleet_id, False) start_id = FleetUtilsAI.get_fleet_system(fleet) dest_id = MoveUtilsAI.get_safe_path_leg_to_dest(fleet_id, start_id, system_id) print "fleet %d with order type(%s) sent to safe leg dest %s and ultimate dest %s" % ( fleet_id, self.ORDER_NAME, PlanetUtilsAI.sys_name_ids([dest_id]), PlanetUtilsAI.sys_name_ids([system_id])) fo.issueFleetMoveOrder(fleet_id, dest_id) print "Order issued: %s fleet: %s target: %s" % (self.ORDER_NAME, self.fleet, self.target) if system_id == fleet.systemID: if foAI.foAIstate.get_fleet_role(fleet_id) == MissionType.EXPLORATION: if system_id in foAI.foAIstate.needsEmergencyExploration: foAI.foAIstate.needsEmergencyExploration.remove(system_id) self.order_issued = True
def __border_exploration_update(self): universe = fo.getUniverse() exploration_center = PlanetUtilsAI.get_capital_sys_id() # a bad state probably from an old savegame, or else empire has lost (or almost has) if exploration_center == INVALID_ID: exploration_center = self.__origin_home_system_id ExplorationAI.graph_flags.clear() if fo.currentTurn() < 50: print "-------------------------------------------------" print "Border Exploration Update (relative to %s)" % ( PlanetUtilsAI.sys_name_ids([exploration_center, INVALID_ID])[0]) print "-------------------------------------------------" if self.visBorderSystemIDs == {INVALID_ID}: self.visBorderSystemIDs.clear() self.visBorderSystemIDs.add(exploration_center) for sys_id in list(self.visBorderSystemIDs): # This set is modified during iteration. if fo.currentTurn() < 50: print "Considering border system %s" % (PlanetUtilsAI.sys_name_ids([sys_id, INVALID_ID])[0]) ExplorationAI.follow_vis_system_connections(sys_id, exploration_center) newly_explored = ExplorationAI.update_explored_systems() nametags = [] for sys_id in newly_explored: newsys = universe.getSystem(sys_id) # an explored system *should* always be able to be gotten nametags.append("ID:%4d -- %-20s" % (sys_id, (newsys and newsys.name) or "name unknown")) if newly_explored: print "-------------------------------------------------" print "Newly explored systems:\n%s" % "\n".join(nametags) print "-------------------------------------------------"
def getInvasionFleets(): "get invasion fleets" allInvasionFleetIDs = FleetUtilsAI.getEmpireFleetIDsByRole(AIFleetMissionType.FLEET_MISSION_INVASION) AIstate.invasionFleetIDs = FleetUtilsAI.extractFleetIDsWithoutMissionTypes(allInvasionFleetIDs) # get supplyable planets universe = fo.getUniverse() empire = fo.getEmpire() empireID = empire.empireID fleetSupplyableSystemIDs = empire.fleetSupplyableSystemIDs fleetSupplyablePlanetIDs = PlanetUtilsAI.getPlanetsInSystemsIDs(fleetSupplyableSystemIDs) # get competitor planets exploredSystemIDs = empire.exploredSystemIDs exploredPlanetIDs = PlanetUtilsAI.getPlanetsInSystemsIDs(exploredSystemIDs) allOwnedPlanetIDs = PlanetUtilsAI.getAllOwnedPlanetIDs(exploredPlanetIDs) # print "All Owned and Populated PlanetIDs: " + str(allOwnedPlanetIDs) empireOwnedPlanetIDs = PlanetUtilsAI.getOwnedPlanetsByEmpire(universe.planetIDs, empireID) # print "Empire Owned PlanetIDs: " + str(empireOwnedPlanetIDs) competitorPlanetIDs = list(set(allOwnedPlanetIDs) - set(empireOwnedPlanetIDs)) print "Competitor PlanetIDs: " + str(competitorPlanetIDs) print "" print "Invasion Targeted SystemIDs: " + str(AIstate.invasionTargetedSystemIDs) invasionTargetedPlanetIDs = getInvasionTargetedPlanetIDs(universe.planetIDs, AIFleetMissionType.FLEET_MISSION_INVASION, empireID) allInvasionTargetedSystemIDs = PlanetUtilsAI.getSystems(invasionTargetedPlanetIDs) # export invasion targeted systems for other AI modules AIstate.invasionTargetedSystemIDs = allInvasionTargetedSystemIDs print "Invasion Targeted PlanetIDs: " + str(invasionTargetedPlanetIDs) invasionFleetIDs = FleetUtilsAI.getEmpireFleetIDsByRole(AIFleetMissionType.FLEET_MISSION_INVASION) if not invasionFleetIDs: print "Available Invasion Fleets: 0" else: print "Invasion FleetIDs: " + str(FleetUtilsAI.getEmpireFleetIDsByRole(AIFleetMissionType.FLEET_MISSION_INVASION)) numInvasionFleets = len(FleetUtilsAI.extractFleetIDsWithoutMissionTypes(invasionFleetIDs)) print "Invasion Fleets Without Missions: " + str(numInvasionFleets) evaluatedPlanetIDs = list(set(competitorPlanetIDs) - set(invasionTargetedPlanetIDs)) # print "Evaluated PlanetIDs: " + str(evaluatedPlanetIDs) evaluatedPlanets = assignInvasionValues(evaluatedPlanetIDs, AIFleetMissionType.FLEET_MISSION_INVASION, fleetSupplyablePlanetIDs, empire) sortedPlanets = evaluatedPlanets.items() sortedPlanets.sort(lambda x, y: cmp(x[1], y[1]), reverse=True) print "" print "Invadable planetIDs:" for evaluationPair in sortedPlanets: print " ID|Score: " + str(evaluationPair) # export opponent planets for other AI modules AIstate.opponentPlanetIDs = sortedPlanets
def setCapitalIDResourceFocus(): "set resource focus of CapitalID planet" universe = fo.getUniverse() empire = fo.getEmpire() empireID = empire.empireID empirePlanetIDs = PlanetUtilsAI.getOwnedPlanetsByEmpire(universe.planetIDs, empireID) capitalID = PlanetUtilsAI.getCapital() topPriority = topResourcePriority() if topPriority == AIPriorityType.PRIORITY_RESOURCE_GROWTH: newFocus = AIFocusType.FOCUS_GROWTH for planetID in empirePlanetIDs: planet = universe.getPlanet(planetID) focus = newFocus if planetID == capitalID and focus in planet.availableFoci: fo.issueChangeFocusOrder(planetID, focus) elif topPriority == AIPriorityType.PRIORITY_RESOURCE_PRODUCTION: newFocus = AIFocusType.FOCUS_INDUSTRY for planetID in empirePlanetIDs: planet = universe.getPlanet(planetID) focus = newFocus if planetID == capitalID and focus in planet.availableFoci: fo.issueChangeFocusOrder(planetID, focus) elif topPriority == AIPriorityType.PRIORITY_RESOURCE_RESEARCH: newFocus = AIFocusType.FOCUS_RESEARCH for planetID in empirePlanetIDs: planet = universe.getPlanet(planetID) focus = newFocus if planetID == capitalID and focus in planet.availableFoci: fo.issueChangeFocusOrder(planetID, focus)
def calculateMilitaryPriority(): "calculates the demand for military ships by military targeted systems" global unmetThreat universe = fo.getUniverse() empire = fo.getEmpire() empireID = empire.empireID capitalID = PlanetUtilsAI.getCapital() if capitalID is not None and capitalID != -1: homeworld = universe.getPlanet(capitalID) else: return 0# no capitol (not even a capitol-in-the-making), means can't produce any ships have_mod_weaps = ( empire.getTechStatus("SHP_WEAPON_1_4") == fo.techStatus.complete or empire.getTechStatus("SHP_WEAPON_2_1") == fo.techStatus.complete or empire.getTechStatus("SHP_WEAPON_4_1") == fo.techStatus.complete ) allottedInvasionTargets = 1+ int(fo.currentTurn()/25) targetPlanetIDs = [pid for pid, pscore, trp in AIstate.invasionTargets[:allottedInvasionTargets] ] + [pid for pid, pscore in foAI.foAIstate.colonisablePlanetIDs[:allottedColonyTargets] ] + [pid for pid, pscore in foAI.foAIstate.colonisableOutpostIDs[:allottedColonyTargets] ] mySystems = set( AIstate.popCtrSystemIDs ).union( AIstate.outpostSystemIDs ) targetSystems = set( PlanetUtilsAI.getSystems(targetPlanetIDs) ) curShipRating = ProductionAI.curBestMilShipRating() cSRR = curShipRating**0.5 unmetThreat = 0.0 currentTurn=fo.currentTurn() shipsNeeded=0 defenses_needed = 0 for sysID in mySystems.union(targetSystems) : status=foAI.foAIstate.systemStatus.get( sysID, {} ) myRating = status.get('myFleetRating', 0) my_defenses = status.get('mydefenses', {}).get('overall', 0) baseMonsterThreat = status.get('monsterThreat', 0) #scale monster threat so that in early - mid game big monsters don't over-drive military production if currentTurn>200: monsterThreat = baseMonsterThreat elif currentTurn>100: if baseMonsterThreat <2000: monsterThreat = baseMonsterThreat else: monsterThreat = 2000 + (currentTurn/100.0 - 1) *(baseMonsterThreat-2000) else: monsterThreat = 0 if sysID in mySystems: threatRoot = status.get('fleetThreat', 0)**0.5 + 0.8*status.get('max_neighbor_threat', 0)**0.5 + 0.2*status.get('neighborThreat', 0)**0.5 + monsterThreat**0.5 + status.get('planetThreat', 0)**0.5 else: threatRoot = status.get('fleetThreat', 0)**0.5 + monsterThreat**0.5 + status.get('planetThreat', 0)**0.5 shipsNeeded += math.ceil(( max(0, (threatRoot - (myRating**0.5 + my_defenses**0.5)))**2)/curShipRating) #militaryPriority = int( 40 + max(0, 75*unmetThreat / curShipRating) ) militaryPriority = int( 40 + max(0, 75*shipsNeeded) ) if not have_mod_weaps: militaryPriority /= 2 #print "Calculating Military Priority: 40 + 75 * unmetThreat/curShipRating \n\t Priority: %d \t unmetThreat %.0f curShipRating: %.0f"%(militaryPriority, unmetThreat, curShipRating) print "Calculating Military Priority: 40 + 75 * shipsNeeded \n\t Priority: %d \t shipsNeeded %d \t unmetThreat %.0f curShipRating: %.0f"%(militaryPriority, shipsNeeded, unmetThreat, curShipRating) return max( militaryPriority, 0)
def calculateMilitaryPriority(): "calculates the demand for military ships by military targeted systems" universe = fo.getUniverse() empire = fo.getEmpire() empireID = empire.empireID capitalID = PlanetUtilsAI.getCapital() if capitalID: homeworld = universe.getPlanet(capitalID) else: return 0# no capitol (not even a capitol-in-the-making), means can't produce any ships allottedInvasionTargets = 1+ int(fo.currentTurn()/25) targetPlanetIDs = [pid for pid, pscore, trp in AIstate.invasionTargets[:allottedInvasionTargets] ] + [pid for pid, pscore in foAI.foAIstate.colonisablePlanetIDs[:allottedColonyTargets] ] + [pid for pid, pscore in foAI.foAIstate.colonisableOutpostIDs[:allottedColonyTargets] ] mySystems = set( AIstate.popCtrSystemIDs ).union( AIstate.outpostSystemIDs ) targetSystems = set( PlanetUtilsAI.getSystems(targetPlanetIDs) ) curShipRating = ProductionAI.curBestMilShipRating() cSRR = curShipRating**0.5 unmetThreat = 0.0 currentTurn=fo.currentTurn() shipsNeeded=0 for sysID in mySystems.union(targetSystems) : status=foAI.foAIstate.systemStatus.get( sysID, {} ) myAttack, myHealth =0, 0 for fid in status.get('myfleets', []) : rating= foAI.foAIstate.fleetStatus.get(fid, {}).get('rating', {}) myAttack += rating.get('attack', 0) myHealth += rating.get('health', 0) myRating = myAttack*myHealth baseMonsterThreat = status.get('monsterThreat', 0) if currentTurn>200: monsterThreat = baseMonsterThreat elif currentTurn>100: if baseMonsterThreat <2000: monsterThreat = baseMonsterThreat else: monsterThreat = 2000 + (currentTurn/100.0 - 1) *(baseMonsterThreat-2000) else: monsterThreat = 0 threatRoot = status.get('fleetThreat', 0)**0.5 + status.get('planetThreat', 0)**0.5 + monsterThreat**0.5 if sysID in mySystems: threatRoot += (0.3* status.get('neighborThreat', 0))**0.5 else: threatRoot += (0.1* status.get('neighborThreat', 0))**0.5 threat = threatRoot**2 unmetThreat += max( 0, threat - myRating ) shipsNeeded += math.ceil( max(0, (threatRoot/cSRR)- (myRating/curShipRating)**0.5 ) ) #militaryPriority = int( 40 + max(0, 75*unmetThreat / curShipRating) ) militaryPriority = int( 40 + max(0, 75*shipsNeeded) ) #print "Calculating Military Priority: 40 + 75 * unmetThreat/curShipRating \n\t Priority: %d \t unmetThreat %.0f curShipRating: %.0f"%(militaryPriority, unmetThreat, curShipRating) print "Calculating Military Priority: 40 + 75 * shipsNeeded \n\t Priority: %d \t shipsNeeded %d \t unmetThreat %.0f curShipRating: %.0f"%(militaryPriority, shipsNeeded, unmetThreat, curShipRating) return max( militaryPriority, 0)
def getColonyFleets(): # get colony fleets allColonyFleetIDs = FleetUtilsAI.getEmpireFleetIDsByRole(AIFleetMissionType.FLEET_MISSION_COLONISATION) AIstate.colonyFleetIDs = FleetUtilsAI.extractFleetIDsWithoutMissionTypes(allColonyFleetIDs) # get supplyable systems empire = fo.getEmpire() universe = fo.getUniverse() capitalID = empire.capitalID homeworld = universe.getPlanet(capitalID) speciesName = homeworld.speciesName species = fo.getSpecies(speciesName) fleetSupplyableSystemIDs = empire.fleetSupplyableSystemIDs fleetSupplyablePlanetIDs = PlanetUtilsAI.getPlanetsInSystemsIDs(fleetSupplyableSystemIDs) print " fleetSupplyablePlanetIDs:" + str(fleetSupplyablePlanetIDs) # get planets systemIDs = foAI.foAIstate.getExplorableSystems(AIExplorableSystemType.EXPLORABLE_SYSTEM_EXPLORED) planetIDs = PlanetUtilsAI.getPlanetsInSystemsIDs(systemIDs) removeAlreadyOwnedPlanetIDs(planetIDs, AIFleetMissionType.FLEET_MISSION_COLONISATION) removeAlreadyOwnedPlanetIDs(planetIDs, AIFleetMissionType.FLEET_MISSION_OUTPOST) evaluatedPlanets = assignColonisationValues(planetIDs, AIFleetMissionType.FLEET_MISSION_COLONISATION, fleetSupplyablePlanetIDs, species, empire) removeLowValuePlanets(evaluatedPlanets) sortedPlanets = evaluatedPlanets.items() sortedPlanets.sort(lambda x, y: cmp(x[1], y[1]), reverse=True) print "Colonisable planets:" for evaluationPair in sortedPlanets: print " ID|Score: " + str(evaluationPair) print "" # export planets for other AI modules AIstate.colonisablePlanetIDs = sortedPlanets # get outpost fleets allOutpostFleetIDs = FleetUtilsAI.getEmpireFleetIDsByRole(AIFleetMissionType.FLEET_MISSION_OUTPOST) AIstate.outpostFleetIDs = FleetUtilsAI.extractFleetIDsWithoutMissionTypes(allOutpostFleetIDs) evaluatedOutposts = assignColonisationValues(planetIDs, AIFleetMissionType.FLEET_MISSION_OUTPOST, fleetSupplyablePlanetIDs, species, empire) removeLowValuePlanets(evaluatedOutposts) sortedOutposts = evaluatedOutposts.items() sortedOutposts.sort(lambda x, y: cmp(x[1], y[1]), reverse=True) print "Colonisable outposts:" for evaluationPair in sortedOutposts: print " ID|Score: " + str(evaluationPair) print "" # export outposts for other AI modules AIstate.colonisableOutpostIDs = sortedOutposts
def get_safe_path_leg_to_dest(fleet_id, start_id, dest_id): start_targ = AITarget.AITarget(AITargetType.TARGET_SYSTEM, start_id) dest_targ = AITarget.AITarget(AITargetType.TARGET_SYSTEM, dest_id) #TODO actually get a safe path this_path = canTravelToSystem(fleet_id, start_targ, dest_targ, fo.empireID(), ensure_return=False) path_ids = [ targ.target_id for targ in this_path if targ.target_id != start_id] + [start_id] start_info = PlanetUtilsAI.sysNameIDs([start_id]) dest_info = PlanetUtilsAI.sysNameIDs([dest_id]) path_info = [ PlanetUtilsAI.sysNameIDs([sys_id]) for sys_id in path_ids] print "Fleet %d requested safe path leg from %s to %s, found path %s"%(fleet_id, start_info, dest_info , path_info) return path_ids[0]
def get_safe_path_leg_to_dest(fleet_id, start_id, dest_id): start_targ = universe_object.System(start_id) dest_targ = universe_object.System(dest_id) # TODO actually get a safe path this_path = can_travel_to_system(fleet_id, start_targ, dest_targ, ensure_return=False) path_ids = [targ.id for targ in this_path if targ.id != start_id] + [start_id] start_info = PlanetUtilsAI.sys_name_ids([start_id]) dest_info = PlanetUtilsAI.sys_name_ids([dest_id]) path_info = [PlanetUtilsAI.sys_name_ids([sys_id]) for sys_id in path_ids] print "Fleet %d requested safe path leg from %s to %s, found path %s" % (fleet_id, ppstring(start_info), ppstring(dest_info), ppstring(path_info)) return path_ids[0]
def getResourceTargetTotals(): universe = fo.getUniverse() empire = fo.getEmpire() empireID = empire.empireID empirePlanetIDs = PlanetUtilsAI.getOwnedPlanetsByEmpire(universe.planetIDs, empireID) capitalID = PlanetUtilsAI.getCapital() # planet = universe.getPlanet(planetID) # if planet.currentMeterValue(fo.meterType.population) >0: planets = map(universe.getPlanet, empirePlanetIDs) planetMap = dict( zip( empirePlanetIDs, planets)) oldTargets.clear() oldTargets.update(newTargets) newTargets.clear() currentFocus.clear() currentOutput.clear() targetPP = sum( map( lambda x: x.currentMeterValue(fo.meterType.targetIndustry), planets) ) targetRP = sum( map( lambda x: x.currentMeterValue(fo.meterType.targetResearch), planets) ) newFocus= IFocus for pid in empirePlanetIDs: canFocus= planetMap[pid].currentMeterValue(fo.meterType.targetPopulation) >0 currentFocus[pid] = planetMap[pid].focus #if currentFocus[pid] == MFocus: # mtarget=planetMap[pid].currentMeterValue(fo.meterType.targetIndustry) currentOutput.setdefault(pid, {} )[ IFocus] = planetMap[pid].currentMeterValue(fo.meterType.industry) currentOutput[pid][ RFocus] = planetMap[pid].currentMeterValue(fo.meterType.research) if canFocus: fo.issueChangeFocusOrder(pid, IFocus) #may not be able to take, but try universe.updateMeterEstimates(empirePlanetIDs) for pid in empirePlanetIDs: canFocus= planetMap[pid].currentMeterValue(fo.meterType.targetPopulation) >0 itarget=planetMap[pid].currentMeterValue(fo.meterType.targetIndustry) rtarget=planetMap[pid].currentMeterValue(fo.meterType.targetResearch) newTargets.setdefault(pid, {}).setdefault(IFocus, (0, 0)) newTargets[pid][IFocus] = ( itarget, rtarget ) #if currentFocus[pid] == MFocus: # newTargets[pid][MFocus] = ( mtarget, rtarget ) if canFocus: fo.issueChangeFocusOrder(pid, RFocus) #may not be able to take, but try universe.updateMeterEstimates(empirePlanetIDs) for pid in empirePlanetIDs: canFocus= planetMap[pid].currentMeterValue(fo.meterType.targetPopulation) >0 itarget=planetMap[pid].currentMeterValue(fo.meterType.targetIndustry) rtarget=planetMap[pid].currentMeterValue(fo.meterType.targetResearch) newTargets.setdefault(pid, {}).setdefault(RFocus, (0, 0)) newTargets[pid][RFocus] = ( itarget, rtarget ) if canFocus and currentFocus[pid] != RFocus: fo.issueChangeFocusOrder(pid, currentFocus[pid]) #put it back to what it was universe.updateMeterEstimates(empirePlanetIDs) return targetPP, targetRP
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 refresh(self): """Turn start AIstate cleanup/refresh.""" universe = fo.getUniverse() # checks exploration border & clears roles/missions of missing fleets & updates fleet locs & threats fleetsLostBySystem.clear() invasionTargets[:] = [] exploration_center = PlanetUtilsAI.get_capital_sys_id() # a bad state probably from an old savegame, or else empire has lost (or almost has) if exploration_center == INVALID_ID: exploration_center = self.__origin_home_system_id for system_id, info in sorted(self.systemStatus.items()): self.systemStatus[system_id][ 'enemy_ship_count'] = 0 # clear now in prep for update_system_status() ExplorationAI.graph_flags.clear() if fo.currentTurn() < 50: print "-------------------------------------------------" print "Border Exploration Update (relative to %s)" % ( PlanetUtilsAI.sys_name_ids([exploration_center, INVALID_ID ])[0]) print "-------------------------------------------------" if self.visBorderSystemIDs == {INVALID_ID}: self.visBorderSystemIDs.clear() self.visBorderSystemIDs.add(exploration_center) for sys_id in list(self.visBorderSystemIDs ): # This set is modified during iteration. if fo.currentTurn() < 50: print "Considering border system %s" % ( PlanetUtilsAI.sys_name_ids([sys_id, INVALID_ID])[0]) ExplorationAI.follow_vis_system_connections( sys_id, exploration_center) newly_explored = ExplorationAI.update_explored_systems() nametags = [] for sys_id in newly_explored: newsys = universe.getSystem(sys_id) # an explored system *should* always be able to be gotten nametags.append("ID:%4d -- %-20s" % (sys_id, (newsys and newsys.name) or "name unknown")) if newly_explored: print "-------------------------------------------------" print "Newly explored systems:\n%s" % "\n".join(nametags) print "-------------------------------------------------" # cleanup fleet roles # self.update_fleet_locs() self.__clean_fleet_roles() self.__clean_fleet_missions(FleetUtilsAI.get_empire_fleet_ids()) print "Fleets lost by system: %s" % fleetsLostBySystem self.update_system_status()
def avail_mil_needing_repair(mil_fleet_ids, split_ships=False, on_mission=False): """returns tuple of lists-- ( ids_needing_repair, ids_not )""" fleet_buckets = [[], []] universe = fo.getUniverse() cutoff = [0.70, 0.25][on_mission] for fleet_id in mil_fleet_ids: fleet = universe.getFleet(fleet_id) ship_buckets = [[], []] ships_cur_health = [0, 0] ships_max_health = [0, 0] for ship_id in fleet.shipIDs: this_ship = universe.getShip(ship_id) cur_struc = this_ship.currentMeterValue(fo.meterType.structure) max_struc = this_ship.currentMeterValue(fo.meterType.maxStructure) ship_ok = cur_struc >= cutoff * max_struc ship_buckets[ship_ok].append(ship_id) ships_cur_health[ship_ok] += cur_struc ships_max_health[ship_ok] += max_struc this_sys_id = (fleet.nextSystemID != -1 and fleet.nextSystemID) or fleet.systemID fleet_ok = (sum(ships_cur_health) >= cutoff * sum(ships_max_health)) local_status = foAI.foAIstate.systemStatus.get(this_sys_id, {}) my_local_rating = combine_ratings( local_status.get('mydefenses', {}).get('overall', 0), local_status.get('myFleetRating', 0)) needed_here = local_status.get( 'totalThreat', 0) > 0 # TODO: assess if remaining other forces are sufficient safely_needed = needed_here and my_local_rating > local_status.get( 'totalThreat', 0) # TODO: improve both assessment prongs if not fleet_ok: if safely_needed: print "Fleet %d at %s needs repair but deemed safely needed to remain for defense" % ( fleet_id, ppstring(PlanetUtilsAI.sys_name_ids([fleet.systemID]))) else: if needed_here: print "Fleet %d at %s needed present for combat, but is damaged and deemed unsafe to remain." % ( fleet_id, ppstring(PlanetUtilsAI.sys_name_ids([fleet.systemID]))) print "\t my_local_rating: %.1f ; threat: %.1f" % ( my_local_rating, local_status.get('totalThreat', 0)) print "Selecting fleet %d at %s for repair" % ( fleet_id, ppstring(PlanetUtilsAI.sys_name_ids([fleet.systemID]))) fleet_buckets[fleet_ok or safely_needed].append(fleet_id) return fleet_buckets
def avail_mil_needing_repair(mil_fleet_ids, split_ships=False, on_mission=False): """returns tuple of lists-- ( ids_needing_repair, ids_not )""" fleet_buckets = [[], []] universe = fo.getUniverse() cutoff = [0.70, 0.25][on_mission] for fleet_id in mil_fleet_ids: fleet = universe.getFleet(fleet_id) ship_buckets = [[], []] ships_cur_health = [0, 0] ships_max_health = [0, 0] safely_needed = False for ship_id in fleet.shipIDs: this_ship = universe.getShip(ship_id) cur_struc = this_ship.currentMeterValue(fo.meterType.structure) max_struc = this_ship.currentMeterValue(fo.meterType.maxStructure) ship_ok = cur_struc >= cutoff * max_struc ship_buckets[ship_ok].append(ship_id) ships_cur_health[ship_ok] += cur_struc ships_max_health[ship_ok] += max_struc thisSysID = (fleet.nextSystemID != -1 and fleet.nextSystemID) or fleet.systemID fleet_ok = sum(ships_cur_health) >= cutoff * sum(ships_max_health) local_status = foAI.foAIstate.systemStatus.get(thisSysID, {}) my_local_rating = local_status.get("mydefenses", {}).get("overall", 0) + local_status.get("myFleetRating", 0) needed_here = local_status.get("totalThreat", 0) > 0 # TODO: assess if remaining other forces are sufficient safely_needed = needed_here and my_local_rating > local_status.get( "totalThreat", 0 ) # TODO: improve both assessment prongs if not fleet_ok: if safely_needed: print "Fleet %d at %s needs repair but deemed safely needed to remain for defense" % ( fleet_id, ppstring(PlanetUtilsAI.sys_name_ids([fleet.systemID])), ) else: if needed_here: print "Fleet %d at %s needed present for combat, but is damaged and deemed unsafe to remain." % ( fleet_id, ppstring(PlanetUtilsAI.sys_name_ids([fleet.systemID])), ) print "\t my_local_rating: %.1f ; threat: %.1f" % ( my_local_rating, local_status.get("totalThreat", 0), ) print "Selecting fleet %d at %s for repair" % ( fleet_id, ppstring(PlanetUtilsAI.sys_name_ids([fleet.systemID])), ) fleet_buckets[fleet_ok or safely_needed].append(fleet_id) return fleet_buckets
def refresh(self): """Turn start AIstate cleanup/refresh.""" universe = fo.getUniverse() # checks exploration border & clears roles/missions of missing fleets & updates fleet locs & threats fleetsLostBySystem.clear() invasionTargets[:] = [] exploration_center = PlanetUtilsAI.get_capital_sys_id() if exploration_center == -1: # a bad state probably from an old savegame, or else empire has lost (or almost has) exploration_center = self.__origin_home_system_id # check if planets in cache is still present. Remove destroyed. for system_id, info in sorted(self.systemStatus.items()): planet_dict = info.get('planets', {}) cache_planet_set = set(planet_dict) system_planet_set = set(universe.getSystem(system_id).planetIDs) diff = cache_planet_set - system_planet_set if diff: print "Removing destroyed planets from systemStatus for system %s: planets to be removed: %s" % (system_id, sorted(diff)) for key in diff: del planet_dict[key] ExplorationAI.graphFlags.clear() if fo.currentTurn() < 50: print "-------------------------------------------------" print "Border Exploration Update (relative to %s)" % (PlanetUtilsAI.sys_name_ids([exploration_center, -1])[0]) print "-------------------------------------------------" if self.visBorderSystemIDs.keys() == [-1]: self.visBorderSystemIDs.clear() self.visBorderSystemIDs[exploration_center] = 1 for sys_id in self.visBorderSystemIDs.keys(): # This dict modified during iteration. if fo.currentTurn() < 50: print "Considering border system %s" % (PlanetUtilsAI.sys_name_ids([sys_id, -1])[0]) ExplorationAI.follow_vis_system_connections(sys_id, exploration_center) newly_explored = ExplorationAI.update_explored_systems() nametags = [] for sys_id in newly_explored: newsys = universe.getSystem(sys_id) nametags.append("ID:%4d -- %-20s" % (sys_id, (newsys and newsys.name) or "name unknown")) # an explored system *should* always be able to be gotten if newly_explored: print "-------------------------------------------------" print "Newly explored systems:\n%s" % "\n".join(nametags) print "-------------------------------------------------" # cleanup fleet roles # self.update_fleet_locs() self.__clean_fleet_roles() self.__clean_fleet_missions(FleetUtilsAI.get_empire_fleet_ids()) print "Fleets lost by system: %s" % fleetsLostBySystem self.update_system_status()
def startNewGame(aggression=fo.aggression.aggressive): # pylint: disable=invalid-name """Called by client when a new game is started (but not when a game is loaded). Should clear any pre-existing state and set up whatever is needed for AI to generate orders.""" empire = fo.getEmpire() if empire.eliminated: print "This empire has been eliminated. Ignoring new game start message." return turn_timer.start("Server Processing") print "New game started, AI Aggression level %d (%s)" % (aggression, UserString(_aggression_names[aggression])) # initialize AIstate global foAIstate print "Initializing foAIstate..." foAIstate = AIstate.AIstate(aggression) foAIstate.session_start_cleanup() print "Initialization of foAIstate complete!" print "Trying to rename our homeworld..." planet_id = PlanetUtilsAI.get_capital() universe = fo.getUniverse() if planet_id is not None and planet_id != -1: planet = universe.getPlanet(planet_id) new_name = " ".join([random.choice(_capitals.get(aggression, []) or [" "]).strip(), planet.name]) print " Renaming to %s..." % new_name res = fo.issueRenameOrder(planet_id, new_name) print " Result: %d; Planet is now named %s" % (res, planet.name) diplomatic_corp_configs = {fo.aggression.beginner: DiplomaticCorp.BeginnerDiplomaticCorp, fo.aggression.maniacal: DiplomaticCorp.ManiacalDiplomaticCorp} global diplomatic_corp diplomatic_corp = diplomatic_corp_configs.get(aggression, DiplomaticCorp.DiplomaticCorp)() TechsListsAI.test_tech_integrity()
def printResourcesPriority(): "calculate top resource priority" universe = fo.getUniverse() empire = fo.getEmpire() empireID = empire.empireID ownedPlanetIDs = PlanetUtilsAI.getOwnedPlanetsByEmpire(universe.planetIDs, empireID) print "Resource Management:" print "" print "Resource Priorities:" resourcePriorities = {} for priorityType in getAIPriorityResourceTypes(): resourcePriorities[priorityType] = foAI.foAIstate.getPriority(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 " ID|Score: " + str(evaluationPair) print " Top Resource Priority: " + str(topPriority) # what is the focus of available resource centers? print "" print "Planet Resources Foci:" for planetID in ownedPlanetIDs: planet = universe.getPlanet(planetID) planetPopulation = planet.currentMeterValue(fo.meterType.population) print " ID: " + str(planetID) + " Name: " + str(planet.name) + " Type: " + str(planet.type) + " Size: " + str(planet.size) + " Focus: " + str(planet.focus) + " Species: " + str(planet.speciesName) + " Population: " + str(planetPopulation)
def system_could_have_unknown_stationary_guard(system_id: SystemId) -> bool: """Return True if the system may have spawned stationary guards. A stationary guard is defined as immobile monster fleets spawned at game start. If this function indicates that there is no such guard, there still may be other threats. """ # We do not play around invisible guards, so if system was visible at some point, # there should not be a stationary guard there system_was_visible = get_partial_visibility_turn(system_id) > 0 if system_was_visible: return False # Universe setup settings may forbid guards if fo.getGalaxySetupData( ).monsterFrequency == fo.galaxySetupOptionMonsterFreq.none: return False # Stationary guards require some distance to the home system to be spawned home_system = PlanetUtilsAI.get_capital_sys_id() jump_distance_to_home_system = fo.getUniverse().jumpDistance( system_id, home_system) if jump_distance_to_home_system < MINIMUM_GUARD_DISTANCE_TO_HOME_SYSTEM: return False # No indicator that there isn't a stationary guard return True
def startNewGame(aggression=fo.aggression.aggressive): # pylint: disable=invalid-name """Called by client when a new game is started (but not when a game is loaded). Should clear any pre-existing state and set up whatever is needed for AI to generate orders.""" empire = fo.getEmpire() if empire.eliminated: print "This empire has been eliminated. Ignoring new game start message." return turn_timer.start("Server Processing") print "New game started, AI Aggression level %d" % aggression # initialize AIstate global foAIstate foAIstate = AIstate.AIstate(aggression=aggression) foAIstate.session_start_cleanup() print "Initialized foAIstate class" planet_id = PlanetUtilsAI.get_capital() universe = fo.getUniverse() if planet_id is not None and planet_id != -1: planet = universe.getPlanet(planet_id) new_name = " ".join([random.choice(_capitals.get(aggression, []) or [" "]).strip(), planet.name]) print "Capitol City Names are: ", _capitals print "This Capitol New name is ", new_name res = fo.issueRenameOrder(planet_id, new_name) print "Capitol Rename attempt result: %d; planet now named %s" % (res, planet.name) diplomatic_corp_configs = {fo.aggression.beginner: DiplomaticCorp.BeginnerDiplomaticCorp, fo.aggression.maniacal: DiplomaticCorp.ManiacalDiplomaticCorp} global diplomatic_corp diplomatic_corp = diplomatic_corp_configs.get(aggression, DiplomaticCorp.DiplomaticCorp)()
def evaluateSystem(systemID, missionType, empireProvinceSystemIDs, otherTargetedSystemIDs, empire): "return the military value of a system" universe = fo.getUniverse() system = universe.getSystem(systemID) if (system == None): return 0 # give preference to home system then closest systems empireID = empire.empireID capitalID = PlanetUtilsAI.getCapital() homeworld = universe.getPlanet(capitalID) if homeworld: homeSystemID = homeworld.systemID evalSystemID = system.systemID leastJumpsPath = len(universe.leastJumpsPath(homeSystemID, evalSystemID, empireID)) distanceFactor = 1.001/(leastJumpsPath + 1) else: homeSystemID=-1 distanceFactor=0 if systemID == homeSystemID: return 10 elif systemID in empireProvinceSystemIDs: return 4 + distanceFactor elif systemID in otherTargetedSystemIDs: return 2 + distanceFactor else: return 1 + .25 * distanceFactor
def startNewGame(aggression_input=fo.aggression.aggressive): # pylint: disable=invalid-name """Called by client when a new game is started (but not when a game is loaded). Should clear any pre-existing state and set up whatever is needed for AI to generate orders.""" empire = fo.getEmpire() if empire.eliminated: print "This empire has been eliminated. Ignoring new game start message." return turn_timer.start("Server Processing") # initialize AIstate global foAIstate print "Initializing foAIstate..." foAIstate = AIstate.AIstate(aggression_input) aggression_trait = foAIstate.character.get_trait(Aggression) print "New game started, AI Aggression level %d (%s)" % ( aggression_trait.key, get_trait_name_aggression(foAIstate.character)) foAIstate.session_start_cleanup() print "Initialization of foAIstate complete!" print "Trying to rename our homeworld..." planet_id = PlanetUtilsAI.get_capital() universe = fo.getUniverse() if planet_id is not None and planet_id != INVALID_ID: planet = universe.getPlanet(planet_id) new_name = " ".join([random.choice(possible_capitals(foAIstate.character)).strip(), planet.name]) print " Renaming to %s..." % new_name res = fo.issueRenameOrder(planet_id, new_name) print " Result: %d; Planet is now named %s" % (res, planet.name) diplomatic_corp_configs = {fo.aggression.beginner: DiplomaticCorp.BeginnerDiplomaticCorp, fo.aggression.maniacal: DiplomaticCorp.ManiacalDiplomaticCorp} global diplomatic_corp diplomatic_corp = diplomatic_corp_configs.get(aggression_trait.key, DiplomaticCorp.DiplomaticCorp)() TechsListsAI.test_tech_integrity()
def startNewGame(aggression_input=fo.aggression.aggressive): # pylint: disable=invalid-name """Called by client when a new game is started (but not when a game is loaded). Should clear any pre-existing state and set up whatever is needed for AI to generate orders.""" empire = fo.getEmpire() if empire is None: fatal("This client has no empire. Ignoring new game start message.") return if empire.eliminated: info( "This empire has been eliminated. Ignoring new game start message." ) return # initialize AIstate debug("Initializing AI state...") create_new_aistate(aggression_input) aistate = get_aistate() aggression_trait = aistate.character.get_trait(Aggression) debug("New game started, AI Aggression level %d (%s)" % (aggression_trait.key, get_trait_name_aggression(aistate.character))) aistate.session_start_cleanup() debug("Initialization of AI state complete!") debug("Trying to rename our homeworld...") planet_id = PlanetUtilsAI.get_capital() universe = fo.getUniverse() if planet_id is not None and planet_id != INVALID_ID: planet = universe.getPlanet(planet_id) new_name = " ".join([ random.choice(possible_capitals(aistate.character)).strip(), planet.name ]) debug(" Renaming to %s..." % new_name) res = fo.issueRenameOrder(planet_id, new_name) debug(" Result: %d; Planet is now named %s" % (res, planet.name)) _pre_game_start(empire.empireID, aistate)
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 calculateIndustryPriority(): "calculates the demand for industry" universe = fo.getUniverse() empire = fo.getEmpire() empireID = empire.empireID # get current industry production & Target industryProduction = empire.resourceProduction(fo.resourceType.industry) ownedPlanetIDs = PlanetUtilsAI.getOwnedPlanetsByEmpire(universe.planetIDs, empireID) planets = map(universe.getPlanet, ownedPlanetIDs) targetPP = sum( map( lambda x: x.currentMeterValue(fo.meterType.targetIndustry), planets) ) if fo.currentTurn() < 20: industryPriority = 20 # mid industry , high research at beginning of game to get easy gro tech elif fo.currentTurn() < 30: industryPriority = 25 # mid industry , mid research elif fo.currentTurn() < 40: industryPriority = 40 # high industry , mid research elif fo.currentTurn() < 50: industryPriority = 50 # high industry , mid research else: industryPriority = 60 # high industry , low-mid research # increase demand for industry industry production is low #industryPriority = 380 / (industryProduction + 0.001) print "" print "Industry Production (current/target) : ( %.1f / %.1f ) at turn %s"%(industryProduction, targetPP, fo.currentTurn()) print "Priority for Industry: " + str(industryPriority) return industryPriority
def calculateResearchPriority(): "calculates the AI empire's demand for research" universe = fo.getUniverse() empire = fo.getEmpire() empireID = empire.empireID gotAlgo = empire.getTechStatus("LRN_ALGO_ELEGANCE") == fo.techStatus.complete totalPP = empire.productionPoints totalRP = empire.resourceProduction(fo.resourceType.research) # get current industry production & Target ownedPlanetIDs = PlanetUtilsAI.getOwnedPlanetsByEmpire(universe.planetIDs, empireID) planets = map(universe.getPlanet, ownedPlanetIDs) targetRP = sum( map( lambda x: x.currentMeterValue(fo.meterType.targetResearch), planets) ) if (fo.currentTurn() < 20) or not gotAlgo: researchPriority = 60 # mid industry , high research at beginning of game to get easy gro tech and to get research booster Algotrithmic Elegance elif fo.currentTurn() < 30: researchPriority = 30 # mid industry , mid research elif fo.currentTurn() < 40: researchPriority = 20 # high industry , low research else: researchPriority = 15 # high industry , low research print "" print "Research Production (current/target) : ( %.1f / %.1f )"%(totalRP, targetRP) print "Priority for Research: " + str(researchPriority) return researchPriority
def __border_exploration_update(self): universe = fo.getUniverse() exploration_center = PlanetUtilsAI.get_capital_sys_id() # a bad state probably from an old savegame, or else empire has lost (or almost has) if exploration_center == INVALID_ID: exploration_center = self.__origin_home_system_id ExplorationAI.graph_flags.clear() if fo.currentTurn() < 50: debug("-------------------------------------------------") debug("Border Exploration Update (relative to %s)" % universe.getSystem(exploration_center)) debug("-------------------------------------------------") if self.visBorderSystemIDs == {INVALID_ID}: self.visBorderSystemIDs.clear() self.visBorderSystemIDs.add(exploration_center) for sys_id in list(self.visBorderSystemIDs): # This set is modified during iteration. if fo.currentTurn() < 50: debug("Considering border system %s" % universe.getSystem(sys_id)) ExplorationAI.follow_vis_system_connections(sys_id, exploration_center) newly_explored = ExplorationAI.update_explored_systems() nametags = [] for sys_id in newly_explored: newsys = universe.getSystem(sys_id) # an explored system *should* always be able to be gotten nametags.append("ID:%4d -- %-20s" % (sys_id, (newsys and newsys.name) or "name unknown")) if newly_explored: debug("-------------------------------------------------") debug("Newly explored systems:\n%s" % "\n".join(nametags)) debug("-------------------------------------------------")
def avail_mil_needing_repair(mil_fleet_ids, split_ships=False, on_mission=False): """returns tuple of lists-- ( ids_needing_repair, ids_not )""" fleet_buckets = [[], []] universe = fo.getUniverse() cutoff = [0.70, 0.25][ on_mission ] for fleet_id in mil_fleet_ids: fleet = universe.getFleet(fleet_id) ship_buckets = [ [], [] ] ships_cur_health = [ 0, 0 ] ships_max_health = [ 0, 0 ] for ship_id in fleet.shipIDs: this_ship = universe.getShip(ship_id) cur_struc = this_ship.currentMeterValue(fo.meterType.structure) max_struc = this_ship.currentMeterValue(fo.meterType.maxStructure) ship_ok = cur_struc >= cutoff * max_struc ship_buckets[ship_ok].append( ship_id ) ships_cur_health[ship_ok] += cur_struc ships_max_health[ship_ok] += max_struc #TODO: the following is a temp all-or-nothing test fleet_ok = ( sum(ships_cur_health) >= cutoff * sum(ships_max_health) ) if not fleet_ok: pass print "Selecting fleet %d at %s for repair"%(fleet_id, PlanetUtilsAI.sys_name_ids( [fleet.systemID] )) fleet_buckets[fleet_ok].append(fleet_id) return fleet_buckets
def calculateMilitaryPriority(): "calculates the demand for military ships by military targeted systems" universe = fo.getUniverse() empire = fo.getEmpire() empireID = empire.empireID capitalID = PlanetUtilsAI.getCapital() if capitalID: homeworld = universe.getPlanet(capitalID) else: return 0# no capitol (not even a capitol-in-the-making), means can't produce any ships allottedInvasionTargets = 1+ int(fo.currentTurn()/25) targetPlanetIDs = [pid for pid, pscore, trp in AIstate.invasionTargets[:allottedInvasionTargets] ] + [pid for pid, pscore in foAI.foAIstate.colonisablePlanetIDs[:allottedColonyTargets] ] + [pid for pid, pscore in foAI.foAIstate.colonisableOutpostIDs[:allottedColonyTargets] ] mySystems = set( AIstate.popCtrSystemIDs ).union( AIstate.outpostSystemIDs ) targetSystems = set( PlanetUtilsAI.getSystems(targetPlanetIDs) ) curShipRating = curBestMilShipRating() unmetThreat = 0.0 currentTurn=fo.currentTurn() for sysID in mySystems.union(targetSystems) : status=foAI.foAIstate.systemStatus.get( sysID, {} ) myAttack, myHealth =0, 0 for fid in status.get('myfleets', []) : rating= foAI.foAIstate.fleetStatus.get(fid, {}).get('rating', {}) myAttack += rating.get('attack', 0) myHealth += rating.get('health', 0) myRating = myAttack*myHealth baseMonsterThreat = status.get('monsterThreat', 0) if currentTurn>200: monsterThreat = baseMonsterThreat elif currentTurn>100: if baseMonsterThreat <2000: monsterThreat = baseMonsterThreat else: monsterThreat = 2000 + (currentTurn/100.0 - 1) *(baseMonsterThreat-2000) else: monsterThreat = 0 if sysID in mySystems: threat = status.get('fleetThreat', 0) + status.get('planetThreat', 0) + 0.3* status.get('neighborThreat', 0) else: threat = status.get('fleetThreat', 0) + status.get('planetThreat', 0) + 0.1* status.get('neighborThreat', 0) unmetThreat += max( 0, threat + monsterThreat - myRating ) militaryPriority = int( 40 + max(0, 75*unmetThreat / curShipRating) ) return max( militaryPriority, 0)
def setGeneralPlanetResourceFocus(): "set resource focus of planets except capitalID, asteroids, and gas giants" universe = fo.getUniverse() empire = fo.getEmpire() empireID = empire.empireID empirePlanetIDs = PlanetUtilsAI.getOwnedPlanetsByEmpire(universe.planetIDs, empireID) capitalID = [empire.capitalID] asteroids = PlanetUtilsAI.getTypePlanetEmpireOwned(fo.planetType.asteroids) gasGiants = PlanetUtilsAI.getTypePlanetEmpireOwned(fo.planetType.gasGiant) generalPlanetIDs = list(set(empirePlanetIDs) - (set(capitalID)|set(asteroids)|set(gasGiants))) topPriority = topResourcePriority() fleetSupplyableSystemIDs = empire.fleetSupplyableSystemIDs fleetSupplyablePlanetIDs = PlanetUtilsAI.getPlanetsInSystemsIDs(fleetSupplyableSystemIDs) if topPriority == AIPriorityType.PRIORITY_RESOURCE_FOOD: newFocus = AIFocusType.FOCUS_FARMING for planetID in generalPlanetIDs: planet = universe.getPlanet(planetID) focus = newFocus if focus in planet.availableFoci: fo.issueChangeFocusOrder(planetID, focus) elif topPriority == AIPriorityType.PRIORITY_RESOURCE_MINERALS: newFocus = AIFocusType.FOCUS_MINING for planetID in generalPlanetIDs: planet = universe.getPlanet(planetID) focus = newFocus if planetID in fleetSupplyablePlanetIDs and focus in planet.availableFoci: fo.issueChangeFocusOrder(planetID, focus) elif topPriority == AIPriorityType.PRIORITY_RESOURCE_PRODUCTION: newFocus = AIFocusType.FOCUS_INDUSTRY for planetID in generalPlanetIDs: planet = universe.getPlanet(planetID) focus = newFocus if planetID in fleetSupplyablePlanetIDs and focus in planet.availableFoci: fo.issueChangeFocusOrder(planetID, focus) elif topPriority == AIPriorityType.PRIORITY_RESOURCE_RESEARCH: newFocus = AIFocusType.FOCUS_RESEARCH for planetID in generalPlanetIDs: planet = universe.getPlanet(planetID) focus = newFocus if planetID in fleetSupplyablePlanetIDs and focus in planet.availableFoci: fo.issueChangeFocusOrder(planetID, focus) else: focus = AIFocusType.FOCUS_FARMING if focus in planet.availableFoci: fo.issueChangeFocusOrder(planetID, focus)
def get_repair_fleet_order(fleet_target, current_sys_id): """ Returns repair AIFleetOrder to [nearest safe] drydock.""" # find nearest supplied system drydock_sys_id = get_nearest_drydock_system_id(current_sys_id) drydock_system_target = AITarget.AITarget(AITargetType.TARGET_SYSTEM, drydock_sys_id) print "ordering fleet %d to %s for repair" % (fleet_target.target_id, PlanetUtilsAI.sys_name_ids([drydock_sys_id])) # create resupply AIFleetOrder return AIFleetOrder.AIFleetOrder(AIFleetOrderType.ORDER_REPAIR, fleet_target, drydock_system_target)
def inspect_ai_interface(): capital_id = PlanetUtilsAI.get_capital() universe = fo.getUniverse() fleets_int_vector = universe.fleetIDs fleet = universe.getFleet(list(fleets_int_vector)[0]) ship = universe.getShip(list(universe.shipIDs)[0]) design = fo.getShipDesign(ship.designID) empire = fo.getEmpire() tech = fo.getTech('SHP_WEAPON_2_1') tech_spec = list(tech.unlockedItems)[0] part_id = list(empire.availableShipParts)[0] part_type = fo.getPartType(part_id) prod_queue = empire.productionQueue fo.issueEnqueueShipProductionOrder( list(empire.availableShipDesigns)[0], capital_id) research_queue = empire.researchQueue fo.issueEnqueueTechOrder('SHP_WEAPON_1_2', -1) planet = universe.getPlanet(capital_id) building = list(planet.buildingIDs)[0] inspect( fo, universe, fleet, planet, universe.getSystem(planet.systemID), ship, empire, design, tech, tech_spec, fo.getFieldType('FLD_ION_STORM'), fo.getBuildingType('BLD_SHIPYARD_BASE'), fo.getGalaxySetupData(), fo.getHullType('SH_XENTRONIUM'), fo.getPartType('SR_WEAPON_1_1'), fo.getSpecial('MODERATE_TECH_NATIVES_SPECIAL'), fo.getSpecies('SP_ABADDONI'), fo.getTech('SHP_WEAPON_4_1'), fo.diplomaticMessage(1, 2, fo.diplomaticMessageType.acceptProposal), fleets_int_vector, part_type, prod_queue, prod_queue.allocatedPP, prod_queue[0], research_queue, research_queue[0], empire.getSitRep(0), universe.getBuilding(building), ) exit(1) # exit game to main menu no need to play anymore.
def inspect_FreeOrionAIInterface(): capital_id = PlanetUtilsAI.get_capital() universe = fo.getUniverse() fleets_int_vector = universe.fleetIDs fleet = universe.getFleet(list(fleets_int_vector)[0]) ship = universe.getShip(list(universe.shipIDs)[0]) design = fo.getShipDesign(ship.designID) empire = fo.getEmpire() tech = fo.getTech('SHP_WEAPON_2_1') tech_spec = list(tech.unlockedItems)[0] part_id = list(empire.availableShipParts)[0] part_type = fo.getPartType(part_id) prod_queue = empire.productionQueue fo.issueEnqueueShipProductionOrder(list(empire.availableShipDesigns)[0], capital_id) research_queue = empire.researchQueue fo.issueEnqueueTechOrder('SHP_WEAPON_1_2', -1) planet = universe.getPlanet(capital_id) building = list(planet.buildingIDs)[0] inspect( fo, universe, fleet, planet, universe.getSystem(planet.systemID), ship, empire, design, tech, tech_spec, fo.getFieldType('FLD_ION_STORM'), fo.getBuildingType('BLD_SHIPYARD_BASE'), fo.getGalaxySetupData(), fo.getHullType('SH_XENTRONIUM'), fo.getPartType('SR_WEAPON_1_1'), fo.getSpecial('MODERATE_TECH_NATIVES_SPECIAL'), fo.getSpecies('SP_ABADDONI'), fo.getTech('SHP_WEAPON_4_1'), fo.diplomaticMessage(1, 2, fo.diplomaticMessageType.acceptProposal), fleets_int_vector, part_type, prod_queue, prod_queue.allocatedPP, prod_queue[0], research_queue, research_queue[0], empire.getSitRep(0), universe.getBuilding(building), ) exit(1) # exit game to main menu no need to play anymore.
def getResourceTargetTotals(empirePlanetIDs):#+ universe = fo.getUniverse() empire = fo.getEmpire() empireID = empire.empireID #empirePlanetIDs = PlanetUtilsAI.getOwnedPlanetsByEmpire(universe.planetIDs, empireID) capitalID = PlanetUtilsAI.getCapital() oldTargets.clear() oldTargets.update(newTargets) newTargets.clear() currentFocus.clear() currentOutput.clear() targetPP = sum( map( lambda x: x.currentMeterValue(fo.meterType.targetIndustry), planetMap.values()) ) targetRP = sum( map( lambda x: x.currentMeterValue(fo.meterType.targetResearch), planetMap.values()) ) newFocus= IFocus for pid in empirePlanetIDs: planet=planetMap[pid] #canFocus= planetMap[pid].currentMeterValue(fo.meterType.targetPopulation) >0 currentFocus[pid] = planet.focus #if currentFocus[pid] == MFocus: # mtarget=planetMap[pid].currentMeterValue(fo.meterType.targetIndustry) currentOutput.setdefault(pid, {} )[ IFocus] = planet.currentMeterValue(fo.meterType.industry) currentOutput[pid][ RFocus] = planet.currentMeterValue(fo.meterType.research) if IFocus in planet.availableFoci and planet.focus !=IFocus: fo.issueChangeFocusOrder(pid, IFocus) #may not be able to take, but try universe.updateMeterEstimates(empirePlanetIDs) for pid in empirePlanetIDs: planet=planetMap[pid] itarget=planet.currentMeterValue(fo.meterType.targetIndustry) rtarget=planet.currentMeterValue(fo.meterType.targetResearch) if planet.focus == IFocus: newTargets.setdefault(pid, {})[IFocus] = ( itarget, rtarget ) newTargets.setdefault(pid, {})[GFocus] = [0, rtarget] else: newTargets.setdefault(pid, {})[IFocus] = ( 0, 0) newTargets.setdefault(pid, {})[GFocus] = [0, 0] #if currentFocus[pid] == MFocus: # newTargets[pid][MFocus] = ( mtarget, rtarget ) if RFocus in planet.availableFoci and planet.focus!=RFocus: fo.issueChangeFocusOrder(pid, RFocus) #may not be able to take, but try universe.updateMeterEstimates(empirePlanetIDs) for pid in empirePlanetIDs: planet=planetMap[pid] canFocus= planet.currentMeterValue(fo.meterType.targetPopulation) >0 itarget=planet.currentMeterValue(fo.meterType.targetIndustry) rtarget=planet.currentMeterValue(fo.meterType.targetResearch) if planet.focus == RFocus: newTargets.setdefault(pid, {})[RFocus] = ( itarget, rtarget ) newTargets[pid][GFocus][0] = itarget else: newTargets.setdefault(pid, {})[RFocus] = ( 0, 0 ) newTargets[pid][GFocus][0] = 0 if canFocus and currentFocus[pid] != planet.focus: fo.issueChangeFocusOrder(pid, currentFocus[pid]) #put it back to what it was universe.updateMeterEstimates(empirePlanetIDs) return targetPP, targetRP
def get_safe_path_leg_to_dest(fleet_id, start_id, dest_id): start_targ = TargetSystem(start_id) dest_targ = TargetSystem(dest_id) # TODO actually get a safe path this_path = can_travel_to_system(fleet_id, start_targ, dest_targ, ensure_return=False) path_ids = [targ.id for targ in this_path if targ.id != start_id] + [start_id] universe = fo.getUniverse() debug("Fleet %d requested safe path leg from %s to %s, found path %s" % ( fleet_id, universe.getSystem(start_id), universe.getSystem(dest_id), PlanetUtilsAI.sys_name_ids(path_ids))) return path_ids[0]
def getRepairAIFleetOrder(fleetAITarget, current_sys_id): "returns repair AIFleetOrder to [nearest safe] drydock" # find nearest supplied system empireID = fo.empireID() drydock_sys_id = getNearestDrydockSystemID(current_sys_id) drydockSystemAITarget = AITarget.AITarget(AITargetType.TARGET_SYSTEM, drydock_sys_id) print "ordering fleet %d to %s for repair"%(fleetAITarget.target_id, PlanetUtilsAI.sysNameIDs([drydock_sys_id])) # create resupply AIFleetOrder aiFleetOrder = AIFleetOrder.AIFleetOrder(AIFleetOrderType.ORDER_REPAIR, fleetAITarget, drydockSystemAITarget) return aiFleetOrder
def calculateResearchPriority(): "calculates the AI empire's demand for research" universe = fo.getUniverse() empire = fo.getEmpire() empireID = empire.empireID industryPriority = foAI.foAIstate.getPriority(EnumsAI.AIPriorityType.PRIORITY_RESOURCE_PRODUCTION) gotAlgo = empire.getTechStatus("LRN_ALGO_ELEGANCE") == fo.techStatus.complete researchQueueList = ResearchAI.getResearchQueueTechs() orbGenTech = "PRO_ORBITAL_GEN" totalPP = empire.productionPoints totalRP = empire.resourceProduction(fo.resourceType.research) industrySurge= (foAI.foAIstate.aggression > fo.aggression.cautious) and ( totalPP <(30*(foAI.foAIstate.aggression)) ) and (orbGenTech in researchQueueList[:3] or empire.getTechStatus(orbGenTech) == fo.techStatus.complete) # get current industry production & Target ownedPlanetIDs = PlanetUtilsAI.getOwnedPlanetsByEmpire(universe.planetIDs, empireID) planets = map(universe.getPlanet, ownedPlanetIDs) targetRP = sum( map( lambda x: x.currentMeterValue(fo.meterType.targetResearch), planets) ) styleIndex = empireID%2 cutoffSets = [ [25, 45, 70 ], [35, 50, 70 ] ] cutoffs = cutoffSets[styleIndex ] settings = [ [2, .6, .4, .35 ], [1.4, .7, .4, .35 ] ][styleIndex ] if industrySurge and True: researchPriority = 0.2 * industryPriority else: if (fo.currentTurn() < cutoffs[0]) or not gotAlgo: researchPriority = settings[0] * industryPriority # high research at beginning of game to get easy gro tech and to get research booster Algotrithmic Elegance elif fo.currentTurn() < cutoffs[1]: researchPriority = settings[1] * industryPriority# med-high research elif fo.currentTurn() < cutoffs[2]: researchPriority = settings[2] * industryPriority # med-high industry else: researchQueue = list(empire.researchQueue) researchPriority = settings[3] * industryPriority # high industry , low research if len(researchQueue) == 0 : researchPriority = 0 # done with research elif len(researchQueue) <5 and researchQueue[-1].allocation > 0 : researchPriority = len(researchQueue) # barely not done with research elif len(researchQueue) <10 and researchQueue[-1].allocation > 0 : researchPriority = 4+ len(researchQueue) # almost done with research elif len(researchQueue) <20 and researchQueue[int(len(researchQueue)/2)].allocation > 0 : researchPriority = 0.5 * researchPriority # closing in on end of research elif len(researchQueue) <20: researchPriority = 0.7*researchPriority # high industry , low research print "" print "Research Production (current/target) : ( %.1f / %.1f )"%(totalRP, targetRP) print "Priority for Research: " + str(researchPriority) return researchPriority
def getHomeSystemID(): "returns the systemID of the home world" empire = fo.getEmpire() universe = fo.getUniverse() homeworld = universe.getPlanet(PlanetUtilsAI.getCapital()) if homeworld: return homeworld.systemID return -1
def assign_scouts_to_explore_systems(): # TODO: use Graph Theory to explore closest systems universe = fo.getUniverse() capital_sys_id = PlanetUtilsAI.get_capital_sys_id() # order fleets to explore #explorable_system_ids = foAI.foAIstate.get_explorable_systems(AIExplorableSystemType.EXPLORABLE_SYSTEM_UNEXPLORED) explorable_system_ids = list(borderUnexploredSystemIDs) if not explorable_system_ids or (capital_sys_id == -1): return exp_systems_by_dist = sorted(map(lambda x: (universe.linearDistance(capital_sys_id, x), x), explorable_system_ids)) print "Exploration system considering following system-distance pairs:\n %s" % ("[ " + ", ".join(["%3d : %5.1f" % (sys, dist) for dist, sys in exp_systems_by_dist]) + " ]") explore_list = [sys_id for dist, sys_id in exp_systems_by_dist] already_covered, available_scouts = get_current_exploration_info() print "explorable sys IDs: %s" % explore_list print "already targeted: %s" % already_covered if 'needsEmergencyExploration' not in dir(foAI.foAIstate): foAI.foAIstate.needsEmergencyExploration = [] needs_coverage = foAI.foAIstate.needsEmergencyExploration + [sys_id for sys_id in explore_list if sys_id not in already_covered] # emergency coverage cane be due to invasion detection trouble, etc. print "needs coverage: %s" % needs_coverage print "available scouts & AIstate locs: %s" % (map(lambda x: (x, foAI.foAIstate.fleetStatus.get(x, {}).get('sysID', -1)), available_scouts)) print "available scouts & universe locs: %s" % (map(lambda x: (x, universe.getFleet(x).systemID), available_scouts)) if not needs_coverage or not available_scouts: return available_scouts = set(available_scouts) sent_list = [] while (len(available_scouts) > 0) and (len(needs_coverage) > 0): this_sys_id = needs_coverage.pop(0) if (foAI.foAIstate.systemStatus.setdefault(this_sys_id, {}).setdefault('monsterThreat', 0) > 2000 * foAI.foAIstate.aggression) or (fo.currentTurn() < 20 and foAI.foAIstate.systemStatus[this_sys_id]['monsterThreat'] > 200): print "Skipping exploration of system %d due to Big Monster, threat %d" % (this_sys_id, foAI.foAIstate.systemStatus[this_sys_id]['monsterThreat']) continue found_fleets = [] this_fleet_list = FleetUtilsAI.get_fleets_for_mission(nships=1, target_stats={}, min_stats={}, cur_stats={}, species="", systems_to_check=[this_sys_id], systems_checked=[], fleet_pool_set=available_scouts, fleet_list=found_fleets, verbose=False) if not this_fleet_list: print "seem to have run out of scouts while trying to cover sys_id %d" % this_sys_id break # must have ran out of scouts fleet_id = this_fleet_list[0] fleet_mission = foAI.foAIstate.get_fleet_mission(fleet_id) target = AITarget.AITarget(TargetType.TARGET_SYSTEM, this_sys_id) if len(MoveUtilsAI.can_travel_to_system_and_return_to_resupply(fleet_id, fleet_mission.get_location_target(), target)) > 0: fleet_mission.add_target(AIFleetMissionType.FLEET_MISSION_EXPLORATION, target) sent_list.append(this_sys_id) else: # system too far out, skip it, but can add scout back to available pool print "sys_id %d too far out for fleet ( ID %d ) to reach" % (this_sys_id, fleet_id) available_scouts.update(this_fleet_list) print "sent scouting fleets to sysIDs : %s" % sent_list return # pylint: disable=pointless-string-statement """
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 calculateMilitaryPriority(): "calculates the demand for military ships by military targeted systems" universe = fo.getUniverse() empire = fo.getEmpire() empireID = empire.empireID capitalID = PlanetUtilsAI.getCapital() homeworld = universe.getPlanet(capitalID) if homeworld: homeSystemID = homeworld.systemID else: homeSystemID=-1 totalThreat = 0 for sysStatus in foAI.foAIstate.systemStatus.values(): totalThreat += max(0, (sysStatus.get('fleetThreat', 0) + sysStatus.get('planetThreat', 0) - 0.7*sysStatus.get('monsterThreat', 0) + sysStatus.get('neighborThreat', 0) )) #being safe; should never be neg since fleetThreat should include monsterThreat totalFleetRating = 0 for fleetStatus in foAI.foAIstate.fleetStatus.values(): totalFleetRating += fleetStatus.get('rating', {}).get('overall', 0) #numMilitaryTargetedSystemIDs = len(AIstate.militaryTargetedSystemIDs) #militaryShipIDs = FleetUtilsAI.getEmpireFleetIDsByRole(AIFleetMissionType.FLEET_MISSION_MILITARY) #numMilitaryShips = len(FleetUtilsAI.extractFleetIDsWithoutMissionTypes(militaryShipIDs)) curShipRating = curBestMilShipRating() if fo.currentTurn() < 20: threatBias = 0 elif fo.currentTurn() < 40: threatBias = 10 elif fo.currentTurn() < 60: threatBias = 80 elif fo.currentTurn() < 80: threatBias = 100 else: threatBias = 200 if threatBias > 0: threatBias = max(threatBias, curShipRating) visibleSystemIDs = foAI.foAIstate.visInteriorSystemIDs.keys() + foAI.foAIstate. visBorderSystemIDs.keys() accessibleSystemIDs = [sysID for sysID in visibleSystemIDs if universe.systemsConnected(sysID, homeSystemID, empireID) ] totalBias = len(accessibleSystemIDs) * threatBias # build one more military ship than military targeted systems #militaryPriority = 100 * ((numMilitaryTargetedSystemIDs +2) - numMilitaryShips) / (numMilitaryTargetedSystemIDs + 1) militaryPriority = int( 40 + max(0, 15*((1.25*totalThreat +threatBias - totalFleetRating ) / curShipRating)) ) print "Military Priority Calc: int( 40 + max(0, 10*((1.25*totalThreat(%d) - totalFleetRating(%d) ) / curShipRating(%d) )) ) = %d"%(totalThreat, totalFleetRating, curShipRating, militaryPriority) # print "" # print "Number of Military Ships Without Missions: " + str(numMilitaryShips) # print "Number of Military Targeted Systems: " + str(numMilitaryTargetedSystemIDs) # print "Priority for Military Ships: " + str(militaryPriority) return max( militaryPriority, 0)
def issue_order(self): if not super(OrderRepair, self).issue_order(): return fleet_id = self.fleet.id system_id = self.target.get_system().id fleet = self.fleet.get_object() if system_id not in [fleet.systemID, fleet.nextSystemID]: fo.issueAggressionOrder(fleet_id, False) start_id = FleetUtilsAI.get_fleet_system(fleet) dest_id = MoveUtilsAI.get_safe_path_leg_to_dest(fleet_id, start_id, system_id) print "fleet %d with order type(%s) sent to safe leg dest %s and ultimate dest %s" % ( fleet_id, self.ORDER_NAME, PlanetUtilsAI.sys_name_ids([dest_id]), PlanetUtilsAI.sys_name_ids([system_id])) fo.issueFleetMoveOrder(fleet_id, dest_id) print "Order issued: %s fleet: %s target: %s" % (self.ORDER_NAME, self.fleet, self.target) if system_id == fleet.systemID: if foAI.foAIstate.get_fleet_role(fleet_id) == MissionType.EXPLORATION: if system_id in foAI.foAIstate.needsEmergencyExploration: foAI.foAIstate.needsEmergencyExploration.remove(system_id) self.order_issued = True
def assign_scouts_to_explore_systems(): # TODO: use Graph Theory to explore closest systems universe = fo.getUniverse() capital_sys_id = PlanetUtilsAI.get_capital_sys_id() # order fleets to explore #explorable_system_ids = foAI.foAIstate.get_explorable_systems(AIExplorableSystemType.EXPLORABLE_SYSTEM_UNEXPLORED) explorable_system_ids = list(borderUnexploredSystemIDs) if not explorable_system_ids or (capital_sys_id == -1): return exp_systems_by_dist = sorted(map(lambda x: (universe.linearDistance(capital_sys_id, x), x), explorable_system_ids)) print "Exploration system considering following system-distance pairs:\n %s"%("[ "+ ", ".join(["%3d : %5.1f"%(sys, dist) for dist, sys in exp_systems_by_dist]) +" ]") explore_list = [sys_id for dist, sys_id in exp_systems_by_dist ] already_covered, available_scouts = get_current_exploration_info() print "explorable sys IDs: %s"%explore_list print "already targeted: %s"%already_covered if 'needsEmergencyExploration' not in dir(foAI.foAIstate): foAI.foAIstate.needsEmergencyExploration = [] needs_coverage = foAI.foAIstate.needsEmergencyExploration + [sys_id for sys_id in explore_list if sys_id not in already_covered ] # emergency coverage cane be due to invasion detection trouble, etc. print "needs coverage: %s"%needs_coverage print "available scouts & AIstate locs: %s" % (map(lambda x: (x, foAI.foAIstate.fleetStatus.get(x, {}).get('sysID', -1)), available_scouts) ) print "available scouts & universe locs: %s" % (map(lambda x: (x, universe.getFleet(x).systemID), available_scouts)) if not needs_coverage or not available_scouts: return available_scouts = set(available_scouts) sent_list = [] while (len(available_scouts) > 0 ) and ( len(needs_coverage) > 0): this_sys_id = needs_coverage.pop(0) if (foAI.foAIstate.systemStatus.setdefault(this_sys_id, {}).setdefault('monsterThreat', 0) > 2000* foAI.foAIstate.aggression ) or (fo.currentTurn() <20 and foAI.foAIstate.systemStatus[this_sys_id]['monsterThreat'] > 200): print "Skipping exploration of system %d due to Big Monster, threat %d"%(this_sys_id, foAI.foAIstate.systemStatus[this_sys_id]['monsterThreat']) continue found_fleets=[] this_fleet_list = FleetUtilsAI.get_fleets_for_mission(nships=1, target_stats={}, min_stats={}, cur_stats={}, species="", systems_to_check=[this_sys_id], systems_checked=[], fleet_pool_set= available_scouts, fleet_list=found_fleets, verbose=False) if not this_fleet_list: print "seem to have run out of scouts while trying to cover sys_id %d"%this_sys_id break #must have ran out of scouts fleet_id = this_fleet_list[0] fleet_mission = foAI.foAIstate.get_fleet_mission( fleet_id ) target = AITarget.AITarget(AITargetType.TARGET_SYSTEM, this_sys_id ) if len(MoveUtilsAI.can_travel_to_system_and_return_to_resupply(fleet_id, fleet_mission.get_location_target(), target)) > 0: fleet_mission.add_target(AIFleetMissionType.FLEET_MISSION_EXPLORATION, target) sent_list.append(this_sys_id) else: #system too far out, skip it, but can add scout back to available pool print "sys_id %d too far out for fleet ( ID %d ) to readch"%(this_sys_id, fleet_id) available_scouts.update(this_fleet_list) print "sent scouting fleets to sysIDs : %s"%sent_list return # pylint: disable=pointless-string-statement """
def _print_empire_capital(): planet_id = PlanetUtilsAI.get_capital() if planet_id is not None and planet_id != INVALID_ID: planet = fo.getUniverse().getPlanet(planet_id) stats.capital(planet_id, planet.name, planet.speciesName) else: stats.capital(None, None, None) debug( "***************************************************************************" ) debug( "***************************************************************************" )
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 get_safe_path_leg_to_dest(fleet_id, start_id, dest_id): start_targ = TargetSystem(start_id) dest_targ = TargetSystem(dest_id) # TODO actually get a safe path this_path = can_travel_to_system(fleet_id, start_targ, dest_targ, ensure_return=False) path_ids = [targ.id for targ in this_path if targ.id != start_id] + [start_id] universe = fo.getUniverse() debug("Fleet %d requested safe path leg from %s to %s, found path %s" % (fleet_id, universe.getSystem(start_id), universe.getSystem(dest_id), PlanetUtilsAI.sys_name_ids(path_ids))) return path_ids[0]
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 startNewGame(aggression_input=fo.aggression.aggressive): # pylint: disable=invalid-name """Called by client when a new game is started (but not when a game is loaded). Should clear any pre-existing state and set up whatever is needed for AI to generate orders.""" empire = fo.getEmpire() if empire is None: print "This client has no empire. Ignoring new game start message." return if empire.eliminated: info( "This empire has been eliminated. Ignoring new game start message." ) return turn_timer.start("Server Processing") # initialize AIstate global foAIstate debug("Initializing foAIstate...") foAIstate = AIstate.AIstate(aggression_input) aggression_trait = foAIstate.character.get_trait(Aggression) debug( "New game started, AI Aggression level %d (%s)" % (aggression_trait.key, get_trait_name_aggression(foAIstate.character))) foAIstate.session_start_cleanup() debug("Initialization of foAIstate complete!") debug("Trying to rename our homeworld...") planet_id = PlanetUtilsAI.get_capital() universe = fo.getUniverse() if planet_id is not None and planet_id != INVALID_ID: planet = universe.getPlanet(planet_id) new_name = " ".join([ random.choice(possible_capitals(foAIstate.character)).strip(), planet.name ]) debug(" Renaming to %s..." % new_name) res = fo.issueRenameOrder(planet_id, new_name) debug(" Result: %d; Planet is now named %s" % (res, planet.name)) diplomatic_corp_configs = { fo.aggression.beginner: DiplomaticCorp.BeginnerDiplomaticCorp, fo.aggression.maniacal: DiplomaticCorp.ManiacalDiplomaticCorp } global diplomatic_corp diplomatic_corp = diplomatic_corp_configs.get( aggression_trait.key, DiplomaticCorp.DiplomaticCorp)() TechsListsAI.test_tech_integrity()
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 _get_path_from_capital( planet: "fo.planet") -> Tuple[Sequence[SystemId], int]: """ Return chain of system from the planet to capital and length. If there is no path, return empty sequence and default distance. """ universe = fo.getUniverse() capital_id = PlanetUtilsAI.get_capital() if capital_id != INVALID_ID: homeworld = universe.getPlanet(capital_id) if homeworld and homeworld.systemID != INVALID_ID and planet.systemID != INVALID_ID: least_jumps_path = list( universe.leastJumpsPath(homeworld.systemID, planet.systemID, fo.empireID())) max_jumps = len(least_jumps_path) return least_jumps_path, max_jumps else: return [], 8
def get_repair_fleet_order(fleet_target, current_sys_id): """ Return fleet_orders.OrderRepair for fleet to proceed system with drydock. :param fleet_target: fleet that need to be repaired :type fleet_target: universe_object.Fleet # TODO check if we can remove this id, because fleet already have it. :param current_sys_id: current system id :type current_sys_id: int :return: order to repair :rtype fleet_orders.OrderRepair """ # TODO Cover new mechanics where happiness increases repair rate - don't always use nearest system! # find nearest supplied system drydock_sys_id = get_best_drydock_system_id(current_sys_id, fleet_target.id) if drydock_sys_id is None: return None print "ordering fleet %d to %s for repair" % (fleet_target.id, ppstring(PlanetUtilsAI.sys_name_ids([drydock_sys_id]))) # create resupply AIFleetOrder return fleet_orders.OrderRepair(fleet_target, universe_object.System(drydock_sys_id))
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 startNewGame(aggression=fo.aggression.aggressive): # pylint: disable=invalid-name """Called by client when a new game is started (but not when a game is loaded). Should clear any pre-existing state and set up whatever is needed for AI to generate orders.""" turn_timer.start("Server Processing") print "New game started, AI Aggression level %d" % aggression # initialize AIstate global foAIstate foAIstate = AIstate.AIstate(aggression=aggression) foAIstate.session_start_cleanup() print "Initialized foAIstate class" planet_id = PlanetUtilsAI.get_capital() universe = fo.getUniverse() if planet_id is not None and planet_id != -1: planet = universe.getPlanet(planet_id) new_name = random.choice(_capitols.get( aggression, "").split('\n')).strip() + " " + planet.name print "Capitol City Names are: ", _capitols print "This Capitol New name is ", new_name res = fo.issueRenameOrder(planet_id, new_name) print "Capitol Rename attempt result: %d; planet now named %s" % ( res, planet.name)
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 _rate_artisan_planet(self, pid: PlanetId, species_name: SpeciesName) -> float: focus_bonus = fo.getNamedValue("ARTISANS_INFLUENCE_FLAT_FOCUS") focus_minimum = fo.getNamedValue("ARTISANS_MIN_STABILITY_FOCUS") species_focus_bonus = focus_bonus * get_species_tag_value( species_name, Tags.INFLUENCE) planet = self._universe.getPlanet(pid) stability = planet.currentMeterValue(fo.meterType.targetHappiness) # First check whether the planet would currently get the focus bonus. if planet.focus == FocusType.FOCUS_INFLUENCE: return 3 * species_focus_bonus if stability >= focus_minimum else 0.0 # Planet does not have influence focus... # Check for the non-focus bonus. Since we would get this "for free", rate it higher non_focus_bonus = fo.getNamedValue("ARTISANS_INFLUENCE_FLAT_NO_FOCUS") non_focus_minimum = fo.getNamedValue("ARTISANS_MIN_STABILITY_NO_FOCUS") rating = 0.0 if stability >= non_focus_minimum: rating += 4 * non_focus_bonus # Check whether this planet would get the focus bonus, if we'd switch it to influence. if PlanetUtilsAI.stability_with_focus( planet, FocusType.FOCUS_INFLUENCE) >= focus_minimum: rating += species_focus_bonus return rating
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_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 evaluate_invasion_planet(planet_id, secure_fleet_missions, verbose=True): """Return the invasion value (score, troops) of a planet.""" universe = fo.getUniverse() empire_id = fo.empireID() detail = [] planet = universe.getPlanet(planet_id) if planet is None: print "Invasion AI couldn't access any info for planet id %d" % planet_id return [0, 0] system_id = planet.systemID # by using the following instead of simply relying on stealth meter reading, can (sometimes) plan ahead even if # planet is temporarily shrouded by an ion storm predicted_detectable = EspionageAI.colony_detectable_by_empire( planet_id, empire_id=fo.empireID(), default_result=False) if not predicted_detectable: if get_partial_visibility_turn(planet_id) < fo.currentTurn(): debug("InvasionAI predicts planet id %d to be stealthed" % planet_id) return [0, 0] else: debug( "InvasionAI predicts planet id %d to be stealthed" % planet_id + ", but somehow have current visibity anyway, will still consider as target" ) # Check if the target planet was extra-stealthed somehow its system was last viewed # this test below may augment the tests above, but can be thrown off by temporary combat-related sighting system_last_seen = get_partial_visibility_turn(planet_id) planet_last_seen = get_partial_visibility_turn(system_id) if planet_last_seen < system_last_seen: # TODO: track detection strength, order new scouting when it goes up debug( "Invasion AI considering planet id %d (stealthed at last view), still proceeding." % planet_id) # get a baseline evaluation of the planet as determined by ColonisationAI species_name = planet.speciesName species = fo.getSpecies(species_name) if not species or AIDependencies.TAG_DESTROYED_ON_CONQUEST in species.tags: # this call iterates over this Empire's available species with which it could colonize after an invasion planet_eval = ColonisationAI.assign_colonisation_values( [planet_id], MissionType.INVASION, None, detail) colony_base_value = max( 0.75 * planet_eval.get(planet_id, [0])[0], ColonisationAI.evaluate_planet(planet_id, MissionType.OUTPOST, None, detail)) else: colony_base_value = ColonisationAI.evaluate_planet( planet_id, MissionType.INVASION, species_name, detail) # Add extra score for all buildings on the planet building_values = { "BLD_IMPERIAL_PALACE": 1000, "BLD_CULTURE_ARCHIVES": 1000, "BLD_AUTO_HISTORY_ANALYSER": 100, "BLD_SHIPYARD_BASE": 100, "BLD_SHIPYARD_ORG_ORB_INC": 200, "BLD_SHIPYARD_ORG_XENO_FAC": 200, "BLD_SHIPYARD_ORG_CELL_GRO_CHAMB": 200, "BLD_SHIPYARD_CON_NANOROBO": 300, "BLD_SHIPYARD_CON_GEOINT": 400, "BLD_SHIPYARD_CON_ADV_ENGINE": 1000, "BLD_SHIPYARD_AST": 300, "BLD_SHIPYARD_AST_REF": 1000, "BLD_SHIPYARD_ENRG_SOLAR": 1500, "BLD_INDUSTRY_CENTER": 500, "BLD_GAS_GIANT_GEN": 200, "BLD_SOL_ORB_GEN": 800, "BLD_BLACK_HOLE_POW_GEN": 2000, "BLD_ENCLAVE_VOID": 500, "BLD_NEUTRONIUM_EXTRACTOR": 2000, "BLD_NEUTRONIUM_SYNTH": 2000, "BLD_NEUTRONIUM_FORGE": 1000, "BLD_CONC_CAMP": 100, "BLD_BIOTERROR_PROJECTOR": 1000, "BLD_SHIPYARD_ENRG_COMP": 3000, } bld_tally = 0 for bldType in [ universe.getBuilding(bldg).buildingTypeName for bldg in planet.buildingIDs ]: bval = building_values.get(bldType, 50) bld_tally += bval detail.append("%s: %d" % (bldType, bval)) # Add extra score for unlocked techs when we conquer the species tech_tally = 0 value_per_pp = 4 for unlocked_tech in AIDependencies.SPECIES_TECH_UNLOCKS.get( species_name, []): if not tech_is_complete(unlocked_tech): rp_cost = fo.getTech(unlocked_tech).researchCost(empire_id) tech_value = value_per_pp * rp_cost tech_tally += tech_value detail.append("%s: %d" % (unlocked_tech, tech_value)) max_jumps = 8 capitol_id = PlanetUtilsAI.get_capital() least_jumps_path = [] clear_path = True if capitol_id: homeworld = universe.getPlanet(capitol_id) if homeworld and homeworld.systemID != INVALID_ID and system_id != INVALID_ID: least_jumps_path = list( universe.leastJumpsPath(homeworld.systemID, system_id, empire_id)) max_jumps = len(least_jumps_path) system_status = foAI.foAIstate.systemStatus.get(system_id, {}) system_fleet_treat = system_status.get('fleetThreat', 1000) system_monster_threat = system_status.get('monsterThreat', 0) sys_total_threat = system_fleet_treat + system_monster_threat + system_status.get( 'planetThreat', 0) max_path_threat = system_fleet_treat mil_ship_rating = MilitaryAI.cur_best_mil_ship_rating() for path_sys_id in least_jumps_path: path_leg_status = foAI.foAIstate.systemStatus.get(path_sys_id, {}) path_leg_threat = path_leg_status.get( 'fleetThreat', 1000) + path_leg_status.get('monsterThreat', 0) if path_leg_threat > 0.5 * mil_ship_rating: clear_path = False if path_leg_threat > max_path_threat: max_path_threat = path_leg_threat pop = planet.currentMeterValue(fo.meterType.population) target_pop = planet.currentMeterValue(fo.meterType.targetPopulation) troops = planet.currentMeterValue(fo.meterType.troops) troop_regen = planet.currentMeterValue( fo.meterType.troops) - planet.initialMeterValue(fo.meterType.troops) max_troops = planet.currentMeterValue(fo.meterType.maxTroops) # TODO: refactor troop determination into function for use in mid-mission updates and also consider defender techs max_troops += AIDependencies.TROOPS_PER_POP * (target_pop - pop) this_system = universe.getSystem(system_id) secure_targets = [system_id] + list(this_system.planetIDs) system_secured = False for mission in secure_fleet_missions: if system_secured: break secure_fleet_id = mission.fleet.id s_fleet = universe.getFleet(secure_fleet_id) if not s_fleet or s_fleet.systemID != system_id: continue if mission.type == MissionType.SECURE: target_obj = mission.target.get_object() if target_obj is not None and target_obj.id in secure_targets: system_secured = True break system_secured = system_secured and system_status.get('myFleetRating', 0) if verbose: print("Invasion eval of %s\n" " - maxShields: %.1f\n" " - sysFleetThreat: %.1f\n" " - sysMonsterThreat: %.1f") % ( planet, planet.currentMeterValue(fo.meterType.maxShield), system_fleet_treat, system_monster_threat) enemy_val = 0 if planet.owner != -1: # value in taking this away from an enemy enemy_val = 20 * ( planet.currentMeterValue(fo.meterType.targetIndustry) + 2 * planet.currentMeterValue(fo.meterType.targetResearch)) # devalue invasions that would require too much military force preferred_max_portion = MilitaryAI.get_preferred_max_military_portion_for_single_battle( ) total_max_mil_rating = MilitaryAI.get_concentrated_tot_mil_rating() threat_exponent = 2 # TODO: make this a character trait; higher aggression with a lower exponent threat_factor = min( 1, preferred_max_portion * total_max_mil_rating / (sys_total_threat + 0.001))**threat_exponent design_id, _, locs = ProductionAI.get_best_ship_info( PriorityType.PRODUCTION_INVASION) if not locs or not universe.getPlanet(locs[0]): # We are in trouble anyway, so just calculate whatever approximation... build_time = 4 planned_troops = troops if system_secured else min( troops + troop_regen * (max_jumps + build_time), max_troops) planned_troops += .01 # we must attack with more troops than there are defenders troop_cost = math.ceil((planned_troops + _TROOPS_SAFETY_MARGIN) / 6.0) * 20 * FleetUtilsAI.get_fleet_upkeep() else: loc = locs[0] species_here = universe.getPlanet(loc).speciesName design = fo.getShipDesign(design_id) cost_per_ship = design.productionCost(empire_id, loc) build_time = design.productionTime(empire_id, loc) troops_per_ship = CombatRatingsAI.weight_attack_troops( design.troopCapacity, CombatRatingsAI.get_species_troops_grade(species_here)) planned_troops = troops if system_secured else min( troops + troop_regen * (max_jumps + build_time), max_troops) planned_troops += .01 # we must attack with more troops than there are defenders ships_needed = math.ceil( (planned_troops + _TROOPS_SAFETY_MARGIN) / float(troops_per_ship)) troop_cost = ships_needed * cost_per_ship # fleet upkeep is already included in query from server # apply some bias to expensive operations normalized_cost = float(troop_cost) / max(fo.getEmpire().productionPoints, 1) normalized_cost = max(1., normalized_cost) cost_score = (normalized_cost**2 / 50.0) * troop_cost base_score = colony_base_value + bld_tally + tech_tally + enemy_val - cost_score # If the AI does have enough total miltary to attack this target, and the target is more than minimally valuable, # don't let the threat_factor discount the adjusted value below MIN_INVASION_SCORE +1, so that if there are no # other targets the AI could still pursue this one. Otherwise, scoring pressure from # MilitaryAI.get_preferred_max_military_portion_for_single_battle might prevent the AI from attacking heavily # defended but still defeatable targets even if it has no softer targets available. if total_max_mil_rating > sys_total_threat and base_score > 2 * MIN_INVASION_SCORE: threat_factor = max(threat_factor, (MIN_INVASION_SCORE + 1) / base_score) planet_score = retaliation_risk_factor(planet.owner) * threat_factor * max( 0, base_score) if clear_path: planet_score *= 1.5 if verbose: print(' - planet score: %.2f\n' ' - planned troops: %.2f\n' ' - projected troop cost: %.1f\n' ' - threat factor: %s\n' ' - planet detail: %s\n' ' - popval: %.1f\n' ' - bldval: %s\n' ' - enemyval: %s') % (planet_score, planned_troops, troop_cost, threat_factor, detail, colony_base_value, bld_tally, enemy_val) return [planet_score, planned_troops]