def assign_invasion_values(planet_ids, mission_type, fleet_suppliable_planet_ids, empire): """Creates a dictionary that takes planet_ids as key and their invasion score as value.""" planet_values = {} neighbor_values = {} neighbor_val_ratio = .95 universe = fo.getUniverse() secure_missions = foAI.foAIstate.get_fleet_missions_with_any_mission_types([EnumsAI.AIFleetMissionType.FLEET_MISSION_SECURE]) for pid in planet_ids: planet_values[pid] = neighbor_values.setdefault(pid, evaluate_invasion_planet(pid, empire, secure_missions)) print "planet %d, values %s" % (pid, planet_values[pid]) planet = universe.getPlanet(pid) species_name = (planet and planet.speciesName) or "" species = fo.getSpecies(species_name) if species and species.canProduceShips: system = universe.getSystem(planet.systemID) if not system: continue planet_industries = {} for pid2 in system.planetIDs: planet2 = universe.getPlanet(pid2) species_name2 = (planet2 and planet2.speciesName) or "" species2 = fo.getSpecies(species_name2) if species2 and species2.canProduceShips: planet_industries[pid2] = planet2.currentMeterValue(fo.meterType.industry) + 0.1 # to prevent divide-by-zero industry_ratio = planet_industries[pid] / max(planet_industries.values()) for pid2 in system.planetIDs: if pid2 == pid: continue planet2 = universe.getPlanet(pid2) if planet2 and (planet2.owner != empire.empireID) and ((planet2.owner != -1) or (planet.currentMeterValue(fo.meterType.population) > 0)): # TODO check for allies planet_values[pid][0] += industry_ratio * neighbor_val_ratio * (neighbor_values.setdefault(pid2, evaluate_invasion_planet(pid2, empire, secure_missions))[0]) return planet_values
def _calculate_get_planet_opinions() -> Dict[str, Opinion]: universe = fo.getUniverse() all_species = [ universe.getPlanet(pid).speciesName for pid in get_owned_planets_by_empire() ] all_species += get_extra_colony_builders() all_features = set() for species_name in all_species: if species_name: species = fo.getSpecies(species_name) all_features.update(species.likes) all_features.update(species.dislikes) result = { feature: Opinion(set(), set(), set()) for feature in all_features } for pid in get_owned_planets_by_empire(): species = _planet_species(pid) for feature, opinion in result.items(): if species: if feature in species.likes: opinion.likes.add(pid) elif feature in species.dislikes: opinion.dislikes.add(pid) else: opinion.neutral.add(pid) # else: no species -> neutral opinion.neutral.add(pid) return result
def test_calc_max_pop(): """ Verify AI calculation of max population by comparing it with actual client queried values. This function may be called in debug mode in a running game and will compare the actual target population meters on all planets owned by this AI with the predicted maximum population. Any mismatch will be reported in chat. """ from freeorion_tools import chat_human chat_human("Verifying calculation of ColonisationAI.calc_max_pop()") universe = fo.getUniverse() for spec_name, planets in get_empire_planets_by_species().items(): species = fo.getSpecies(spec_name) for pid in planets: planet = universe.getPlanet(pid) detail = [] predicted = calc_max_pop(planet, species, detail) actual = planet.initialMeterValue(fo.meterType.targetPopulation) if actual != predicted: error( "Predicted pop of %.2f on %s but actually is %.2f; Details: %s" % (predicted, planet, actual, "\n".join(detail)) ) chat_human("Finished verification of ColonisationAI.calc_max_pop()")
def get_piloting_grades(self, species_name): if species_name in piloting_grades: return piloting_grades[species_name] weapons_grade="" shields_grade="" if species_name == "": spec_tags = [] else: species = fo.getSpecies(species_name) if species: spec_tags = species.tags else: print "Error: get_piloting_grades couldn't retrieve species '%s'" % species_name spec_tags = [] for tag in spec_tags: if "AI_TAG" not in tag: continue tag_parts = tag.split('_') tag_type = tag_parts[3] if tag_type == 'WEAPONS': weapons_grade = tag_parts[2] elif tag_type == 'SHIELDS': shields_grade = tag_parts[2] piloting_grades[species_name] = (weapons_grade, shields_grade) return (weapons_grade, shields_grade)
def assign_invasion_values(planet_ids): """Creates a dictionary that takes planet_ids as key and their invasion score as value.""" empire_id = fo.empireID() planet_values = {} neighbor_values = {} neighbor_val_ratio = .95 universe = fo.getUniverse() secure_missions = get_aistate().get_fleet_missions_with_any_mission_types( [MissionType.SECURE, MissionType.MILITARY]) for pid in planet_ids: planet_values[pid] = neighbor_values.setdefault( pid, evaluate_invasion_planet(pid, secure_missions)) debug("planet %d, values %s", pid, planet_values[pid]) planet = universe.getPlanet(pid) species_name = (planet and planet.speciesName) or "" species = fo.getSpecies(species_name) if species and species.canProduceShips: system = universe.getSystem(planet.systemID) if not system: continue planet_industries = {} for pid2 in system.planetIDs: planet2 = universe.getPlanet(pid2) species_name2 = (planet2 and planet2.speciesName) or "" species2 = fo.getSpecies(species_name2) if species2 and species2.canProduceShips: # to prevent divide-by-zero planet_industries[pid2] = planet2.initialMeterValue( fo.meterType.industry) + 0.1 industry_ratio = planet_industries[pid] / max( planet_industries.values()) for pid2 in system.planetIDs: if pid2 == pid: continue planet2 = universe.getPlanet(pid2) # TODO check for allies if (planet2 and (planet2.owner != empire_id) and ( (planet2.owner != -1) or (planet2.initialMeterValue(fo.meterType.population) > 0))): planet_values[pid][0] += ( industry_ratio * neighbor_val_ratio * (neighbor_values.setdefault( pid2, evaluate_invasion_planet(pid2, secure_missions))[0])) return planet_values
def get_species_tag_grade(species_name, tag_type): if not species_name: return "" species = fo.getSpecies(species_name) if assertion_fails(species is not None): return "" return get_ai_tag_grade(species.tags, tag_type)
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 _get_species_grades(species_name, grade_type): spec_tags = [] if species_name: species = fo.getSpecies(species_name) if species: spec_tags = species.tags else: print >> sys.stderr, "get_species_grades() couldn't retrieve species '%s'\n" % species_name return get_ai_tag_grade(spec_tags, grade_type)
def _get_species_grades(species_name, grade_type): spec_tags = [] if species_name: species = fo.getSpecies(species_name) if species: spec_tags = species.tags else: warn("get_species_grades() couldn't retrieve species '%s'\n" % species_name) return get_ai_tag_grade(spec_tags, grade_type)
def _get_species_grades(species_name, grade_type): spec_tags = [] if species_name: species = fo.getSpecies(species_name) if species: spec_tags = species.tags else: sys.stderr.write("Error: get_species_grades couldn't retrieve species '%s'\n" % species_name) return get_ai_tag_grade(spec_tags, grade_type)
def _planet_species(pid: PlanetId) -> Optional[fo.species]: universe = fo.getUniverse() planet = universe.getPlanet(pid) species_name = planet.speciesName if not species_name: species_name = _planned_species().get(pid) if species_name: return fo.getSpecies(species_name) return None
def get_species_tag_grade(species_name: str, tag_type: AIDependencies.Tags) -> str: """Determine grade string ("NO", "BAD", "GOOD", etc.), if any, for given tag and species.""" if not species_name: return "" species = fo.getSpecies(species_name) if assertion_fails(species is not None): return "" return get_ai_tag_grade(species.tags, tag_type)
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 assign_invasion_values(planet_ids): """Creates a dictionary that takes planet_ids as key and their invasion score as value.""" empire_id = fo.empireID() planet_values = {} neighbor_values = {} neighbor_val_ratio = .95 universe = fo.getUniverse() secure_missions = get_aistate().get_fleet_missions_with_any_mission_types([MissionType.SECURE, MissionType.MILITARY]) for pid in planet_ids: planet_values[pid] = neighbor_values.setdefault(pid, evaluate_invasion_planet(pid, secure_missions)) debug("planet %d, values %s", pid, planet_values[pid]) planet = universe.getPlanet(pid) species_name = (planet and planet.speciesName) or "" species = fo.getSpecies(species_name) if species and species.canProduceShips: system = universe.getSystem(planet.systemID) if not system: continue planet_industries = {} for pid2 in system.planetIDs: planet2 = universe.getPlanet(pid2) species_name2 = (planet2 and planet2.speciesName) or "" species2 = fo.getSpecies(species_name2) if species2 and species2.canProduceShips: # to prevent divide-by-zero planet_industries[pid2] = planet2.initialMeterValue(fo.meterType.industry) + 0.1 industry_ratio = planet_industries[pid] / max(planet_industries.values()) for pid2 in system.planetIDs: if pid2 == pid: continue planet2 = universe.getPlanet(pid2) # TODO check for allies if (planet2 and (planet2.owner != empire_id) and ((planet2.owner != -1) or (planet2.initialMeterValue(fo.meterType.population) > 0))): planet_values[pid][0] += ( industry_ratio * neighbor_val_ratio * (neighbor_values.setdefault(pid2, evaluate_invasion_planet(pid2, secure_missions))[0]) ) return planet_values
def stability_with_focus(planet: fo.planet, focus: str) -> float: """ What would the planets target stability be when switched to the given focus. Returns -99 if species cannot use the specified focus. """ stability = planet.currentMeterValue(fo.meterType.targetHappiness) species = fo.getSpecies(planet.speciesName) if focus not in species.foci: # The actual value here is not important. If some part of the AI asks for a stability, # returning a big negative value here should stop it from considering that focus for anything. return -99.0 return stability - focus_stability_effect( species, planet.focus) + focus_stability_effect(species, focus)
def assignColonisationValues(planetIDs, missionType, fleetSupplyablePlanetIDs, species, empire): "creates a dictionary that takes planetIDs as key and their colonisation score as value" planetValues = {} for planetID in planetIDs: pv = [] for specName in empireColonizers: thisSpecies=fo.getSpecies(specName) pv.append( (evaluatePlanet(planetID, missionType, fleetSupplyablePlanetIDs, thisSpecies, empire), specName) ) best = sorted(pv)[-1:] if best!=[]: if (missionType == AIFleetMissionType.FLEET_MISSION_OUTPOST ): planetValues[planetID] = (best[0][0], "") else: planetValues[planetID] = best[0] return planetValues
def assignColonisationValues(planetIDs, missionType, fleetSupplyablePlanetIDs, species, empire): #TODO: clean up supplyable versus annexable "creates a dictionary that takes planetIDs as key and their colonisation score as value" planetValues = {} for planetID in planetIDs: pv = [] for specName in empireColonizers: thisSpecies=fo.getSpecies(specName) pv.append( (evaluatePlanet(planetID, missionType, fleetSupplyablePlanetIDs, thisSpecies, empire), specName) ) best = sorted(pv)[-1:] if best!=[]: if (missionType == AIFleetMissionType.FLEET_MISSION_OUTPOST ): planetValues[planetID] = (best[0][0], "") else:#TODO: check for system-local colonizer; also, if a tie amongst top try to choose empire main species planetValues[planetID] = best[0] return planetValues
def _rate_artisans(self) -> float: """Rate artisan workshops.""" # Diversity unlocks artisans, so if we have diversity, we could unlock artisans if diversity not in self._empire.availablePolicies: return 0.0 # TBD: could use _calculate_empire_output, but we'd still have to check the species, since artistic # species may not be switched to influence. rating = 0.0 artists = [] for species_name, planets in get_empire_planets_by_species().items(): species = fo.getSpecies(species_name) if Tags.ARTISTIC in species.tags: artists.append(species_name) for pid in planets: rating += self._rate_artisan_planet(pid, species_name) rating += self._rate_opinion(artisans) debug(f"_rate_artisans: {rating}, artists: {artists}") return rating
def _print_empire_species_roster(): """Print empire species roster in table format to log.""" grade_map = {"ULTIMATE": "+++", "GREAT": "++", "GOOD": "+", "AVERAGE": "o", "BAD": "-", "NO": "---"} grade_tags = [ Tags.INDUSTRY, Tags.RESEARCH, Tags.POPULATION, Tags.SUPPLY, Tags.WEAPONS, Tags.ATTACKTROOPS, ] grade_tags_names = { Tags.INDUSTRY: "Ind.", Tags.RESEARCH: "Res.", Tags.POPULATION: "Pop.", Tags.SUPPLY: "Supply", Tags.WEAPONS: "Pilot", Tags.ATTACKTROOPS: "Troop", } species_table = Table( Text("species"), Sequence("PIDs"), Bool("Colonize"), Text("Shipyards"), *[Text(grade_tags_names[v]) for v in grade_tags], Sequence("Tags"), table_name="Empire species roster Turn %d" % fo.currentTurn(), ) for species_name, planet_ids in get_empire_planets_by_species().items(): species_tags = fo.getSpecies(species_name).tags number_of_shipyards = len(get_ship_builder_locations(species_name)) species_table.add_row( species_name, planet_ids, can_build_colony_for_species(species_name), number_of_shipyards, *[grade_map.get(get_species_tag_grade(species_name, tag).upper(), "o") for tag in grade_tags], [tag for tag in species_tags if not any(s in tag for s in grade_tags) and "PEDIA" not in tag], ) species_table.print_table(info)
def evaluateInvasionPlanet(planetID, missionType, fleetSupplyablePlanetIDs, empire): "return the invasion value of a planet" #TODO: add more factors, as used for colonization universe = fo.getUniverse() empireID = empire.empireID distanceFactor = 0 planet = universe.getPlanet(planetID) if (planet == None) : #TODO: exclude planets with stealth higher than empireDetection print "invasion AI couldn't get current info on planet %d"%planetID return 0, 0 capitalID = PlanetUtilsAI.getCapital() homeworld = universe.getPlanet(capitalID) if homeworld: homeSystemID = homeworld.systemID evalSystemID = planet.systemID leastJumpsPath = len(universe.leastJumpsPath(homeSystemID, evalSystemID, empireID)) distanceFactor = 4.0/(leastJumpsPath + 1) troops = planet.currentMeterValue(fo.meterType.troops) specName=planet.speciesName species=fo.getSpecies(specName) if not species:# perhaps stealth might make species info inaccessible targetPop=planet.currentMeterValue(fo.meterType.targetPopulation) if planetID in fleetSupplyablePlanetIDs: popVal = 4*targetPop else: popVal = 6*targetPop#assign higher value if the colony would extend our supply range planetSpecials = list(planet.specials) specialVal=0 if ( ( planet.size == fo.planetSize.asteroids ) and (empire.getTechStatus("PRO_ASTEROID_MINE") == fo.techStatus.complete ) ): specialVal= 15 # asteroid mining is great, fast return for special in [ "MINERALS_SPECIAL", "CRYSTALS_SPECIAL", "METALOIDS_SPECIAL"] : if special in planetSpecials: specialVal = 40 return popVal+specialVal, troops else: popVal = evaluatePlanet(planetID, AIFleetMissionType.FLEET_MISSION_COLONISATION, [planetID], species, empire) #evaluatePlanet is implorted from ColonisationAI if planetID not in fleetSupplyablePlanetIDs: popVal = 2.0*popVal#assign higher value if the colony would extend our supply range return popVal, troops
def assignColonisationValues(planetIDs, missionType, fleetSupplyablePlanetIDs, species, empire, detail=[]): #TODO: clean up supplyable versus annexable "creates a dictionary that takes planetIDs as key and their colonisation score as value" origDetail = detail planetValues = {} if (missionType == AIFleetMissionType.FLEET_MISSION_OUTPOST ): print "\n=========\nAssigning Outpost Values\n=========" trySpecies = [ "" ] else: print "\n=========\nAssigning Colony Values\n=========" trySpecies = list( empireColonizers ) for planetID in planetIDs: pv = [] for specName in trySpecies: thisSpecies=fo.getSpecies(specName) detail = origDetail[:] pv.append( (evaluatePlanet(planetID, missionType, fleetSupplyablePlanetIDs, thisSpecies, empire, detail), specName, list(detail)) ) best = sorted(pv)[-1:] if best!=[]: planetValues[planetID] = best[0][:2] print best[0][2] return planetValues
def is_valid(self) -> bool: """ Check the colonization plan for validity, i.e. if it could be executed in the future. The plan is valid if it is possible to outpost the target planet and if the planet envisioned to build the outpost bases can still do so. """ universe = fo.getUniverse() # make sure target is valid target = universe.getPlanet(self.target) if target is None or (not target.unowned) or target.speciesName: return False # make sure source is valid source = universe.getPlanet(self.source) if not (source and source.ownedBy(fo.empireID()) and source.speciesName and fo.getSpecies(source.speciesName).canColonize): return False # appears to be valid return True
def assignInvasionValues(planetIDs, missionType, fleetSupplyablePlanetIDs, empire): "creates a dictionary that takes planetIDs as key and their invasion score as value" planetValues = {} neighbor_values = {} universe = fo.getUniverse() secureAIFleetMissions = foAI.foAIstate.getAIFleetMissionsWithAnyMissionTypes([EnumsAI.AIFleetMissionType.FLEET_MISSION_SECURE]) for planetID in planetIDs: planetValues[planetID] = neighbor_values.setdefault(planetID, evaluateInvasionPlanet(planetID, missionType, fleetSupplyablePlanetIDs, empire, secureAIFleetMissions)) print "planet %d, values %s"%(planetID, planetValues[planetID]) planet = universe.getPlanet(planetID) specName = (planet and planet.speciesName) or "" species = fo.getSpecies(specName) if species and species.canProduceShips: system = universe.getSystem(planet.systemID) if not system: continue for pid2 in system.planetIDs: if pid2 == planetID: continue planet2 = universe.getPlanet(pid2) if planet2 and (planet2.owner != empire.empireID) and ((planet2.owner != -1) or (planet.currentMeterValue(fo.meterType.population) > 0)): #TODO check for allies planetValues[planetID][0] += 0.5 * (neighbor_values.setdefault( pid2, evaluateInvasionPlanet(pid2, missionType, fleetSupplyablePlanetIDs, empire, secureAIFleetMissions))[0]) return planetValues
def evaluate_invasion_planet(planet_id, secure_fleet_missions, verbose=True): """Return the invasion value (score, troops) of a planet.""" detail = [] 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, } # TODO: add more factors, as used for colonization universe = fo.getUniverse() empire_id = fo.empireID() max_jumps = 8 planet = universe.getPlanet(planet_id) if planet is None: # TODO: exclude planets with stealth higher than empireDetection print "invasion AI couldn't access any info for planet id %d" % planet_id return [0, 0] sys_partial_vis_turn = get_partial_visibility_turn(planet.systemID) planet_partial_vis_turn = get_partial_visibility_turn(planet_id) if planet_partial_vis_turn < sys_partial_vis_turn: print "invasion AI couldn't get current info on planet id %d (was stealthed at last sighting)" % planet_id # TODO: track detection strength, order new scouting when it goes up return [0, 0] # last time we had partial vis of the system, the planet was stealthed to us 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) pop_val = max(0.75 * planet_eval.get(planet_id, [0])[0], ColonisationAI.evaluate_planet(planet_id, MissionType.OUTPOST, None, detail)) else: pop_val = ColonisationAI.evaluate_planet(planet_id, MissionType.INVASION, species_name, detail) 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)) tech_tally = 0 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_tally += rp_cost * 4 detail.append("%s: %d" % (unlocked_tech, rp_cost * 4)) p_sys_id = planet.systemID capitol_id = PlanetUtilsAI.get_capital() least_jumps_path = [] clear_path = True if capitol_id: homeworld = universe.getPlanet(capitol_id) if homeworld: home_system_id = homeworld.systemID eval_system_id = planet.systemID if (home_system_id != INVALID_ID) and (eval_system_id != INVALID_ID): least_jumps_path = list(universe.leastJumpsPath(home_system_id, eval_system_id, empire_id)) max_jumps = len(least_jumps_path) system_status = foAI.foAIstate.systemStatus.get(p_sys_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) 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(p_sys_id) secure_targets = [p_sys_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 != p_sys_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) supply_val = 0 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)) if p_sys_id in ColonisationAI.annexable_system_ids: # TODO: extend to rings supply_val = 100 elif p_sys_id in state.get_systems_by_supply_tier(-1): supply_val = 200 elif p_sys_id in state.get_systems_by_supply_tier(-2): supply_val = 300 elif p_sys_id in state.get_systems_by_supply_tier(-3): supply_val = 400 if max_path_threat > 0.5 * mil_ship_rating: if max_path_threat < 3 * mil_ship_rating: supply_val *= 0.5 else: supply_val *= 0.2 # devalue invasions that would require too much military force threat_factor = min(1, 0.2*MilitaryAI.get_tot_mil_rating()/(sys_total_threat+0.001))**2 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 + 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 + 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 = pop_val + supply_val + bld_tally + tech_tally + enemy_val - cost_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' ' - troop score: %.2f\n' ' - projected troop cost: %.1f\n' ' - threat factor: %s\n' ' - planet detail: %s\n' ' - popval: %.1f\n' ' - supplyval: %.1f\n' ' - bldval: %s\n' ' - enemyval: %s') % (planet_score, planned_troops, troop_cost, threat_factor, detail, pop_val, supply_val, bld_tally, enemy_val) return [planet_score, planned_troops]
def generate_classic_research_orders(): """generate research orders""" empire = fo.getEmpire() empire_id = empire.empireID aistate = get_aistate() enemies_sighted = aistate.misc.get("enemies_sighted", {}) galaxy_is_sparse = ColonisationAI.galaxy_is_sparse() resource_production = empire.resourceProduction(fo.resourceType.research) completed_techs = sorted(list(get_completed_techs())) _print_reserch_order_header(resource_production, completed_techs) # # report techs currently at head of research queue # research_queue = empire.researchQueue research_queue_list = get_research_queue_techs() total_rp = empire.resourceProduction(fo.resourceType.research) tech_turns_left = {} if research_queue_list: debug("Techs currently at head of Research Queue:") for element in list(research_queue)[:10]: tech_turns_left[element.tech] = element.turnsLeft this_tech = fo.getTech(element.tech) if not this_tech: warning("Can't retrieve tech ", element.tech) continue missing_prereqs = [ preReq for preReq in this_tech.recursivePrerequisites(empire_id) if preReq not in completed_techs ] # unlocked_items = [(uli.name, uli.type) for uli in this_tech.unlocked_items] unlocked_items = [uli.name for uli in this_tech.unlockedItems] if not missing_prereqs: debug( " %25s allocated %6.2f RP (%d turns left)-- unlockable items: %s ", element.tech, element.allocation, tech_turns_left[element.tech], unlocked_items, ) else: debug( " %25s allocated %6.2f RP -- missing preReqs: %s -- unlockable items: %s ", element.tech, element.allocation, missing_prereqs, unlocked_items, ) debug("") # # set starting techs, or after turn 100 add any additional default techs # if (fo.currentTurn() <= 2) or ((total_rp - research_queue.totalSpent) > 0): research_index = get_research_index() if fo.currentTurn() == 1: # do only this one on first turn, to facilitate use of a turn-1 savegame for testing of alternate # research strategies new_tech = ["LRN_PHYS_BRAIN", "GRO_PLANET_ECOL"] else: new_tech = (TechsListsAI.sparse_galaxy_techs(research_index) if galaxy_is_sparse else TechsListsAI.primary_meta_techs(research_index)) debug("Empire %s (%d) is selecting research index %d", empire.name, empire_id, research_index) # techs_to_enqueue = (set(new_tech)-(set(completed_techs)|set(research_queue_list))) techs_to_enqueue = new_tech[:] tech_base = set(completed_techs + research_queue_list) techs_to_add = [] for tech in techs_to_enqueue: if tech not in tech_base: this_tech = fo.getTech(tech) if this_tech is None: error("Desired tech '%s' appears to not exist" % tech) continue missing_prereqs = [ preReq for preReq in this_tech.recursivePrerequisites(empire_id) if preReq not in tech_base ] techs_to_add.extend(missing_prereqs + [tech]) tech_base.update(missing_prereqs + [tech]) cum_cost = 0 debug(" Enqueued Tech: %20s \t\t %8s \t %s", "Name", "Cost", "CumulativeCost") for name in techs_to_add: try: enqueue_res = fo.issueEnqueueTechOrder(name, -1) if enqueue_res == 1: this_tech = fo.getTech(name) this_cost = 0 if this_tech: this_cost = this_tech.researchCost(empire_id) cum_cost += this_cost debug(" Enqueued Tech: %20s \t\t %8.0f \t %8.0f", name, this_cost, cum_cost) else: warning(" Failed attempt to enqueued Tech: " + name) except: # noqa: E722 warning(" Failed attempt to enqueued Tech: " + name, exc_info=True) debug("\n\nAll techs:") debug("=" * 20) alltechs = fo.techs() print_in_columns(sorted(fo.techs()), columns=3) debug("\n\nAll unqueued techs:") debug("=" * 20) # coveredTechs = new_tech+completed_techs print_in_columns([tn for tn in alltechs if tn not in tech_base], columns=3) debug("") if fo.currentTurn() == 1: return if True: research_queue_list = get_research_queue_techs() def_techs = TechsListsAI.defense_techs_1() for def_tech in def_techs: if (aistate.character.may_research_tech_classic(def_tech) and def_tech not in research_queue_list[:5] and not tech_is_complete(def_tech)): res = fo.issueEnqueueTechOrder( def_tech, min(3, len(research_queue_list))) debug( "Empire is very defensive, so attempted to fast-track %s, got result %d", def_tech, res) if False: # with current stats of Conc Camps, disabling this fast-track research_queue_list = get_research_queue_techs() if "CON_CONC_CAMP" in research_queue_list and aistate.character.may_research_tech_classic( "CON_CONC_CAMP"): insert_idx = min(40, research_queue_list.index("CON_CONC_CAMP")) else: insert_idx = max(0, min(40, len(research_queue_list) - 10)) if "SHP_DEFLECTOR_SHIELD" in research_queue_list and aistate.character.may_research_tech_classic( "SHP_DEFLECTOR_SHIELD"): insert_idx = min( insert_idx, research_queue_list.index("SHP_DEFLECTOR_SHIELD")) for cc_tech in ["CON_ARCH_PSYCH", "CON_CONC_CAMP"]: if (cc_tech not in research_queue_list[:insert_idx + 1] and not tech_is_complete(cc_tech) and aistate.character.may_research_tech_classic(cc_tech)): res = fo.issueEnqueueTechOrder(cc_tech, insert_idx) debug( "Empire is very aggressive, so attempted to fast-track %s, got result %d", cc_tech, res) elif fo.currentTurn() > 100: generate_default_research_order() research_queue_list = get_research_queue_techs() num_techs_accelerated = 1 # will ensure leading tech doesn't get dislodged got_ggg_tech = tech_is_complete("PRO_ORBITAL_GEN") got_sym_bio = tech_is_complete("GRO_SYMBIOTIC_BIO") got_xeno_gen = tech_is_complete("GRO_XENO_GENETICS") # # Consider accelerating techs; priority is # Supply/Detect range # xeno arch # ast / GG # gro xeno gen # distrib thought # quant net # pro sing gen # death ray 1 cleanup nest_tech = Dep.NEST_DOMESTICATION_TECH artif_minds = Dep.LRN_ARTIF_MINDS_1 if have_nest() and not tech_is_complete(nest_tech): if artif_minds in research_queue_list: insert_idx = 1 + research_queue_list.index(artif_minds) else: insert_idx = 1 res = fo.issueEnqueueTechOrder(nest_tech, insert_idx) num_techs_accelerated += 1 debug( "Have a monster nest, so attempted to fast-track %s, got result %d", nest_tech, res) research_queue_list = get_research_queue_techs() # # Supply range and detection range if False: # disabled for now, otherwise just to help with cold-folding / organization if len(aistate.colonisablePlanetIDs) == 0: best_colony_site_score = 0 else: best_colony_site_score = next( iter(aistate.colonisablePlanetIDs.items()))[1] if len(aistate.colonisableOutpostIDs) == 0: best_outpost_site_score = 0 else: best_outpost_site_score = next( iter(aistate.colonisableOutpostIDs.items()))[1] need_improved_scouting = best_colony_site_score < 150 or best_outpost_site_score < 200 if need_improved_scouting: if not tech_is_complete("CON_ORBITAL_CON"): num_techs_accelerated += 1 if ("CON_ORBITAL_CON" not in research_queue_list[:1 + num_techs_accelerated] ) and (tech_is_complete("PRO_FUSION_GEN") or ("PRO_FUSION_GEN" in research_queue_list[:1 + num_techs_accelerated])): res = fo.issueEnqueueTechOrder("CON_ORBITAL_CON", num_techs_accelerated) debug( "Empire has poor colony/outpost prospects, so attempted to fast-track %s, got result %d", "CON_ORBITAL_CON", res, ) elif not tech_is_complete("CON_CONTGRAV_ARCH"): num_techs_accelerated += 1 if ("CON_CONTGRAV_ARCH" not in research_queue_list[:1 + num_techs_accelerated] ) and (tech_is_complete("CON_METRO_INFRA")): for supply_tech in [ _s_tech for _s_tech in ["CON_ARCH_MONOFILS", "CON_CONTGRAV_ARCH"] if not tech_is_complete(_s_tech) ]: res = fo.issueEnqueueTechOrder(supply_tech, num_techs_accelerated) debug( "Empire has poor colony/outpost prospects, so attempted to fast-track %s, got result %d", supply_tech, res, ) else: pass research_queue_list = get_research_queue_techs() # could add more supply tech if False and not tech_is_complete( "SPY_DETECT_2"): # disabled for now, detect2 num_techs_accelerated += 1 if "SPY_DETECT_2" not in research_queue_list[:2 + num_techs_accelerated] and tech_is_complete( "PRO_FUSION_GEN" ): if "CON_ORBITAL_CON" not in research_queue_list[:1 + num_techs_accelerated]: res = fo.issueEnqueueTechOrder("SPY_DETECT_2", num_techs_accelerated) else: co_idx = research_queue_list.index("CON_ORBITAL_CON") res = fo.issueEnqueueTechOrder("SPY_DETECT_2", co_idx + 1) debug( "Empire has poor colony/outpost prospects, so attempted to fast-track %s, got result %d" "CON_ORBITAL_CON", res, ) research_queue_list = get_research_queue_techs() # # check to accelerate xeno_arch if True: # just to help with cold-folding / organization if (have_ruins() and not tech_is_complete("LRN_XENOARCH") and aistate.character.may_research_tech_classic("LRN_XENOARCH")): if artif_minds in research_queue_list: insert_idx = 7 + research_queue_list.index(artif_minds) elif "GRO_SYMBIOTIC_BIO" in research_queue_list: insert_idx = research_queue_list.index("GRO_SYMBIOTIC_BIO") + 1 else: insert_idx = num_techs_accelerated if "LRN_XENOARCH" not in research_queue_list[:insert_idx]: for xenoTech in [ "LRN_XENOARCH", "LRN_TRANSLING_THT", "LRN_PHYS_BRAIN", "LRN_ALGO_ELEGANCE" ]: if not tech_is_complete( xenoTech ) and xenoTech not in research_queue_list[:(insert_idx + 4)]: res = fo.issueEnqueueTechOrder(xenoTech, insert_idx) num_techs_accelerated += 1 debug( "ANCIENT_RUINS: have an ancient ruins, so attempted to fast-track %s to enable LRN_XENOARCH, got result %d", xenoTech, res, ) research_queue_list = get_research_queue_techs() if False and not enemies_sighted: # curently disabled # params = [ (tech, gate, target_slot, add_tech_list), ] params = [ ("GRO_XENO_GENETICS", "PRO_EXOBOTS", "PRO_EXOBOTS", ["GRO_GENETIC_MED", "GRO_XENO_GENETICS"]), ("PRO_EXOBOTS", "PRO_ADAPTIVE_AUTOMATION", "PRO_ADAPTIVE_AUTOMATION", ["PRO_EXOBOTS"]), ("PRO_ADAPTIVE_AUTOMATION", "PRO_NANOTECH_PROD", "PRO_NANOTECH_PROD", ["PRO_ADAPTIVE_AUTOMATION"]), ( "PRO_INDUSTRY_CENTER_I", "GRO_SYMBIOTIC_BIO", "GRO_SYMBIOTIC_BIO", [ "PRO_ROBOTIC_PROD", "PRO_FUSION_GEN", "PRO_INDUSTRY_CENTER_I" ], ), ("GRO_SYMBIOTIC_BIO", "SHP_ORG_HULL", "SHP_ZORTRIUM_PLATE", ["GRO_SYMBIOTIC_BIO"]), ] for (tech, gate, target_slot, add_tech_list) in params: if tech_is_complete(tech): break if tech_turns_left.get(gate, 0) not in [ 0, 1, 2, ]: # needs to exclude -1, the flag for no predicted completion continue if target_slot in research_queue_list: target_index = 1 + research_queue_list.index(target_slot) else: target_index = num_techs_accelerated for move_tech in add_tech_list: debug( "for tech %s, target_slot %s, target_index:%s ; num_techs_accelerated:%s", move_tech, target_slot, target_index, num_techs_accelerated, ) if tech_is_complete(move_tech): continue if target_index <= num_techs_accelerated: num_techs_accelerated += 1 if move_tech not in research_queue_list[:1 + target_index]: fo.issueEnqueueTechOrder(move_tech, target_index) debug( "Research: To prioritize %s, have advanced %s to slot %d", tech, move_tech, target_index) target_index += 1 # # check to accelerate asteroid or GG tech if True: # just to help with cold-folding / organization if have_asteroids(): insert_idx = (num_techs_accelerated if "GRO_SYMBIOTIC_BIO" not in research_queue_list else research_queue_list.index("GRO_SYMBIOTIC_BIO")) ast_tech = "PRO_MICROGRAV_MAN" if not (tech_is_complete(ast_tech) or ast_tech in research_queue_list[:(1 + insert_idx)]): res = fo.issueEnqueueTechOrder(ast_tech, insert_idx) num_techs_accelerated += 1 debug( "Asteroids: plan to colonize an asteroid belt, so attempted to fast-track %s , got result %d", ast_tech, res, ) research_queue_list = get_research_queue_techs() elif tech_is_complete("SHP_ZORTRIUM_PLATE"): insert_idx = ( (1 + insert_idx) if "LRN_FORCE_FIELD" not in research_queue_list else max( 1 + insert_idx, research_queue_list.index("LRN_FORCE_FIELD") - 1)) for ast_tech in [ "SHP_ASTEROID_HULLS", "SHP_IMPROVED_ENGINE_COUPLINGS" ]: if not tech_is_complete( ast_tech ) and ast_tech not in research_queue_list[:insert_idx + 1]: res = fo.issueEnqueueTechOrder(ast_tech, insert_idx) num_techs_accelerated += 1 insert_idx += 1 debug( "Asteroids: plan to colonize an asteroid belt, so attempted to fast-track %s , got result %d", ast_tech, res, ) research_queue_list = get_research_queue_techs() if have_gas_giant() and not tech_is_complete("PRO_ORBITAL_GEN"): fusion_idx = (0 if "PRO_FUSION_GEN" not in research_queue_list else (1 + research_queue_list.index("PRO_FUSION_GEN"))) forcefields_idx = (0 if "LRN_FORCE_FIELD" not in research_queue_list else (1 + research_queue_list.index("LRN_FORCE_FIELD"))) insert_idx = max( fusion_idx, forcefields_idx) if enemies_sighted else fusion_idx if "PRO_ORBITAL_GEN" not in research_queue_list[:insert_idx + 1]: res = fo.issueEnqueueTechOrder("PRO_ORBITAL_GEN", insert_idx) num_techs_accelerated += 1 debug( "GasGiant: plan to colonize a gas giant, so attempted to fast-track %s, got result %d", "PRO_ORBITAL_GEN", res, ) research_queue_list = get_research_queue_techs() # # assess if our empire has any non-lousy colonizers, & boost gro_xeno_gen if we don't if True: # just to help with cold-folding / organization if got_ggg_tech and got_sym_bio and (not got_xeno_gen): most_adequate = 0 for specName in get_colony_builders(): environs = {} this_spec = fo.getSpecies(specName) if not this_spec: continue for ptype in [ fo.planetType.swamp, fo.planetType.radiated, fo.planetType.toxic, fo.planetType.inferno, fo.planetType.barren, fo.planetType.tundra, fo.planetType.desert, fo.planetType.terran, fo.planetType.ocean, fo.planetType.asteroids, ]: environ = this_spec.getPlanetEnvironment(ptype) environs.setdefault(environ, []).append(ptype) most_adequate = max( most_adequate, len(environs.get(fo.planetEnvironment.adequate, []))) if most_adequate == 0: insert_idx = num_techs_accelerated for xg_tech in ["GRO_XENO_GENETICS", "GRO_GENETIC_ENG"]: if (xg_tech not in research_queue_list[:1 + num_techs_accelerated] and not tech_is_complete(xg_tech) and aistate.character.may_research_tech_classic( xg_tech)): res = fo.issueEnqueueTechOrder(xg_tech, insert_idx) num_techs_accelerated += 1 debug( "Empire has poor colonizers, so attempted to fast-track %s, got result %d", xg_tech, res, ) research_queue_list = get_research_queue_techs() # # check to accelerate translinguistics if True: # just to help with cold-folding / organization # planet is needed to determine the cost. Without a capital we have bigger problems anyway... if not tech_is_complete("LRN_TRANSLING_THT") and translators_wanted(): insert_idx = num_techs_accelerated for dt_ech in [ "LRN_TRANSLING_THT", "LRN_PHYS_BRAIN", "LRN_ALGO_ELEGANCE" ]: if (dt_ech not in research_queue_list[:insert_idx + 2] and not tech_is_complete(dt_ech) and aistate.character.may_research_tech_classic(dt_ech)): res = fo.issueEnqueueTechOrder(dt_ech, insert_idx) num_techs_accelerated += 1 insert_idx += 1 fmt_str = "Empire wants to build translators, so attempted to fast-track %s (got result %d)" fmt_str += " with current target_RP %.1f and current pop %.1f, on turn %d" debug(fmt_str, dt_ech, res, resource_production, empire.population(), fo.currentTurn()) research_queue_list = get_research_queue_techs() # # check to accelerate distrib thought if True: # just to help with cold-folding / organization if not tech_is_complete("LRN_DISTRIB_THOUGHT"): got_telepathy = False for specName in get_empire_planets_by_species(): this_spec = fo.getSpecies(specName) if this_spec and ("TELEPATHIC" in list(this_spec.tags)): got_telepathy = True break pop_threshold = 100 if got_telepathy else 300 if empire.population() > pop_threshold: insert_idx = num_techs_accelerated for dt_ech in [ "LRN_PHYS_BRAIN", "LRN_TRANSLING_THT", "LRN_PSIONICS", "LRN_DISTRIB_THOUGHT" ]: if (dt_ech not in research_queue_list[:insert_idx + 2] and not tech_is_complete(dt_ech) and aistate.character.may_research_tech_classic( dt_ech)): res = fo.issueEnqueueTechOrder(dt_ech, insert_idx) num_techs_accelerated += 1 insert_idx += 1 fmt_str = "Empire has a telepathic race, so attempted to fast-track %s (got result %d)" fmt_str += " with current target_RP %.1f and current pop %.1f, on turn %d" debug(fmt_str, dt_ech, res, resource_production, empire.population(), fo.currentTurn()) research_queue_list = get_research_queue_techs() # # check to accelerate quant net if False: # disabled for now, otherwise just to help with cold-folding / organization if aistate.character.may_research_tech_classic("LRN_QUANT_NET") and ( population_with_research_focus() >= 40): if not tech_is_complete("LRN_QUANT_NET"): insert_idx = num_techs_accelerated # TODO determine min target slot if reenabling for qnTech in ["LRN_NDIM_SUBSPACE", "LRN_QUANT_NET"]: if qnTech not in research_queue_list[:insert_idx + 2] and not tech_is_complete( qnTech): res = fo.issueEnqueueTechOrder(qnTech, insert_idx) num_techs_accelerated += 1 insert_idx += 1 debug( "Empire has many researchers, so attempted to fast-track %s (got result %d) on turn %d", qnTech, res, fo.currentTurn(), ) research_queue_list = get_research_queue_techs() # # if we own a blackhole, accelerate sing_gen and conc camp if True: # just to help with cold-folding / organization if (fo.currentTurn() > 50 and len(AIstate.empireStars.get(fo.starType.blackHole, [])) != 0 and aistate.character.may_research_tech_classic("PRO_SINGULAR_GEN") and not tech_is_complete(Dep.PRO_SINGULAR_GEN) and tech_is_complete("LRN_EVERYTHING")): # sing_tech_list = [ "LRN_GRAVITONICS" , "PRO_SINGULAR_GEN"] # formerly also "CON_ARCH_PSYCH", "CON_CONC_CAMP", sing_gen_tech = fo.getTech(Dep.PRO_SINGULAR_GEN) sing_tech_list = [ pre_req for pre_req in sing_gen_tech.recursivePrerequisites(empire_id) if not tech_is_complete(pre_req) ] sing_tech_list += [Dep.PRO_SINGULAR_GEN] for singTech in sing_tech_list: if singTech not in research_queue_list[:num_techs_accelerated + 1]: res = fo.issueEnqueueTechOrder(singTech, num_techs_accelerated) num_techs_accelerated += 1 debug( "have a black hole star outpost/colony, so attempted to fast-track %s, got result %d", singTech, res, ) research_queue_list = get_research_queue_techs() # # if got deathray from Ruins, remove most prereqs from queue if True: # just to help with cold-folding / organization if tech_is_complete("SHP_WEAPON_4_1"): this_tech = fo.getTech("SHP_WEAPON_4_1") if this_tech: missing_prereqs = [ preReq for preReq in this_tech.recursivePrerequisites(empire_id) if preReq in research_queue_list ] if len(missing_prereqs ) > 2: # leave plasma 4 and 3 if up to them already for preReq in missing_prereqs: # sorted(missing_prereqs, reverse=True)[2:] if preReq in research_queue_list: fo.issueDequeueTechOrder(preReq) research_queue_list = get_research_queue_techs() if "SHP_WEAPON_4_2" in research_queue_list: # (should be) idx = research_queue_list.index("SHP_WEAPON_4_2") fo.issueEnqueueTechOrder("SHP_WEAPON_4_2", max(0, idx - 18)) # TODO: Remove the following example code # Example/Test code for the new ShipDesigner functionality techs = [ "SHP_WEAPON_4_2", "SHP_TRANSSPACE_DRIVE", "SHP_INTSTEL_LOG", "SHP_ASTEROID_HULLS", "" ] for tech in techs: this_tech = fo.getTech(tech) if not this_tech: debug("Invalid Tech specified") continue unlocked_items = this_tech.unlockedItems unlocked_hulls = [] unlocked_parts = [] for item in unlocked_items: if item.type == fo.unlockableItemType.shipPart: debug("Tech %s unlocks a ShipPart: %s", tech, item.name) unlocked_parts.append(item.name) elif item.type == fo.unlockableItemType.shipHull: debug("Tech %s unlocks a ShipHull: %s", tech, item.name) unlocked_hulls.append(item.name) if not (unlocked_parts or unlocked_hulls): debug("No new ship parts/hulls unlocked by tech %s", tech) continue old_designs = ShipDesignAI.WarShipDesigner().optimize_design( consider_fleet_count=False) new_designs = ShipDesignAI.WarShipDesigner().optimize_design( additional_hulls=unlocked_hulls, additional_parts=unlocked_parts, consider_fleet_count=False) if not (old_designs and new_designs): # AI is likely defeated; don't bother with logging error message continue old_rating, old_pid, old_design_id, old_cost, old_stats = old_designs[ 0] old_design = fo.getShipDesign(old_design_id) new_rating, new_pid, new_design_id, new_cost, new_stats = new_designs[ 0] new_design = fo.getShipDesign(new_design_id) if new_rating > old_rating: debug("Tech %s gives access to a better design!", tech) debug("old best design: Rating %.5f", old_rating) debug("old design specs: %s - %s", old_design.hull, list(old_design.parts)) debug("new best design: Rating %.5f", new_rating) debug("new design specs: %s - %s", new_design.hull, list(new_design.parts)) else: debug( "Tech %s gives access to new parts or hulls but there seems to be no military advantage.", tech)
def evaluateInvasionPlanet(planetID, missionType, fleetSupplyablePlanetIDs, empire, secureAIFleetMissions, verbose=True): "return the invasion value (score, troops) of a planet" detail = [] buildingValues = {"BLD_IMPERIAL_PALACE": 1000, "BLD_CULTURE_ARCHIVES": 1000, "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, } #TODO: add more factors, as used for colonization universe = fo.getUniverse() empireID = empire.empireID maxJumps=8 planet = universe.getPlanet(planetID) if (planet == None) : #TODO: exclude planets with stealth higher than empireDetection print "invasion AI couldn't access any info for planet id %d"%planetID return [0, 0] sysPartialVisTurn = dictFromMap(universe.getVisibilityTurnsMap(planet.systemID, empireID)).get(fo.visibility.partial, -9999) planetPartialVisTurn = dictFromMap(universe.getVisibilityTurnsMap(planetID, empireID)).get(fo.visibility.partial, -9999) if planetPartialVisTurn < sysPartialVisTurn: print "invasion AI couldn't get current info on planet id %d (was stealthed at last sighting)"%planetID return [0, 0] #last time we had partial vis of the system, the planet was stealthed to us #TODO: track detection strength, order new scouting when it goes up specName=planet.speciesName species=fo.getSpecies(specName) if not species: #this call iterates over this Empire's available species with which it could colonize after an invasion planetEval = ColonisationAI.assignColonisationValues([planetID], EnumsAI.AIFleetMissionType.FLEET_MISSION_COLONISATION, [planetID], None, empire, detail) #evaluatePlanet is imported from ColonisationAI popVal = max( 0.75*planetEval.get(planetID, [0])[0], ColonisationAI.evaluatePlanet(planetID, EnumsAI.AIFleetMissionType.FLEET_MISSION_OUTPOST, [planetID], None, empire, detail) ) else: popVal = ColonisationAI.evaluatePlanet(planetID, EnumsAI.AIFleetMissionType.FLEET_MISSION_COLONISATION, [planetID], specName, empire, detail) #evaluatePlanet is imported from ColonisationAI bldTally=0 for bldType in [universe.getObject(bldg).buildingTypeName for bldg in planet.buildingIDs]: bval = buildingValues.get(bldType, 50) bldTally += bval detail.append("%s: %d"%(bldType, bval)) pSysID = planet.systemID capitolID = PlanetUtilsAI.getCapital() leastJumpsPath = [] clear_path = True if capitolID: homeworld = universe.getPlanet(capitolID) if homeworld: homeSystemID = homeworld.systemID evalSystemID = planet.systemID if (homeSystemID != -1) and (evalSystemID != -1): leastJumpsPath = list(universe.leastJumpsPath(homeSystemID, evalSystemID, empireID)) maxJumps = len(leastJumpsPath) system_status = foAI.foAIstate.systemStatus.get(pSysID, {}) sysFThrt = system_status.get('fleetThreat', 1000 ) sysMThrt = foAI.foAIstate.systemStatus.get(pSysID, {}).get('monsterThreat', 0 ) sysPThrt = foAI.foAIstate.systemStatus.get(pSysID, {}).get('planetThreat', 0 ) sysTotThrt = sysFThrt + sysMThrt + sysPThrt max_path_threat = sysFThrt mil_ship_rating = ProductionAI.curBestMilShipRating() for path_sys_id in leastJumpsPath: 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 troops = planet.currentMeterValue(fo.meterType.troops) maxTroops = planet.currentMeterValue(fo.meterType.maxTroops) this_system = universe.getSystem(pSysID) secure_targets = [pSysID] + list(this_system.planetIDs) system_secured = False for mission in secureAIFleetMissions: if system_secured: break secure_fleet_id = mission.target_id s_fleet = universe.getFleet(secure_fleet_id) if (not s_fleet) or (s_fleet.systemID != pSysID): continue for ai_target in mission.getAITargets(EnumsAI.AIFleetMissionType.FLEET_MISSION_SECURE): target_obj = ai_target.target_obj if (target_obj is not None) and target_obj.id in secure_targets: system_secured = True break pmaxShield = planet.currentMeterValue(fo.meterType.maxShield) if verbose: print "invasion eval of %s %d --- maxShields %.1f -- sysFleetThreat %.1f -- sysMonsterThreat %.1f"%(planet.name, planetID, pmaxShield, sysFThrt, sysMThrt) supplyVal=0 enemyVal=0 if planet.owner!=-1 : #value in taking this away from an enemy enemyVal= 20* (planet.currentMeterValue(fo.meterType.targetIndustry) + 2*planet.currentMeterValue(fo.meterType.targetResearch)) if pSysID in ColonisationAI.annexableSystemIDs: #TODO: extend to rings supplyVal = 100 elif pSysID in ColonisationAI.annexableRing1: supplyVal = 200 elif pSysID in ColonisationAI.annexableRing2: supplyVal = 300 elif pSysID in ColonisationAI.annexableRing2: supplyVal = 400 if ( max_path_threat > 0.5 * mil_ship_rating ): if ( max_path_threat < 3 * mil_ship_rating ): supplyVal *= 0.5 else: supplyVal *= 0.2 threatFactor = min(1, 0.2*MilitaryAI.totMilRating/(sysTotThrt+0.001))**2 #devalue invasions that would require too much military force buildTime=4 if system_secured: plannedTroops = troops else: plannedTroops = min(troops+maxJumps+buildTime, maxTroops) if ( empire.getTechStatus("SHP_ORG_HULL") != fo.techStatus.complete ): troopCost = math.ceil( plannedTroops/6.0) * ( 40*( 1+foAI.foAIstate.shipCount * AIDependencies.shipUpkeep ) ) else: troopCost = math.ceil( plannedTroops/6.0) * ( 20*( 1+foAI.foAIstate.shipCount * AIDependencies.shipUpkeep ) ) planet_score = threatFactor*max(0, popVal+supplyVal+bldTally+enemyVal-0.8*troopCost) if clear_path: planet_score *= 1.5 invscore = [ planet_score, plannedTroops ] print invscore, "projected Troop Cost:", troopCost, ", threatFactor: ", threatFactor, ", planet detail ", detail, "popval, supplyval, bldval, enemyval", popVal, supplyVal, bldTally, enemyVal return invscore
def colony_detectable_by_empire(planet_id, species_name=None, empire=ALL_EMPIRES, future_stealth_bonus=0, default_result=True): """ Predicts if a planet/colony is/will-be detectable by an empire. The passed empire value can be a single empire ID or a list of empire IDs. If passed ALL_empires, will use the list of all empires. When using a list of empires (or when passed ALL_EMPIRES), the present empire is excluded. To check for the present empire the current empire ID must be passed as a simple int. Ignores current ownership of the planet unless the passed empire value is a simple int matching fo.empireID(), because in most cases we are concerned about (i) visibility to us of a planet we do not own, or (ii) visibility by enemies of a planet we own or expect to own at the time we are making the visibility projection for (even if they may own it right now). The only case where current ownership matters is when we are considering whether to abort a colonization mission, which might be for a planet we already own. :param planet_id: required, the planet of concern :type planet_id: int :param species_name: will override the existing planet species if provided :type species_name: str :param empire: empire ID (or list of empire IDs) whose detection ability is of concern :type empire: int | list[int] :param future_stealth_bonus: can specify a projected future stealth bonus, such as from a stealth tech :type future_stealth_bonus: int :param default_result: generally for offensive assessments should be False, for defensive should be True :type default_result: bool :return: whether the planet is predicted to be detectable :rtype: bool """ # The future_stealth_bonus can be used if the AI knows it has researched techs that would grant a stealth bonus to # the planet once it was colonized/captured planet = fo.getUniverse().getPlanet(planet_id) if not planet: error("Couldn't retrieve planet ID %d." % planet_id) return default_result if species_name is None: species_name = planet.speciesName # in case we are checking about aborting a colonization mission if empire == fo.empireID() and planet.ownedBy(empire): return True species = fo.getSpecies(species_name) if species: species_tags = species.tags elif species_name == "": species_tags = [] else: error("Couldn't retrieve species named '%s'." % species_name) return default_result # could just check stealth meter, but this approach might allow us to plan ahead a bit even if the planet # is temporarily stealth boosted by temporary effects like ion storm planet_stealth = max([AIDependencies.BASE_PLANET_STEALTH] + [AIDependencies.STEALTH_SPECIAL_STRENGTHS.get(_spec, 0) for _spec in planet.specials]) # TODO: check planet buildings for stealth bonuses # if the planet already has an existing stealth special, then the most common situation is that it would be # overlapping with or superseded by the future_stealth_bonus, not additive with it. planet_stealth = max(planet_stealth, AIDependencies.BASE_PLANET_STEALTH + future_stealth_bonus) total_stealth = planet_stealth + sum([AIDependencies.STEALTH_STRENGTHS_BY_SPECIES_TAG.get(tag, 0) for tag in species_tags]) if isinstance(empire, int): empire_detection = get_empire_detection(empire) else: empire_detection = get_max_empire_detection(empire) return total_stealth < empire_detection
def evaluateInvasionPlanet(planetID, missionType, fleetSupplyablePlanetIDs, empire): "return the invasion value of a planet" detail = [] buildingValues = {"BLD_IMPERIAL_PALACE": 1000, "BLD_CULTURE_ARCHIVES": 1000, "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": 150, "BLD_SHIPYARD_AST_REF": 500, "BLD_SHIPYARD_ENRG_COMP": 500, "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, } #TODO: add more factors, as used for colonization universe = fo.getUniverse() empireID = empire.empireID maxJumps=8 planet = universe.getPlanet(planetID) if (planet == None) : #TODO: exclude planets with stealth higher than empireDetection print "invasion AI couldn't get current info on planet %d"%planetID return 0, 0 specName=planet.speciesName species=fo.getSpecies(specName) if not species:#TODO: probably stealth makes planet inacccesible & should abort return 0, 0 else: popVal = ColonisationAI.evaluatePlanet(planetID, EnumsAI.AIFleetMissionType.FLEET_MISSION_COLONISATION, [planetID], species, empire, detail) #evaluatePlanet is imported from ColonisationAI bldTally=0 for bldType in [universe.getObject(bldg).buildingTypeName for bldg in planet.buildingIDs]: bval = buildingValues.get(bldType, 50) bldTally += bval detail.append("%s: %d"%(bldType, bval)) capitolID = PlanetUtilsAI.getCapital() if capitolID: homeworld = universe.getPlanet(capitolID) if homeworld: homeSystemID = homeworld.systemID evalSystemID = planet.systemID leastJumpsPath = len(universe.leastJumpsPath(homeSystemID, evalSystemID, empireID)) maxJumps = leastJumpsPath troops = planet.currentMeterValue(fo.meterType.troops) maxTroops = planet.currentMeterValue(fo.meterType.maxTroops) popTSize = planet.currentMeterValue(fo.meterType.targetPopulation)#TODO: adjust for empire tech planetSpecials = list(planet.specials) pSysID = planet.systemID#TODO: check star value pmaxShield = planet.currentMeterValue(fo.meterType.maxShield) sysFThrt = foAI.foAIstate.systemStatus.get(pSysID, {}).get('fleetThreat', 1000 ) sysMThrt = foAI.foAIstate.systemStatus.get(pSysID, {}).get('monsterThreat', 0 ) print "invasion eval of %s %d --- maxShields %.1f -- sysFleetThreat %.1f -- sysMonsterThreat %.1f"%(planet.name, planetID, pmaxShield, sysFThrt, sysMThrt) supplyVal=0 enemyVal=0 if planet.owner!=-1 : #value in taking this away from an enemy enemyVal= 20* (planet.currentMeterValue(fo.meterType.targetIndustry) + 2*planet.currentMeterValue(fo.meterType.targetResearch)) if planetID in fleetSupplyablePlanetIDs: #TODO: extend to rings supplyVal = 100 if planet.owner== -1: #if (pmaxShield <10): if ( sysFThrt < 0.5*ProductionAI.curBestMilShipRating() ): if ( sysMThrt < 3*ProductionAI.curBestMilShipRating()): supplyVal = 50 else: supplyVal = 20 else: supplyVal *= int( min(1, ProductionAI.curBestMilShipRating() / sysFThrt ) ) buildTime=4 plannedTroops = min(troops+maxJumps+buildTime, maxTroops) if ( empire.getTechStatus("SHP_ORG_HULL") != fo.techStatus.complete ): troopCost = math.ceil( plannedTroops/6.0) * ( 40*( 1+foAI.foAIstate.shipCount * AIDependencies.shipUpkeep ) ) else: troopCost = math.ceil( plannedTroops/6.0) * ( 20*( 1+foAI.foAIstate.shipCount * AIDependencies.shipUpkeep ) ) invscore = max(0, popVal+supplyVal+bldTally+enemyVal-0.8*troopCost), plannedTroops print invscore, "projected Troop Cost:", troopCost, "planet detail ", detail, popVal, supplyVal, bldTally, enemyVal return invscore
def evaluate_invasion_planet(planet_id, empire, secure_fleet_missions, verbose=True): """Return the invasion value (score, troops) of a planet.""" detail = [] building_values = {"BLD_IMPERIAL_PALACE": 1000, "BLD_CULTURE_ARCHIVES": 1000, "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, } # TODO: add more factors, as used for colonization universe = fo.getUniverse() empire_id = empire.empireID max_jumps = 8 planet = universe.getPlanet(planet_id) if planet is None: # TODO: exclude planets with stealth higher than empireDetection print "invasion AI couldn't access any info for planet id %d" % planet_id return [0, 0] sys_partial_vis_turn = universe.getVisibilityTurnsMap(planet.systemID, empire_id).get(fo.visibility.partial, -9999) planet_partial_vis_turn = universe.getVisibilityTurnsMap(planet_id, empire_id).get(fo.visibility.partial, -9999) if planet_partial_vis_turn < sys_partial_vis_turn: print "invasion AI couldn't get current info on planet id %d (was stealthed at last sighting)" % planet_id # TODO: track detection strength, order new scouting when it goes up return [0, 0] # last time we had partial vis of the system, the planet was stealthed to us species_name = planet.speciesName species = fo.getSpecies(species_name) if not species: # 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], EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION, None, empire, detail) pop_val = max(0.75*planet_eval.get(planet_id, [0])[0], ColonisationAI.evaluate_planet(planet_id, EnumsAI.AIFleetMissionType.FLEET_MISSION_OUTPOST, None, empire, detail)) else: pop_val = ColonisationAI.evaluate_planet(planet_id, EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION, species_name, empire, detail) bld_tally = 0 for bldType in [universe.getObject(bldg).buildingTypeName for bldg in planet.buildingIDs]: bval = building_values.get(bldType, 50) bld_tally += bval detail.append("%s: %d" % (bldType, bval)) p_sys_id = planet.systemID capitol_id = PlanetUtilsAI.get_capital() least_jumps_path = [] clear_path = True if capitol_id: homeworld = universe.getPlanet(capitol_id) if homeworld: home_system_id = homeworld.systemID eval_system_id = planet.systemID if (home_system_id != -1) and (eval_system_id != -1): least_jumps_path = list(universe.leastJumpsPath(home_system_id, eval_system_id, empire_id)) max_jumps = len(least_jumps_path) system_status = foAI.foAIstate.systemStatus.get(p_sys_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 troops = planet.currentMeterValue(fo.meterType.troops) max_troops = planet.currentMeterValue(fo.meterType.maxTroops) this_system = universe.getSystem(p_sys_id) secure_targets = [p_sys_id] + list(this_system.planetIDs) system_secured = False for mission in secure_fleet_missions: if system_secured: break secure_fleet_id = mission.target_id s_fleet = universe.getFleet(secure_fleet_id) if not s_fleet or s_fleet.systemID != p_sys_id: continue for ai_target in mission.get_targets(EnumsAI.AIFleetMissionType.FLEET_MISSION_SECURE): target_obj = ai_target.target_obj if (target_obj is not None) and target_obj.id in secure_targets: system_secured = True break if verbose: print "invasion eval of %s %d --- maxShields %.1f -- sysFleetThreat %.1f -- sysMonsterThreat %.1f" % ( planet.name, planet_id, planet.currentMeterValue(fo.meterType.maxShield), system_fleet_treat, system_monster_threat) supply_val = 0 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)) if p_sys_id in ColonisationAI.annexable_system_ids: # TODO: extend to rings supply_val = 100 elif p_sys_id in ColonisationAI.annexable_ring1: supply_val = 200 elif p_sys_id in ColonisationAI.annexable_ring2: supply_val = 300 elif p_sys_id in ColonisationAI.annexable_ring3: supply_val = 400 if max_path_threat > 0.5 * mil_ship_rating: if max_path_threat < 3 * mil_ship_rating: supply_val *= 0.5 else: supply_val *= 0.2 threat_factor = min(1, 0.2*MilitaryAI.totMilRating/(sys_total_threat+0.001))**2 # devalue invasions that would require too much military force build_time = 4 planned_troops = troops if system_secured else min(troops+max_jumps+build_time, max_troops) if not tech_is_complete("SHP_ORG_HULL"): troop_cost = math.ceil(planned_troops/6.0) * (40*(1+foAI.foAIstate.shipCount * AIDependencies.SHIP_UPKEEP)) else: troop_cost = math.ceil(planned_troops/6.0) * (20*(1+foAI.foAIstate.shipCount * AIDependencies.SHIP_UPKEEP)) planet_score = retaliation_risk_factor(planet.owner) * threat_factor * max(0, pop_val+supply_val+bld_tally+enemy_val-0.8*troop_cost) if clear_path: planet_score *= 1.5 invasion_score = [planet_score, planned_troops] print invasion_score, "projected Troop Cost:", troop_cost, ", threatFactor: ", threat_factor, ", planet detail ", detail, "popval, supplyval, bldval, enemyval", pop_val, supply_val, bld_tally, enemy_val return invasion_score
def getColonyFleets(): global empireSpecies, empireColonizers, empireSpeciesSystems, annexableSystemIDs, annexableRing1, annexableRing2, annexableRing3 global annexablePlanetIDs, curBestMilShipRating curBestMilShipRating = ProductionAI.curBestMilShipRating() "get colony fleets" allColonyFleetIDs = FleetUtilsAI.getEmpireFleetIDsByRole(AIFleetMissionType.FLEET_MISSION_COLONISATION) AIstate.colonyFleetIDs[:] = FleetUtilsAI.extractFleetIDsWithoutMissionTypes(allColonyFleetIDs) # get suppliable systems and planets universe = fo.getUniverse() empire = fo.getEmpire() empireID = empire.empireID capitalID = PlanetUtilsAI.getCapital() #capitalID = empire.capitalID homeworld=None if capitalID: homeworld = universe.getPlanet(capitalID) if homeworld: speciesName = homeworld.speciesName homeworldName=homeworld.name homeSystemID = homeworld.systemID else: speciesName = "" homeworldName=" no remaining homeworld " homeSystemID = -1 if not speciesName: speciesName = foAI.foAIstate.origSpeciesName species = fo.getSpecies(speciesName) if not species: print "**************************************************************************************" print "**************************************************************************************" print "Problem determining species for colonization planning: capitalID: %s, homeworld %s and species name %s"%(capitalID, homeworldName, speciesName) else: print "Plannning colonization for species name %s"%species.name fleetSupplyableSystemIDs = empire.fleetSupplyableSystemIDs fleetSupplyablePlanetIDs = PlanetUtilsAI.getPlanetsInSystemsIDs(fleetSupplyableSystemIDs) print "" print " fleetSupplyableSystemIDs: " + str(list(fleetSupplyableSystemIDs)) print " fleetSupplyablePlanetIDs: " + str(fleetSupplyablePlanetIDs) print "" print "-------\nEmpire Obstructed Starlanes:" print list(empire.obstructedStarlanes()) annexableSystemIDs.clear() annexableRing1.clear() annexableRing2.clear() annexableRing3.clear() annexablePlanetIDs.clear() for sysID in empire.fleetSupplyableSystemIDs: annexableSystemIDs.add(sysID) for nID in universe.getImmediateNeighbors(sysID, empireID): annexableSystemIDs.add(nID) annexableRing1.add(nID) annexableRing1.difference_update(empire.fleetSupplyableSystemIDs) print "First Ring of annexable systems: ", PlanetUtilsAI.sysNameIDs(annexableRing1) if empire.getTechStatus("CON_ORBITAL_CON") == fo.techStatus.complete: for sysID in list(annexableRing1): for nID in universe.getImmediateNeighbors(sysID, empireID): annexableRing2.add(nID) annexableRing2.difference_update(annexableSystemIDs) print "Second Ring of annexable systems: ", PlanetUtilsAI.sysNameIDs(annexableRing2) annexableSystemIDs.update(annexableRing2) if foAI.foAIstate.aggression > fo.aggression.cautious: for sysID in list(annexableRing2): for nID in universe.getImmediateNeighbors(sysID, empireID): annexableRing3.add(nID) annexableRing3.difference_update(annexableSystemIDs) print "Third Ring of annexable systems: ", PlanetUtilsAI.sysNameIDs(annexableRing3) annexableSystemIDs.update(annexableRing3) annexablePlanetIDs.update( PlanetUtilsAI.getPlanetsInSystemsIDs(annexableSystemIDs)) # get outpost and colonization planets exploredSystemIDs = foAI.foAIstate.getExplorableSystems(AIExplorableSystemType.EXPLORABLE_SYSTEM_EXPLORED) unExSysIDs = list(foAI.foAIstate.getExplorableSystems(AIExplorableSystemType.EXPLORABLE_SYSTEM_UNEXPLORED)) unExSystems = map(universe.getSystem, unExSysIDs) print "Unexplored Systems: %s " % [(sysID, (sys and sys.name) or "name unknown") for sysID, sys in zip( unExSysIDs, unExSystems)] print "Explored SystemIDs: " + str(list(exploredSystemIDs)) exploredPlanetIDs = PlanetUtilsAI.getPlanetsInSystemsIDs(exploredSystemIDs) print "Explored PlanetIDs: " + str(exploredPlanetIDs) print "" #visibleSystemIDs = foAI.foAIstate.visInteriorSystemIDs.keys() + foAI.foAIstate. visBorderSystemIDs.keys() #visiblePlanetIDs = PlanetUtilsAI.getPlanetsInSystemsIDs(visibleSystemIDs) #print "VisiblePlanets: %s "%[ (pid, (universe.getPlanet(pid) and universe.getPlanet(pid).name) or "unknown") for pid in visiblePlanetIDs] #print "" #accessibleSystemIDs = [sysID for sysID in visibleSystemIDs if universe.systemsConnected(sysID, homeSystemID, empireID) ] #acessiblePlanetIDs = PlanetUtilsAI.getPlanetsInSystemsIDs(accessibleSystemIDs) empireOwnedPlanetIDs = PlanetUtilsAI.getOwnedPlanetsByEmpire(universe.planetIDs, empireID) print "Empire Owned PlanetIDs: " + str(empireOwnedPlanetIDs) #allOwnedPlanetIDs = PlanetUtilsAI.getAllOwnedPlanetIDs(exploredPlanetIDs) #working with Explored systems not all 'visible' because might not have a path to the latter allOwnedPlanetIDs = PlanetUtilsAI.getAllOwnedPlanetIDs(annexablePlanetIDs) # print "All annexable Owned or Populated PlanetIDs: " + str(set(allOwnedPlanetIDs)-set(empireOwnedPlanetIDs)) #unOwnedPlanetIDs = list(set(exploredPlanetIDs) -set(allOwnedPlanetIDs)) unOwnedPlanetIDs = list(set(annexablePlanetIDs) -set(allOwnedPlanetIDs)) print "UnOwned annexable PlanetIDs: " + str(PlanetUtilsAI.planetNameIDs(unOwnedPlanetIDs)) empirePopCtrs = set( PlanetUtilsAI.getPopulatedPlanetIDs( empireOwnedPlanetIDs) ) empireOutpostIDs=set(empireOwnedPlanetIDs) - empirePopCtrs AIstate.popCtrIDs[:]=list(empirePopCtrs) AIstate.popCtrSystemIDs[:]=list(set(PlanetUtilsAI.getSystems(empirePopCtrs))) AIstate.outpostIDs[:]=list(empireOutpostIDs) AIstate.outpostSystemIDs[:]=list(set(PlanetUtilsAI.getSystems(empireOutpostIDs))) AIstate.colonizedSystems.clear() for pid in empireOwnedPlanetIDs: planet=universe.getPlanet(pid) if planet: AIstate.colonizedSystems.setdefault(planet.systemID, []).append(pid) # track these to plan Solar Generators and Singularity Generators AIstate.empireStars.clear() for sysID in AIstate.colonizedSystems: system = universe.getSystem(sysID) if system: AIstate.empireStars.setdefault(system.starType, []).append(sysID) oldPopCtrs=[] for specN in empireSpecies: oldPopCtrs.extend(empireSpecies[specN]) oldEmpSpec = empireSpecies empireSpecies.clear() oldEmpCol=empireColonizers empireColonizers.clear() if empire.getTechStatus(TechsListsAI.exobotTechName) == fo.techStatus.complete: empireColonizers["SP_EXOBOT"]=[]# get it into colonizer list even if no colony yet empireSpeciesSystems.clear() for pID in empirePopCtrs: planet=universe.getPlanet(pID) if not planet: print "Error empire has apparently lost sight of former colony at planet %d but doesn't realize it"%pID continue pSpecName=planet.speciesName if pID not in oldPopCtrs: if (AIFocusType.FOCUS_MINING in planet.availableFoci): fo.issueChangeFocusOrder(pID, AIFocusType.FOCUS_MINING) print "Changing focus of newly settled planet ID %d : %s to mining "%(pID, planet.name ) empireSpecies[pSpecName] = empireSpecies.get(pSpecName, [])+[pID] print "\n"+"Empire species roster:" for specName in empireSpecies: thisSpec=fo.getSpecies(specName) if thisSpec: shipyards=[] for pID in empireSpecies[specName]: planet=universe.getPlanet(pID) if thisSpec.canColonize: if "BLD_SHIPYARD_BASE" in [universe.getObject(bldg).buildingTypeName for bldg in planet.buildingIDs]: shipyards.append(pID) empireSpeciesSystems.setdefault(planet.systemID, {}).setdefault('pids', []).append(pID) if thisSpec.canColonize: empireColonizers[specName]=shipyards print "%s on planets %s; can%s colonize from %d shipyards; has tags %s"%(specName, empireSpecies[specName], ["not", ""][thisSpec.canColonize], len(shipyards), list(thisSpec.tags)) else: print "Unable to retrieve info for Species named %s"%specName print"" if empireSpecies!=oldEmpSpec: print "Old empire species: %s ; new empire species: %s"%(oldEmpSpec, empireSpecies) if empireColonizers!=oldEmpCol: print "Old empire colonizers: %s ; new empire colonizers: %s"%(oldEmpCol, empireColonizers) print # export colony targeted systems for other AI modules colonyTargetedPlanetIDs = getColonyTargetedPlanetIDs(universe.planetIDs, AIFleetMissionType.FLEET_MISSION_COLONISATION, empireID) allColonyTargetedSystemIDs = PlanetUtilsAI.getSystems(colonyTargetedPlanetIDs) AIstate.colonyTargetedSystemIDs = allColonyTargetedSystemIDs print "" print "Colony Targeted SystemIDs: " + str(AIstate.colonyTargetedSystemIDs) print "Colony Targeted PlanetIDs: " + str(colonyTargetedPlanetIDs) colonyFleetIDs = FleetUtilsAI.getEmpireFleetIDsByRole(AIFleetMissionType.FLEET_MISSION_COLONISATION) if not colonyFleetIDs: print "Available Colony Fleets: 0" else: print "Colony FleetIDs: " + str(FleetUtilsAI.getEmpireFleetIDsByRole(AIFleetMissionType.FLEET_MISSION_COLONISATION)) numColonyFleets = len(FleetUtilsAI.extractFleetIDsWithoutMissionTypes(colonyFleetIDs)) print "Colony Fleets Without Missions: " + str(numColonyFleets) outpostTargetedPlanetIDs = getOutpostTargetedPlanetIDs(universe.planetIDs, AIFleetMissionType.FLEET_MISSION_OUTPOST, empireID) allOutpostTargetedSystemIDs = PlanetUtilsAI.getSystems(outpostTargetedPlanetIDs) # export outpost targeted systems for other AI modules AIstate.outpostTargetedSystemIDs = allOutpostTargetedSystemIDs print "" print "Outpost Targeted SystemIDs: " + str(AIstate.outpostTargetedSystemIDs) print "Outpost Targeted PlanetIDs: " + str(outpostTargetedPlanetIDs) outpostFleetIDs = FleetUtilsAI.getEmpireFleetIDsByRole(AIFleetMissionType.FLEET_MISSION_OUTPOST) if not outpostFleetIDs: print "Available Outpost Fleets: 0" else: print "Outpost FleetIDs: " + str(FleetUtilsAI.getEmpireFleetIDsByRole(AIFleetMissionType.FLEET_MISSION_OUTPOST)) numOutpostFleets = len(FleetUtilsAI.extractFleetIDsWithoutMissionTypes(outpostFleetIDs)) print "Outpost Fleets Without Missions: " + str(numOutpostFleets) evaluatedColonyPlanetIDs = list(set(unOwnedPlanetIDs).union(empireOutpostIDs) - set(colonyTargetedPlanetIDs) ) # print "Evaluated Colony PlanetIDs: " + str(evaluatedColonyPlanetIDs) evaluatedOutpostPlanetIDs = list(set(unOwnedPlanetIDs) - set(outpostTargetedPlanetIDs)- set(colonyTargetedPlanetIDs)) # print "Evaluated Outpost PlanetIDs: " + str(evaluatedOutpostPlanetIDs) evaluatedColonyPlanets = assignColonisationValues(evaluatedColonyPlanetIDs, AIFleetMissionType.FLEET_MISSION_COLONISATION, fleetSupplyablePlanetIDs, species, empire) removeLowValuePlanets(evaluatedColonyPlanets) sortedPlanets = evaluatedColonyPlanets.items() sortedPlanets.sort(lambda x, y: cmp(x[1], y[1]), reverse=True) print "" print "Settleable Colony Planets (score,species) | ID | Name | Specials:" for ID, score in sortedPlanets: print " %15s | %5s | %s | %s "%(score, ID, universe.getPlanet(ID).name , list(universe.getPlanet(ID).specials)) print "" # export planets for other AI modules foAI.foAIstate.colonisablePlanetIDs = sortedPlanets#TODO: should include species designation corresponding to rating # get outpost fleets allOutpostFleetIDs = FleetUtilsAI.getEmpireFleetIDsByRole(AIFleetMissionType.FLEET_MISSION_OUTPOST) AIstate.outpostFleetIDs = FleetUtilsAI.extractFleetIDsWithoutMissionTypes(allOutpostFleetIDs) evaluatedOutpostPlanets = assignColonisationValues(evaluatedOutpostPlanetIDs, AIFleetMissionType.FLEET_MISSION_OUTPOST, fleetSupplyablePlanetIDs, species, empire) removeLowValuePlanets(evaluatedOutpostPlanets) #bad! lol, was preventing all mining outposts sortedOutposts = evaluatedOutpostPlanets.items() sortedOutposts.sort(lambda x, y: cmp(x[1], y[1]), reverse=True) print "Settleable Outpost PlanetIDs:" for ID, score in sortedOutposts: print " %5s | %5s | %s | %s "%(score, ID, universe.getPlanet(ID).name , list(universe.getPlanet(ID).specials)) print "" # export outposts for other AI modules foAI.foAIstate.colonisableOutpostIDs = sortedOutposts
def evaluate_invasion_planet(planet_id): """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: debug("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=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 visibility 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) empire_research_list = tuple(element.tech for element in fo.getEmpire().researchQueue) 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], calculate_planet_colonization_rating. calculate_planet_colonization_rating( planet_id=planet_id, mission_type=MissionType.OUTPOST, spec_name=None, detail=detail, empire_research_list=empire_research_list, ), ) else: colony_base_value = calculate_planet_colonization_rating.calculate_planet_colonization_rating( planet_id=planet_id, mission_type=MissionType.INVASION, spec_name=species_name, detail=detail, empire_research_list=empire_research_list, ) # 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)) least_jumps_path, max_jumps = _get_path_from_capital(planet) clear_path = True aistate = get_aistate() system_status = aistate.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 = aistate.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 secure_fleets = get_aistate().get_fleet_missions_with_any_mission_types( [MissionType.SECURE, MissionType.MILITARY]) for mission in secure_fleets: 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 in [MissionType.SECURE, MissionType.MILITARY]: 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) debug( "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 = 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 += 0.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, get_species_tag_grade(species_here, Tags.ATTACKTROOPS)) planned_troops = troops if system_secured else min( troops + troop_regen * (max_jumps + build_time), max_troops) planned_troops += 0.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.0, 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 military 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 debug( " - 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, ) debug(" - system secured: %s" % system_secured) return [planet_score, planned_troops]
def colony_detectable_by_empire(planet_id, species_name=None, empire=ALL_EMPIRES, future_stealth_bonus=0, default_result=True): """ Predicts if a planet/colony is/will-be detectable by an empire. The passed empire value can be a single empire ID or a list of empire IDs. If passed ALL_empires, will use the list of all empires. When using a list of empires (or when passed ALL_EMPIRES), the present empire is excluded. To check for the present empire the current empire ID must be passed as a simple int. Ignores current ownership of the planet unless the passed empire value is a simple int matching fo.empireID(), because in most cases we are concerned about (i) visibility to us of a planet we do not own, or (ii) visibility by enemies of a planet we own or expect to own at the time we are making the visibility projection for (even if they may own it right now). The only case where current ownership matters is when we are considering whether to abort a colonization mission, which might be for a planet we already own. :param planet_id: required, the planet of concern :type planet_id: int :param species_name: will override the existing planet species if provided :type species_name: str :param empire: empire ID (or list of empire IDs) whose detection ability is of concern :type empire: int | list[int] :param future_stealth_bonus: can specify a projected future stealth bonus, such as from a stealth tech :type future_stealth_bonus: int :param default_result: generally for offensive assessments should be False, for defensive should be True :type default_result: bool :return: whether the planet is predicted to be detectable :rtype: bool """ # The future_stealth_bonus can be used if the AI knows it has researched techs that would grant a stealth bonus to # the planet once it was colonized/captured planet = fo.getUniverse().getPlanet(planet_id) if not planet: error("Couldn't retrieve planet ID %d." % planet_id) return default_result if species_name is None: species_name = planet.speciesName # in case we are checking about aborting a colonization mission if empire == fo.empireID() and planet.ownedBy(empire): return True species = fo.getSpecies(species_name) if species: species_tags = species.tags elif species_name == "": species_tags = [] else: error("Couldn't retrieve species named '%s'." % species_name) return default_result # could just check stealth meter, but this approach might allow us to plan ahead a bit even if the planet # is temporarily stealth boosted by temporary effects like ion storm planet_stealth = AIDependencies.BASE_PLANET_STEALTH if planet.specials: planet_stealth += max([ AIDependencies.STEALTH_SPECIAL_STRENGTHS.get(_spec, 0) for _spec in planet.specials ]) # TODO: check planet buildings for stealth bonuses # if the planet already has an existing stealth special, then the most common situation is that it would be # overlapping with or superseded by the future_stealth_bonus, not additive with it. planet_stealth = max( planet_stealth, AIDependencies.BASE_PLANET_STEALTH + future_stealth_bonus) total_stealth = planet_stealth + sum([ AIDependencies.STEALTH_STRENGTHS_BY_SPECIES_TAG.get(tag, 0) for tag in species_tags ]) if isinstance(empire, int): empire_detection = get_empire_detection(empire) else: empire_detection = get_max_empire_detection(empire) return total_stealth < empire_detection
def generateResearchOrders(): "generate research orders" universe=fo.getUniverse() empire = fo.getEmpire() empireID = empire.empireID print "Research Queue Management:" tRP = empire.resourceProduction(fo.resourceType.research) print "\nTotal Current Research Points: %.2f\n"%tRP print "Techs researched and available for use:" completedTechs = sorted(list(getCompletedTechs())) tlist = completedTechs+3*[" "] tlines = zip( tlist[0::3], tlist[1::3], tlist[2::3]) for tline in tlines: print "%25s %25s %25s"%tline print"" # # report techs currently at head of research queue # researchQueue = empire.researchQueue researchQueueList = getResearchQueueTechs() inProgressTechs.clear() if researchQueueList: print "Techs currently at head of Research Queue:" for element in list(researchQueue)[:10]: if element.allocation > 0.0: inProgressTechs[element.tech]=True thisTech=fo.getTech(element.tech) if not thisTech: print "Error: can't retrieve tech ", element.tech continue missingPrereqs = [preReq for preReq in thisTech.recursivePrerequisites(empireID) if preReq not in completedTechs] #unlockedItems = [(uli.name, uli.type) for uli in thisTech.unlockedItems] unlockedItems = [uli.name for uli in thisTech.unlockedItems] if not missingPrereqs: print " %25s allocated %6.2f RP -- unlockable items: %s "%(element.tech, element.allocation, unlockedItems) else: print " %25s allocated %6.2f RP -- missing preReqs: %s -- unlockable items: %s "%(element.tech, element.allocation, missingPrereqs, unlockedItems) print "" # # set starting techs, or after turn 100 add any additional default techs # if (fo.currentTurn()==1) or ((fo.currentTurn()<5) and (len(researchQueueList)==0) ): research_index = get_research_index() newtech = TechsListsAI.primary_meta_techs(index = research_index) print "Empire %s (%d) is selecting research index %d"%(empire.name, empireID, research_index) #pLTsToEnqueue = (set(newtech)-(set(completedTechs)|set(researchQueueList))) pLTsToEnqueue = newtech[:] techBase = set(completedTechs+researchQueueList) techsToAdd=[] for tech in pLTsToEnqueue: if (tech not in techBase): thisTech=fo.getTech(tech) if thisTech is None: print "Error: desired tech '%s' appears to not exist"%tech continue missingPrereqs = [preReq for preReq in thisTech.recursivePrerequisites(empireID) if preReq not in techBase] techsToAdd.extend( missingPrereqs+[tech] ) techBase.update( missingPrereqs+[tech] ) cumCost=0 print " Enqueued Tech: %20s \t\t %8s \t %s"%("Name", "Cost", "CumulativeCost") for name in techsToAdd: try: enqueueRes = fo.issueEnqueueTechOrder(name, -1) if enqueueRes == 1: thisTech=fo.getTech(name) thisCost=0 if thisTech: thisCost = thisTech.researchCost(empireID) cumCost += thisCost print " Enqueued Tech: %20s \t\t %8.0f \t %8.0f" % ( name, thisCost, cumCost) else: print " Error: failed attempt to enqueued Tech: " + name except: print " Error: failed attempt to enqueued Tech: " + name print " Error: exception triggered and caught: ", traceback.format_exc() if foAI.foAIstate.aggression <= fo.aggression.cautious: researchQueueList = getResearchQueueTechs() defTechs = TechsListsAI.defense_techs_1() for defTech in defTechs: if defTech not in researchQueueList[:5] and empire.getTechStatus(defTech) != fo.techStatus.complete: res=fo.issueEnqueueTechOrder(defTech, min(3, len(researchQueueList))) print "Empire is very defensive, so attempted to fast-track %s, got result %d"%(defTech, res) if False and foAI.foAIstate.aggression >= fo.aggression.aggressive: #with current stats of Conc Camps, disabling this fast-track researchQueueList = getResearchQueueTechs() if "CON_CONC_CAMP" in researchQueueList: insertIdx = min(40, researchQueueList.index("CON_CONC_CAMP")) else: insertIdx=max(0, min(40, len(researchQueueList)-10)) if "SHP_DEFLECTOR_SHIELD" in researchQueueList: insertIdx = min(insertIdx, researchQueueList.index("SHP_DEFLECTOR_SHIELD")) for ccTech in [ "CON_ARCH_PSYCH", "CON_CONC_CAMP"]: if ccTech not in researchQueueList[:insertIdx+1] and empire.getTechStatus(ccTech) != fo.techStatus.complete: res=fo.issueEnqueueTechOrder(ccTech, insertIdx) print "Empire is very aggressive, so attempted to fast-track %s, got result %d"%(ccTech, res) print"" generateDefaultResearchOrders() print "\n\nAll techs:" alltechs = fo.techs() # returns names of all techs for tname in alltechs: print tname print "\n-------------------------------\nAll unqueued techs:" #coveredTechs = newtech+completedTechs for tname in [tn for tn in alltechs if tn not in techBase]: print tname elif fo.currentTurn() >100: generateDefaultResearchOrders() researchQueueList = getResearchQueueTechs() num_techs_accelerated = 1 # will ensure leading tech doesn't get dislodged gotGGG = empire.getTechStatus("PRO_ORBITAL_GEN") == fo.techStatus.complete gotSymBio = empire.getTechStatus("GRO_SYMBIOTIC_BIO") == fo.techStatus.complete gotXenoGen = empire.getTechStatus("GRO_XENO_GENETICS") == fo.techStatus.complete # # Consider accelerating techs; priority is # Supply/Detect range # xeno arch # ast / GG # gro xeno gen # distrib thought # quant net # pro sing gen # death ray 1 cleanup # # Supply range and detection range if True: #just to help with cold-folding / organization if len(foAI.foAIstate.colonisablePlanetIDs)==0: bestColonySiteScore = 0 else: bestColonySiteScore= foAI.foAIstate.colonisablePlanetIDs[0][1] if len(foAI.foAIstate.colonisableOutpostIDs)==0: bestOutpostSiteScore = 0 else: bestOutpostSiteScore= foAI.foAIstate.colonisableOutpostIDs[0][1] needImprovedScouting = ( bestColonySiteScore <150 or bestOutpostSiteScore < 200 ) if needImprovedScouting: if (empire.getTechStatus("CON_ORBITAL_CON") != fo.techStatus.complete): if ( "CON_ORBITAL_CON" not in researchQueueList[:1 + num_techs_accelerated] ) and ( (empire.getTechStatus("PRO_FUSION_GEN") == fo.techStatus.complete) or ( "PRO_FUSION_GEN" in researchQueueList[:1+num_techs_accelerated] )): res=fo.issueEnqueueTechOrder("CON_ORBITAL_CON", num_techs_accelerated) num_techs_accelerated += 1 print "Empire has poor colony/outpost prospects, so attempted to fast-track %s, got result %d"%("CON_ORBITAL_CON", res) elif (empire.getTechStatus("CON_CONTGRAV_ARCH") != fo.techStatus.complete): if ( "CON_CONTGRAV_ARCH" not in researchQueueList[:1+num_techs_accelerated] ) and ((empire.getTechStatus("CON_METRO_INFRA") == fo.techStatus.complete)): for supply_tech in [_s_tech for _s_tech in ["CON_ARCH_MONOFILS", "CON_CONTGRAV_ARCH"] if (empire.getTechStatus(_s_tech) != fo.techStatus.complete)]: res=fo.issueEnqueueTechOrder(supply_tech, num_techs_accelerated) num_techs_accelerated += 1 print "Empire has poor colony/outpost prospects, so attempted to fast-track %s, got result %d"%(supply_tech, res) elif (empire.getTechStatus("CON_GAL_INFRA") != fo.techStatus.complete): if ( "CON_GAL_INFRA" not in researchQueueList[:1+num_techs_accelerated] ) and ((empire.getTechStatus("PRO_SINGULAR_GEN") == fo.techStatus.complete)): res=fo.issueEnqueueTechOrder("CON_GAL_INFRA", num_techs_accelerated) num_techs_accelerated += 1 print "Empire has poor colony/outpost prospects, so attempted to fast-track %s, got result %d"%("CON_GAL_INFRA", res) else: pass researchQueueList = getResearchQueueTechs() #could add more supply tech if False and (empire.getTechStatus("SPY_DETECT_2") != fo.techStatus.complete): #disabled for now, detect2 if ( "SPY_DETECT_2" not in researchQueueList[:2+num_techs_accelerated] ) and (empire.getTechStatus("PRO_FUSION_GEN") == fo.techStatus.complete) : if ( "CON_ORBITAL_CON" not in researchQueueList[:1+num_techs_accelerated] ): res=fo.issueEnqueueTechOrder("SPY_DETECT_2", num_techs_accelerated) else: CO_idx = researchQueueList.index( "CON_ORBITAL_CON") res=fo.issueEnqueueTechOrder("SPY_DETECT_2", CO_idx+1) num_techs_accelerated += 1 print "Empire has poor colony/outpost prospects, so attempted to fast-track %s, got result %d"%("CON_ORBITAL_CON", res) researchQueueList = getResearchQueueTechs() # # check to accelerate xeno_arch if True: #just to help with cold-folding / organization if ColonisationAI.gotRuins and empire.getTechStatus("LRN_XENOARCH") != fo.techStatus.complete: if "LRN_ARTIF_MINDS" in researchQueueList: insert_idx = 7+ researchQueueList.index("LRN_ARTIF_MINDS") elif "GRO_SYMBIOTIC_BIO" in researchQueueList: insert_idx = researchQueueList.index("GRO_SYMBIOTIC_BIO") + 1 else: insert_idx = num_techs_accelerated if "LRN_XENOARCH" not in researchQueueList[:insert_idx]: for xenoTech in [ "LRN_XENOARCH", "LRN_TRANSLING_THT", "LRN_PHYS_BRAIN" , "LRN_ALGO_ELEGANCE"]: if (empire.getTechStatus(xenoTech) != fo.techStatus.complete) and ( xenoTech not in researchQueueList[:(insert_idx+4)]) : res=fo.issueEnqueueTechOrder(xenoTech,insert_idx) num_techs_accelerated += 1 print "ANCIENT_RUINS: have an ancient ruins, so attempted to fast-track %s to enable LRN_XENOARCH, got result %d"%(xenoTech, res) researchQueueList = getResearchQueueTechs() # # check to accelerate asteroid or GG tech if True: #just to help with cold-folding / organization if ColonisationAI.gotAst and empire.getTechStatus("SHP_ASTEROID_HULLS") != fo.techStatus.complete and ( ("SHP_ASTEROID_HULLS" not in researchQueueList[num_techs_accelerated])): #if needed but not top item, will block acceleration of pro_orb_gen if ("SHP_ASTEROID_HULLS" not in researchQueueList[:2+num_techs_accelerated]): if "GRO_SYMBIOTIC_BIO" in researchQueueList: insert_idx = 1+ researchQueueList.index("GRO_SYMBIOTIC_BIO") else: insert_idx = num_techs_accelerated for ast_tech in ["SHP_ASTEROID_HULLS", "PRO_MICROGRAV_MAN"]: if (empire.getTechStatus(ast_tech) != fo.techStatus.complete) and ( ast_tech not in researchQueueList[:insert_idx+2]) : res=fo.issueEnqueueTechOrder(ast_tech,insert_idx) num_techs_accelerated += 1 print "Asteroids: have colonized an asteroid belt, so attempted to fast-track %s , got result %d"%(ast_tech, res) researchQueueList = getResearchQueueTechs() elif ColonisationAI.gotGG and empire.getTechStatus("PRO_ORBITAL_GEN") != fo.techStatus.complete and ( "PRO_ORBITAL_GEN" not in researchQueueList[:3+num_techs_accelerated]): if "GRO_SYMBIOTIC_BIO" in researchQueueList: insert_idx = 1+ researchQueueList.index("GRO_SYMBIOTIC_BIO") else: insert_idx = num_techs_accelerated res=fo.issueEnqueueTechOrder("PRO_ORBITAL_GEN",insert_idx) num_techs_accelerated += 1 print "GasGiant: have colonized a gas giant, so attempted to fast-track %s, got result %d"%("PRO_ORBITAL_GEN", res) researchQueueList = getResearchQueueTechs() # # assess if our empire has any non-lousy colonizers, & boost gro_xeno_gen if we don't if True: #just to help with cold-folding / organization if gotGGG and gotSymBio and (not gotXenoGen) and foAI.foAIstate.aggression >= fo.aggression.cautious: mostAdequate=0 for specName in ColonisationAI.empireColonizers: environs={} thisSpec = fo.getSpecies(specName) if not thisSpec: continue for ptype in [fo.planetType.swamp, fo.planetType.radiated, fo.planetType.toxic, fo.planetType.inferno, fo.planetType.barren, fo.planetType.tundra, fo.planetType.desert, fo.planetType.terran, fo.planetType.ocean, fo.planetType.asteroids]: environ=thisSpec.getPlanetEnvironment(ptype) environs.setdefault(environ, []).append(ptype) mostAdequate = max(mostAdequate, len(environs.get( fo.planetEnvironment.adequate, []))) if mostAdequate==0: insert_idx = num_techs_accelerated for xgTech in [ "GRO_XENO_GENETICS", "GRO_GENETIC_ENG" ]: if xgTech not in researchQueueList[:1+num_techs_accelerated] and empire.getTechStatus(xgTech) != fo.techStatus.complete: res=fo.issueEnqueueTechOrder(xgTech, insert_idx) num_techs_accelerated += 1 print "Empire has poor colonizers, so attempted to fast-track %s, got result %d"%(xgTech, res) researchQueueList = getResearchQueueTechs() # # check to accelerate distrib thought if True: #just to help with cold-folding / organization if (empire.getTechStatus("LRN_DISTRIB_THOUGHT") != fo.techStatus.complete): got_telepathy = False for specName in ColonisationAI.empireSpecies: thisSpec=fo.getSpecies(specName) if thisSpec and ("TELEPATHIC" in list(thisSpec.tags)): got_telepathy = True break if ((foAI.foAIstate.aggression > fo.aggression.cautious) and (empire.population() > ([300, 100][got_telepathy]))): insert_idx = num_techs_accelerated for dt_ech in [ "LRN_DISTRIB_THOUGHT", "LRN_PSIONICS", "LRN_TRANSLING_THT", "LRN_PHYS_BRAIN" ]: if dt_ech not in researchQueueList[:4+num_techs_accelerated] and empire.getTechStatus(dt_ech) != fo.techStatus.complete: res=fo.issueEnqueueTechOrder(dt_ech, insert_idx) num_techs_accelerated += 1 fmt_str = "Empire has a telepathic race, so attempted to fast-track %s (got result %d)" fmt_str += " with current target_RP %.1f and current pop %.1f, on turn %d" print fmt_str%( dt_ech, res, tRP, empire.population(), fo.currentTurn()) researchQueueList = getResearchQueueTechs() # # check to accelerate quant net if True: #just to help with cold-folding / organization if (foAI.foAIstate.aggression > fo.aggression.cautious) and( ColonisationAI.empire_status.get('researchers', 0) >= 40 ): if (empire.getTechStatus("LRN_QUANT_NET") != fo.techStatus.complete): insert_idx = num_techs_accelerated for qnTech in [ "LRN_NDIM_SUBSPACE", "LRN_QUANT_NET" ]: if qnTech not in researchQueueList[:2+num_techs_accelerated] and empire.getTechStatus(qnTech) != fo.techStatus.complete: res=fo.issueEnqueueTechOrder(qnTech, insert_idx) num_techs_accelerated += 1 print "Empire has many researchers, so attempted to fast-track %s (got result %d) on turn %d"%(qnTech, res, fo.currentTurn()) researchQueueList = getResearchQueueTechs() # # if we own a blackhole, accelerate sing_gen and conc camp if True: #just to help with cold-folding / organization if ( fo.currentTurn() >50 and len (AIstate.empireStars.get(fo.starType.blackHole, []))!=0 and foAI.foAIstate.aggression > fo.aggression.cautious and (empire.getTechStatus(AIDependencies.sing_tech_name) != fo.techStatus.complete) ): #sing_tech_list = [ "LRN_GRAVITONICS" , "PRO_SINGULAR_GEN"] # formerly also "CON_ARCH_PSYCH", "CON_CONC_CAMP", sing_gen_tech = fo.getTech(AIDependencies.sing_tech_name) sing_tech_list = [pre_req for pre_req in sing_gen_tech.recursivePrerequisites(empireID) if (empire.getTechStatus(pre_req) != fo.techStatus.complete) ] sing_tech_list += [ AIDependencies.sing_tech_name ] for singTech in sing_tech_list: if ( singTech not in researchQueueList[:num_techs_accelerated+1 ]) : res=fo.issueEnqueueTechOrder(singTech,num_techs_accelerated) num_techs_accelerated += 1 print "have a black hole star outpost/colony, so attempted to fast-track %s, got result %d"%(singTech, res) researchQueueList = getResearchQueueTechs() # # if got deathray from Ruins, remove most prereqs from queue if True: #just to help with cold-folding / organization if empire.getTechStatus("SHP_WEAPON_4_1" ) == fo.techStatus.complete: thisTech=fo.getTech("SHP_WEAPON_4_1") if thisTech: missingPrereqs = [preReq for preReq in thisTech.recursivePrerequisites(empireID) if preReq in researchQueueList] if len(missingPrereqs) > 2 : #leave plasma 4 and 3 if up to them already for preReq in missingPrereqs: #sorted(missingPrereqs, reverse=True)[2:] if preReq in researchQueueList: res = fo.issueDequeueTechOrder(preReq) if "SHP_WEAPON_4_2" in researchQueueList: #(should be) idx = researchQueueList.index("SHP_WEAPON_4_2") res=fo.issueEnqueueTechOrder("SHP_WEAPON_4_2", max(0, idx-15) ) researchQueueList = getResearchQueueTechs()
def colony_detectable_by_empire(planet_id, species_name=None, empire_id=ALL_EMPIRES, future_stealth_bonus=0, default_result=True): """ Predicts if a planet/colony is/will-be detectable by an empire :param planet_id: required, the planet of concern :type planet_id: int :param species_name: will override the existing planet species if provided :type species_name: str :param empire_id: empire whose detection ability is of concern :type empire_id: int :param future_stealth_bonus: can specify a projected future stealth bonus, such as from a stealth tech :type future_stealth_bonus: int :param default_result: generally for offensive assessments should be False, for defensive should be True :type default_result: bool :return: whether the planet is predicted to be detectable :rtype: bool """ # The future_stealth_bonus can be used if the AI knows it has researched techs that would grant a stealth bonus to # the planet once it was colonized/captured empire_detection = get_empire_detection(empire_id) planet = fo.getUniverse().getPlanet(planet_id) if not planet: error("Couldn't retrieve planet ID %d." % planet_id) return default_result if species_name is None: species_name = planet.speciesName # in case we are checking about aborting a colonization mission if empire_id == fo.empireID() and planet.ownedBy(empire_id): return True species = fo.getSpecies(species_name) if species: species_tags = species.tags elif species_name == "": species_tags = [] else: error("Couldn't retrieve species named '%s'." % species_name) return default_result # could just check stealth meter, but this approach might allow us to plan ahead a bit even if the planet # is temporarily stealth boosted by temporary effects like ion storm planet_stealth = max([AIDependencies.BASE_PLANET_STEALTH] + [ AIDependencies.STEALTH_SPECIAL_STRENGTHS.get(_spec, 0) for _spec in planet.specials ]) # TODO: check planet buildings for stealth bonuses # if the planet already has an existing stealth special, then the most common situation is that it would be # overlapping with or superseded by the future_stealth_bonus, not additive with it. planet_stealth = max( planet_stealth, AIDependencies.BASE_PLANET_STEALTH + future_stealth_bonus) total_stealth = planet_stealth + sum([ AIDependencies.STEALTH_STRENGTHS_BY_SPECIES_TAG.get(tag, 0) for tag in species_tags ]) return total_stealth < empire_detection
def generateResearchOrders(): global inProgressTechs "generate research orders" universe=fo.getUniverse() empire = fo.getEmpire() empireID = empire.empireID print "Research Queue Management:" tRP = empire.resourceProduction(fo.resourceType.research) print "\nTotal Current Research Points: %.2f\n"%tRP print "Techs researched and available for use:" completedTechs = sorted(list(getCompletedTechs())) tlist = completedTechs+3*[" "] tlines = zip( tlist[0::3], tlist[1::3], tlist[2::3]) for tline in tlines: print "%25s %25s %25s"%tline print"" if tRP >= 20 and foAI.foAIstate.aggression > 1: researchQueueList = getResearchQueueTechs() if (empire.getTechStatus("LRN_PSIONICS") != fo.techStatus.complete) and ( "LRN_PSIONICS" not in researchQueueList[:5] ) : for specName in ColonisationAI.empireSpecies: thisSpec=fo.getSpecies(specName) if thisSpec: if "TELEPATHIC" in list(thisSpec.tags): res=fo.issueEnqueueTechOrder("LRN_DISTRIB_THOUGHT", 0) res=fo.issueEnqueueTechOrder("LRN_PSIONICS", 0) break gotSymBio = empire.getTechStatus("GRO_SYMBIOTIC_BIO") == fo.techStatus.complete gotXenoGen = empire.getTechStatus("GRO_XENO_GENETICS") == fo.techStatus.complete #assess if our empire has any non-lousy colonizers, & boost gro_xeno_gen if we don't if gotSymBio and (not gotXenoGen) and foAI.foAIstate.aggression!=0: mostAdequate=0 for specName in ColonisationAI.empireColonizers: environs={} thisSpec = fo.getSpecies(specName) if not thisSpec: continue for ptype in [fo.planetType.swamp, fo.planetType.radiated, fo.planetType.toxic, fo.planetType.inferno, fo.planetType.barren, fo.planetType.tundra, fo.planetType.desert, fo.planetType.terran, fo.planetType.ocean, fo.planetType.asteroids]: environ=thisSpec.getPlanetEnvironment(ptype) environs.setdefault(environ, []).append(ptype) mostAdequate = max(mostAdequate, len(environs.get( fo.planetEnvironment.adequate, []))) if mostAdequate==0: researchQueue = empire.researchQueue researchQueueList = getResearchQueueTechs() if "GRO_XENO_GENETICS" not in researchQueueList[:2]: res=fo.issueEnqueueTechOrder("GRO_XENO_GENETICS", 0) print "Empire has poor colonizers, so attempted to fast-track GRO_XENO_GENETICS, got result %d"%res researchQueue = empire.researchQueue researchQueueList = getResearchQueueTechs() inProgressTechs.clear() if researchQueueList: print "Techs currently at head of Research Queue:" for element in list(researchQueue)[:10]: if element.allocation > 0.0: inProgressTechs[element.tech]=True thisTech=fo.getTech(element.tech) missingPrereqs = [preReq for preReq in thisTech.recursivePrerequisites(empireID) if preReq not in completedTechs] unlockedItems = [(uli.name, uli.type) for uli in thisTech.unlockedItems] if not missingPrereqs: print " %25s allocated %6.2f RP -- unlockable items: %s "%(element.tech, element.allocation, unlockedItems) else: print " %25s allocated %6.2f RP -- missing preReqs: %s -- unlockable items: %s "%(element.tech, element.allocation, missingPrereqs, unlockedItems) print "" if fo.currentTurn()==1: newtech = TechsListsAI.primaryMetaTechsList() #pLTsToEnqueue = (set(newtech)-(set(completedTechs)|set(researchQueueList))) pLTsToEnqueue = newtech[:] techBase = set(completedTechs+researchQueueList) techsToAdd=[] for tech in pLTsToEnqueue: if (tech not in techBase): thisTech=fo.getTech(tech) if thisTech is None: continue missingPrereqs = [preReq for preReq in thisTech.recursivePrerequisites(empireID) if preReq not in techBase] techsToAdd.extend( missingPrereqs+[tech] ) techBase.update( missingPrereqs+[tech] ) for name in techsToAdd: try: enqueueRes = fo.issueEnqueueTechOrder(name, -1) if enqueueRes == 1: print " Enqueued Tech: " + name else: print " Error: failed attempt to enqueued Tech: " + name except: print " Error: failed attempt to enqueued Tech: " + name print " Error: exception triggered and caught: ", traceback.format_exc() print"" generateDefaultResearchOrders() print "\n\nAll techs:" alltechs = fo.techs() # returns names of all techs for tname in alltechs: print tname print "\n-------------------------------\nAll unqueued techs:" coveredTechs = newtech+completedTechs for tname in [tn for tn in alltechs if tn not in coveredTechs]: print tname elif fo.currentTurn() >50: generateDefaultResearchOrders()
def generate_research_orders(): """generate research orders""" report_adjustments = False empire = fo.getEmpire() empire_id = empire.empireID enemies_sighted = foAI.foAIstate.misc.get('enemies_sighted', {}) galaxy_is_sparse = ColonisationAI.galaxy_is_sparse() print "Research Queue Management:" resource_production = empire.resourceProduction(fo.resourceType.research) print "\nTotal Current Research Points: %.2f\n" % resource_production print "Techs researched and available for use:" completed_techs = sorted(list(get_completed_techs())) tlist = completed_techs + 3 * [" "] tlines = zip(tlist[0::3], tlist[1::3], tlist[2::3]) for tline in tlines: print "%25s %25s %25s" % tline print # # report techs currently at head of research queue # research_queue = empire.researchQueue research_queue_list = get_research_queue_techs() inProgressTechs.clear() tech_turns_left = {} if research_queue_list: print "Techs currently at head of Research Queue:" for element in list(research_queue)[:10]: tech_turns_left[element.tech] = element.turnsLeft if element.allocation > 0.0: inProgressTechs[element.tech] = True this_tech = fo.getTech(element.tech) if not this_tech: print "Error: can't retrieve tech ", element.tech continue missing_prereqs = [ preReq for preReq in this_tech.recursivePrerequisites(empire_id) if preReq not in completed_techs ] # unlocked_items = [(uli.name, uli.type) for uli in this_tech.unlocked_items] unlocked_items = [uli.name for uli in this_tech.unlockedItems] if not missing_prereqs: print " %25s allocated %6.2f RP -- unlockable items: %s " % ( element.tech, element.allocation, unlocked_items) else: print " %25s allocated %6.2f RP -- missing preReqs: %s -- unlockable items: %s " % ( element.tech, element.allocation, missing_prereqs, unlocked_items) print # # set starting techs, or after turn 100 add any additional default techs # if (fo.currentTurn() == 1) or ((fo.currentTurn() < 5) and (len(research_queue_list) == 0)): research_index = get_research_index() new_tech = TechsListsAI.sparse_galaxy_techs( research_index ) if galaxy_is_sparse else TechsListsAI.primary_meta_techs( research_index) print "Empire %s (%d) is selecting research index %d" % ( empire.name, empire_id, research_index) # techs_to_enqueue = (set(new_tech)-(set(completed_techs)|set(research_queue_list))) techs_to_enqueue = new_tech[:] tech_base = set(completed_techs + research_queue_list) techs_to_add = [] for tech in techs_to_enqueue: if tech not in tech_base: this_tech = fo.getTech(tech) if this_tech is None: print "Error: desired tech '%s' appears to not exist" % tech continue missing_prereqs = [ preReq for preReq in this_tech.recursivePrerequisites(empire_id) if preReq not in tech_base ] techs_to_add.extend(missing_prereqs + [tech]) tech_base.update(missing_prereqs + [tech]) cum_cost = 0 print " Enqueued Tech: %20s \t\t %8s \t %s" % ("Name", "Cost", "CumulativeCost") for name in techs_to_add: try: enqueue_res = fo.issueEnqueueTechOrder(name, -1) if enqueue_res == 1: this_tech = fo.getTech(name) this_cost = 0 if this_tech: this_cost = this_tech.researchCost(empire_id) cum_cost += this_cost print " Enqueued Tech: %20s \t\t %8.0f \t %8.0f" % ( name, this_cost, cum_cost) else: print " Error: failed attempt to enqueued Tech: " + name except: print " Error: failed attempt to enqueued Tech: " + name print " Error: exception triggered and caught: ", traceback.format_exc( ) if foAI.foAIstate.aggression <= fo.aggression.cautious: research_queue_list = get_research_queue_techs() def_techs = TechsListsAI.defense_techs_1() for def_tech in def_techs: if def_tech not in research_queue_list[: 5] and not tech_is_complete( def_tech): res = fo.issueEnqueueTechOrder( def_tech, min(3, len(research_queue_list))) print "Empire is very defensive, so attempted to fast-track %s, got result %d" % ( def_tech, res) if False and foAI.foAIstate.aggression >= fo.aggression.aggressive: # with current stats of Conc Camps, disabling this fast-track research_queue_list = get_research_queue_techs() if "CON_CONC_CAMP" in research_queue_list: insert_idx = min(40, research_queue_list.index("CON_CONC_CAMP")) else: insert_idx = max(0, min(40, len(research_queue_list) - 10)) if "SHP_DEFLECTOR_SHIELD" in research_queue_list: insert_idx = min( insert_idx, research_queue_list.index("SHP_DEFLECTOR_SHIELD")) for cc_tech in ["CON_ARCH_PSYCH", "CON_CONC_CAMP"]: if cc_tech not in research_queue_list[:insert_idx + 1] and not tech_is_complete( cc_tech): res = fo.issueEnqueueTechOrder(cc_tech, insert_idx) msg = "Empire is very aggressive, so attempted to fast-track %s, got result %d" % ( cc_tech, res) if report_adjustments: chat_human(msg) else: print msg print "" generate_default_research_order() print "\n\nAll techs:" alltechs = fo.techs() # returns names of all techs for tname in alltechs: print tname print "\n-------------------------------\nAll unqueued techs:" # coveredTechs = new_tech+completed_techs for tname in [tn for tn in alltechs if tn not in tech_base]: print tname elif fo.currentTurn() > 100: generate_default_research_order() research_queue_list = get_research_queue_techs() num_techs_accelerated = 1 # will ensure leading tech doesn't get dislodged got_ggg_tech = tech_is_complete("PRO_ORBITAL_GEN") got_sym_bio = tech_is_complete("GRO_SYMBIOTIC_BIO") got_xeno_gen = tech_is_complete("GRO_XENO_GENETICS") # # Consider accelerating techs; priority is # Supply/Detect range # xeno arch # ast / GG # gro xeno gen # distrib thought # quant net # pro sing gen # death ray 1 cleanup # # Supply range and detection range if False: # disabled for now, otherwise just to help with cold-folding / organization if len(foAI.foAIstate.colonisablePlanetIDs) == 0: best_colony_site_score = 0 else: best_colony_site_score = foAI.foAIstate.colonisablePlanetIDs.items( )[0][1] if len(foAI.foAIstate.colonisableOutpostIDs) == 0: best_outpost_site_score = 0 else: best_outpost_site_score = foAI.foAIstate.colonisableOutpostIDs.items( )[0][1] need_improved_scouting = (best_colony_site_score < 150 or best_outpost_site_score < 200) if need_improved_scouting: if not tech_is_complete("CON_ORBITAL_CON"): num_techs_accelerated += 1 if ("CON_ORBITAL_CON" not in research_queue_list[:1 + num_techs_accelerated] ) and (tech_is_complete("PRO_FUSION_GEN") or ("PRO_FUSION_GEN" in research_queue_list[:1 + num_techs_accelerated])): res = fo.issueEnqueueTechOrder("CON_ORBITAL_CON", num_techs_accelerated) msg = "Empire has poor colony/outpost prospects, so attempted to fast-track %s, got result %d" % ( "CON_ORBITAL_CON", res) if report_adjustments: chat_human(msg) else: print msg elif not tech_is_complete("CON_CONTGRAV_ARCH"): num_techs_accelerated += 1 if ("CON_CONTGRAV_ARCH" not in research_queue_list[:1 + num_techs_accelerated] ) and (tech_is_complete("CON_METRO_INFRA")): for supply_tech in [ _s_tech for _s_tech in ["CON_ARCH_MONOFILS", "CON_CONTGRAV_ARCH"] if not tech_is_complete(_s_tech) ]: res = fo.issueEnqueueTechOrder(supply_tech, num_techs_accelerated) msg = "Empire has poor colony/outpost prospects, so attempted to fast-track %s, got result %d" % ( supply_tech, res) if report_adjustments: chat_human(msg) else: print msg elif not tech_is_complete("CON_GAL_INFRA"): num_techs_accelerated += 1 if ("CON_GAL_INFRA" not in research_queue_list[:1 + num_techs_accelerated] ) and (tech_is_complete("PRO_SINGULAR_GEN")): res = fo.issueEnqueueTechOrder("CON_GAL_INFRA", num_techs_accelerated) msg = "Empire has poor colony/outpost prospects, so attempted to fast-track %s, got result %d" % ( "CON_GAL_INFRA", res) if report_adjustments: chat_human(msg) else: print msg else: pass research_queue_list = get_research_queue_techs() # could add more supply tech if False and not tech_is_complete( "SPY_DETECT_2"): # disabled for now, detect2 num_techs_accelerated += 1 if "SPY_DETECT_2" not in research_queue_list[:2 + num_techs_accelerated] and tech_is_complete( "PRO_FUSION_GEN" ): if "CON_ORBITAL_CON" not in research_queue_list[:1 + num_techs_accelerated]: res = fo.issueEnqueueTechOrder("SPY_DETECT_2", num_techs_accelerated) else: co_idx = research_queue_list.index("CON_ORBITAL_CON") res = fo.issueEnqueueTechOrder("SPY_DETECT_2", co_idx + 1) msg = "Empire has poor colony/outpost prospects, so attempted to fast-track %s, got result %d" % ( "CON_ORBITAL_CON", res) if report_adjustments: chat_human(msg) else: print msg research_queue_list = get_research_queue_techs() # # check to accelerate xeno_arch if True: # just to help with cold-folding / organization if (ColonisationAI.gotRuins and not tech_is_complete("LRN_XENOARCH") and foAI.foAIstate.aggression >= fo.aggression.typical): if "LRN_ARTIF_MINDS" in research_queue_list: insert_idx = 7 + research_queue_list.index("LRN_ARTIF_MINDS") elif "GRO_SYMBIOTIC_BIO" in research_queue_list: insert_idx = research_queue_list.index("GRO_SYMBIOTIC_BIO") + 1 else: insert_idx = num_techs_accelerated if "LRN_XENOARCH" not in research_queue_list[:insert_idx]: for xenoTech in [ "LRN_XENOARCH", "LRN_TRANSLING_THT", "LRN_PHYS_BRAIN", "LRN_ALGO_ELEGANCE" ]: if not tech_is_complete( xenoTech ) and xenoTech not in research_queue_list[:(insert_idx + 4)]: res = fo.issueEnqueueTechOrder(xenoTech, insert_idx) num_techs_accelerated += 1 msg = "ANCIENT_RUINS: have an ancient ruins, so attempted to fast-track %s to enable LRN_XENOARCH, got result %d" % ( xenoTech, res) if report_adjustments: chat_human(msg) else: print msg research_queue_list = get_research_queue_techs() if False and not enemies_sighted: # curently disabled # params = [ (tech, gate, target_slot, add_tech_list), ] params = [ ("GRO_XENO_GENETICS", "PRO_EXOBOTS", "PRO_EXOBOTS", ["GRO_GENETIC_MED", "GRO_XENO_GENETICS"]), ("PRO_EXOBOTS", "PRO_SENTIENT_AUTOMATION", "PRO_SENTIENT_AUTOMATION", ["PRO_EXOBOTS"]), ("PRO_SENTIENT_AUTOMATION", "PRO_NANOTECH_PROD", "PRO_NANOTECH_PROD", ["PRO_SENTIENT_AUTOMATION"]), ("PRO_INDUSTRY_CENTER_I", "GRO_SYMBIOTIC_BIO", "GRO_SYMBIOTIC_BIO", ["PRO_ROBOTIC_PROD", "PRO_FUSION_GEN", "PRO_INDUSTRY_CENTER_I"]), ("GRO_SYMBIOTIC_BIO", "SHP_ORG_HULL", "SHP_ZORTRIUM_PLATE", ["GRO_SYMBIOTIC_BIO"]), ] for (tech, gate, target_slot, add_tech_list) in params: if tech_is_complete(tech): break if tech_turns_left.get(gate, 0) not in [ 0, 1, 2 ]: # needs to exclude -1, the flag for no predicted completion continue if target_slot in research_queue_list: target_index = 1 + research_queue_list.index(target_slot) else: target_index = num_techs_accelerated for move_tech in add_tech_list: print "for tech %s, target_slot %s, target_index:%s ; num_techs_accelerated:%s" % ( move_tech, target_slot, target_index, num_techs_accelerated) if tech_is_complete(move_tech): continue if target_index <= num_techs_accelerated: num_techs_accelerated += 1 if move_tech not in research_queue_list[:1 + target_index]: res = fo.issueEnqueueTechOrder(move_tech, target_index) msg = "Research: To prioritize %s, have advanced %s to slot %d" % ( tech, move_tech, target_index) if report_adjustments: chat_human(msg) else: print msg target_index += 1 # # check to accelerate asteroid or GG tech if True: # just to help with cold-folding / organization if ColonisationAI.got_ast: insert_idx = num_techs_accelerated if "GRO_SYMBIOTIC_BIO" not in research_queue_list else research_queue_list.index( "GRO_SYMBIOTIC_BIO") ast_tech = "PRO_MICROGRAV_MAN" if not (tech_is_complete(ast_tech) or ast_tech in research_queue_list[:(1 + insert_idx)]): res = fo.issueEnqueueTechOrder(ast_tech, insert_idx) num_techs_accelerated += 1 msg = "Asteroids: plan to colonize an asteroid belt, so attempted to fast-track %s , got result %d" % ( ast_tech, res) if report_adjustments: chat_human(msg) else: print msg research_queue_list = get_research_queue_techs() elif tech_is_complete("SHP_ZORTRIUM_PLATE"): insert_idx = ( 1 + insert_idx ) if "LRN_FORCE_FIELD" not in research_queue_list else max( 1 + insert_idx, research_queue_list.index("LRN_FORCE_FIELD") - 1) for ast_tech in [ "SHP_ASTEROID_HULLS", "SHP_IMPROVED_ENGINE_COUPLINGS" ]: if not tech_is_complete( ast_tech ) and ast_tech not in research_queue_list[:insert_idx + 1]: res = fo.issueEnqueueTechOrder(ast_tech, insert_idx) num_techs_accelerated += 1 insert_idx += 1 msg = "Asteroids: plan to colonize an asteroid belt, so attempted to fast-track %s , got result %d" % ( ast_tech, res) print msg if report_adjustments: chat_human(msg) research_queue_list = get_research_queue_techs() if ColonisationAI.got_gg and not tech_is_complete("PRO_ORBITAL_GEN"): fusion_idx = 0 if "PRO_FUSION_GEN" not in research_queue_list else ( 1 + research_queue_list.index("PRO_FUSION_GEN")) forcefields_idx = 0 if "LRN_FORCE_FIELD" not in research_queue_list else ( 1 + research_queue_list.index("LRN_FORCE_FIELD")) insert_idx = max( fusion_idx, forcefields_idx) if enemies_sighted else fusion_idx if "PRO_ORBITAL_GEN" not in research_queue_list[:insert_idx + 1]: res = fo.issueEnqueueTechOrder("PRO_ORBITAL_GEN", insert_idx) num_techs_accelerated += 1 msg = "GasGiant: plan to colonize a gas giant, so attempted to fast-track %s, got result %d" % ( "PRO_ORBITAL_GEN", res) print msg if report_adjustments: chat_human(msg) research_queue_list = get_research_queue_techs() # # assess if our empire has any non-lousy colonizers, & boost gro_xeno_gen if we don't if True: # just to help with cold-folding / organization if got_ggg_tech and got_sym_bio and ( not got_xeno_gen ) and foAI.foAIstate.aggression >= fo.aggression.cautious: most_adequate = 0 for specName in ColonisationAI.empire_colonizers: environs = {} this_spec = fo.getSpecies(specName) if not this_spec: continue for ptype in [ fo.planetType.swamp, fo.planetType.radiated, fo.planetType.toxic, fo.planetType.inferno, fo.planetType.barren, fo.planetType.tundra, fo.planetType.desert, fo.planetType.terran, fo.planetType.ocean, fo.planetType.asteroids ]: environ = this_spec.getPlanetEnvironment(ptype) environs.setdefault(environ, []).append(ptype) most_adequate = max( most_adequate, len(environs.get(fo.planetEnvironment.adequate, []))) if most_adequate == 0: insert_idx = num_techs_accelerated for xg_tech in ["GRO_XENO_GENETICS", "GRO_GENETIC_ENG"]: if xg_tech not in research_queue_list[:1 + num_techs_accelerated] and not tech_is_complete( xg_tech): res = fo.issueEnqueueTechOrder(xg_tech, insert_idx) num_techs_accelerated += 1 msg = "Empire has poor colonizers, so attempted to fast-track %s, got result %d" % ( xg_tech, res) print msg if report_adjustments: chat_human(msg) research_queue_list = get_research_queue_techs() # # check to accelerate distrib thought if True: # just to help with cold-folding / organization if not tech_is_complete("LRN_DISTRIB_THOUGHT"): got_telepathy = False for specName in ColonisationAI.empire_species: this_spec = fo.getSpecies(specName) if this_spec and ("TELEPATHIC" in list(this_spec.tags)): got_telepathy = True break if (foAI.foAIstate.aggression > fo.aggression.cautious) and (empire.population() > ([300, 100][got_telepathy])): insert_idx = num_techs_accelerated for dt_ech in [ "LRN_PHYS_BRAIN", "LRN_TRANSLING_THT", "LRN_PSIONICS", "LRN_DISTRIB_THOUGHT" ]: if dt_ech not in research_queue_list[:insert_idx + 2] and not tech_is_complete( dt_ech): res = fo.issueEnqueueTechOrder(dt_ech, insert_idx) num_techs_accelerated += 1 insert_idx += 1 fmt_str = "Empire has a telepathic race, so attempted to fast-track %s (got result %d)" fmt_str += " with current target_RP %.1f and current pop %.1f, on turn %d" msg = fmt_str % (dt_ech, res, resource_production, empire.population(), fo.currentTurn()) print msg if report_adjustments: chat_human(msg) research_queue_list = get_research_queue_techs() # # check to accelerate quant net if False: # disabled for now, otherwise just to help with cold-folding / organization if (foAI.foAIstate.aggression > fo.aggression.cautious) and ( ColonisationAI.empire_status.get('researchers', 0) >= 40): if not tech_is_complete("LRN_QUANT_NET"): insert_idx = num_techs_accelerated # TODO determine min target slot if reenabling for qnTech in ["LRN_NDIM_SUBSPACE", "LRN_QUANT_NET"]: if qnTech not in research_queue_list[:insert_idx + 2] and not tech_is_complete( qnTech): res = fo.issueEnqueueTechOrder(qnTech, insert_idx) num_techs_accelerated += 1 insert_idx += 1 msg = "Empire has many researchers, so attempted to fast-track %s (got result %d) on turn %d" % ( qnTech, res, fo.currentTurn()) print msg if report_adjustments: chat_human(msg) research_queue_list = get_research_queue_techs() # # if we own a blackhole, accelerate sing_gen and conc camp if True: # just to help with cold-folding / organization if (fo.currentTurn() > 50 and len(AIstate.empireStars.get(fo.starType.blackHole, [])) != 0 and foAI.foAIstate.aggression > fo.aggression.cautious and not tech_is_complete(AIDependencies.PRO_SINGULAR_GEN) and tech_is_complete(AIDependencies.PRO_SOL_ORB_GEN)): # sing_tech_list = [ "LRN_GRAVITONICS" , "PRO_SINGULAR_GEN"] # formerly also "CON_ARCH_PSYCH", "CON_CONC_CAMP", sing_gen_tech = fo.getTech(AIDependencies.PRO_SINGULAR_GEN) sing_tech_list = [ pre_req for pre_req in sing_gen_tech.recursivePrerequisites(empire_id) if not tech_is_complete(pre_req) ] sing_tech_list += [AIDependencies.PRO_SINGULAR_GEN] for singTech in sing_tech_list: if singTech not in research_queue_list[:num_techs_accelerated + 1]: res = fo.issueEnqueueTechOrder(singTech, num_techs_accelerated) num_techs_accelerated += 1 msg = "have a black hole star outpost/colony, so attempted to fast-track %s, got result %d" % ( singTech, res) print msg if report_adjustments: chat_human(msg) research_queue_list = get_research_queue_techs() # # if got deathray from Ruins, remove most prereqs from queue if True: # just to help with cold-folding / organization if tech_is_complete("SHP_WEAPON_4_1"): this_tech = fo.getTech("SHP_WEAPON_4_1") if this_tech: missing_prereqs = [ preReq for preReq in this_tech.recursivePrerequisites(empire_id) if preReq in research_queue_list ] if len(missing_prereqs ) > 2: # leave plasma 4 and 3 if up to them already for preReq in missing_prereqs: # sorted(missing_prereqs, reverse=True)[2:] if preReq in research_queue_list: fo.issueDequeueTechOrder(preReq) research_queue_list = get_research_queue_techs() if "SHP_WEAPON_4_2" in research_queue_list: # (should be) idx = research_queue_list.index("SHP_WEAPON_4_2") fo.issueEnqueueTechOrder("SHP_WEAPON_4_2", max(0, idx - 18))
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: debug("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=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) aistate = get_aistate() system_status = aistate.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 = aistate.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 in [MissionType.SECURE, MissionType.MILITARY]: 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: debug("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: debug(' - 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) debug(' - system secured: %s' % system_secured) return [planet_score, planned_troops]
def evaluateInvasionPlanet(planetID, missionType, fleetSupplyablePlanetIDs, empire): "return the invasion value of a planet" buildingValues = {"BLD_IMPERIAL_PALACE": 1000, "BLD_CULTURE_ARCHIVES": 1000, "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": 150, "BLD_SHIPYARD_AST_REF": 500, "BLD_SHIPYARD_ENRG_COMP": 500, "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, } #TODO: add more factors, as used for colonization universe = fo.getUniverse() empireID = empire.empireID maxJumps=8 planet = universe.getPlanet(planetID) if (planet == None) : #TODO: exclude planets with stealth higher than empireDetection print "invasion AI couldn't get current info on planet %d"%planetID return 0, 0 bldTally=0 for bldType in [universe.getObject(bldg).buildingTypeName for bldg in planet.buildingIDs]: bldTally += buildingValues.get(bldType, 50) capitolID = PlanetUtilsAI.getCapital() if capitolID: homeworld = universe.getPlanet(capitolID) if homeworld: homeSystemID = homeworld.systemID evalSystemID = planet.systemID leastJumpsPath = len(universe.leastJumpsPath(homeSystemID, evalSystemID, empireID)) maxJumps = leastJumpsPath troops = planet.currentMeterValue(fo.meterType.troops) maxTroops = planet.currentMeterValue(fo.meterType.maxTroops) specName=planet.speciesName species=fo.getSpecies(specName) popTSize = planet.currentMeterValue(fo.meterType.targetPopulation)#TODO: adjust for empire tech planetSpecials = list(planet.specials) pSysID = planet.systemID#TODO: check star value indVal = 0 basePopInd=0.2 prodFactor = 1 discountMultiplier=20 for special in [ "MINERALS_SPECIAL", "CRYSTALS_SPECIAL", "METALOIDS_SPECIAL"] : if special in planetSpecials: prodFactor+=1 proSingVal = [0, 4][(len( AIstate.empireStars.get(fo.starType.blackHole, [])) > 0)] indTechMap={ "GRO_ENERGY_META": 0.5, "PRO_ROBOTIC_PROD":0.4, "PRO_FUSION_GEN": 1.0, "PRO_INDUSTRY_CENTER_I": 1, "PRO_INDUSTRY_CENTER_II":1, "PRO_INDUSTRY_CENTER_III":1, "PRO_SOL_ORB_GEN": 2.0, #assumes will build a gen at a blue/white star "PRO_SINGULAR_GEN": proSingVal, } for tech in indTechMap: if (empire.getTechStatus(tech) == fo.techStatus.complete): prodFactor += indTechMap[tech] indVal = discountMultiplier * basePopInd *prodFactor*popTSize if (empire.getTechStatus("PRO_SENTIENT_AUTOMATION") == fo.techStatus.complete): indVal += discountMultiplier * 5 pmaxShield = planet.currentMeterValue(fo.meterType.maxShield) sysFThrt = foAI.foAIstate.systemStatus.get(pSysID, {}).get('fleetThreat', 1000 ) sysMThrt = foAI.foAIstate.systemStatus.get(pSysID, {}).get('monsterThreat', 0 ) print "invasion eval of %s %d --- maxShields %.1f -- sysFleetThreat %.1f -- sysMonsterThreat %.1f"%(planet.name, planetID, pmaxShield, sysFThrt, sysMThrt) supplyVal=0 enemyVal=0 if planet.owner!=-1 : #value in taking this away from an enemy enemyVal= 20* max(planet.currentMeterValue(fo.meterType.targetIndustry), 2*planet.currentMeterValue(fo.meterType.targetResearch)) if not species:#TODO: perhaps stealth makes planet inacccesible & should abort try: targetPop=planet.currentMeterValue(fo.meterType.targetPopulation) popVal = 2*targetPop except: popVal=0 else: popVal = evaluatePlanet(planetID, AIFleetMissionType.FLEET_MISSION_COLONISATION, [planetID], species, empire) #evaluatePlanet is imported from ColonisationAI if planetID in fleetSupplyablePlanetIDs: #TODO: extend to rings supplyVal = 100 if planet.owner== -1: #if (pmaxShield <10): if ( sysFThrt < 0.5*curBestMilShipRating() ): if ( sysMThrt < 3*curBestMilShipRating()): supplyVal = 10000 else: supplyVal = 50 planetSpecials = list(planet.specials) specialVal=0 if ( ( planet.size == fo.planetSize.asteroids ) and (empire.getTechStatus("PRO_ASTEROID_MINE") == fo.techStatus.complete ) ): specialVal= 15 #TODO: should do more eval re asteroid mining here for special in [ "MINERALS_SPECIAL", "CRYSTALS_SPECIAL", "METALOIDS_SPECIAL"] : if special in planetSpecials: specialVal +=10 # buildTime=4 return max(0, popVal+supplyVal+specialVal+bldTally+indVal+enemyVal-20*troops), min(troops+maxJumps+buildTime, maxTroops)
def generateResearchOrders(): global inProgressTechs "generate research orders" universe=fo.getUniverse() empire = fo.getEmpire() empireID = empire.empireID print "Research Queue Management:" tRP = empire.resourceProduction(fo.resourceType.research) print "\nTotal Current Research Points: %.2f\n"%tRP print "Techs researched and available for use:" completedTechs = sorted(list(getCompletedTechs())) tlist = completedTechs+3*[" "] tlines = zip( tlist[0::3], tlist[1::3], tlist[2::3]) for tline in tlines: print "%25s %25s %25s"%tline print"" researchQueueList = getResearchQueueTechs() if tRP >= 20 and foAI.foAIstate.aggression > fo.aggression.cautious: if (empire.getTechStatus("LRN_PSIONICS") != fo.techStatus.complete) and ( "LRN_PSIONICS" not in researchQueueList[:5] ) : for specName in ColonisationAI.empireSpecies: thisSpec=fo.getSpecies(specName) if thisSpec: if "TELEPATHIC" in list(thisSpec.tags): res=fo.issueEnqueueTechOrder("LRN_DISTRIB_THOUGHT", 0) res=fo.issueEnqueueTechOrder("LRN_PSIONICS", 0) break if len(foAI.foAIstate.colonisablePlanetIDs)==0: bestColonySiteScore = 0 else: bestColonySiteScore= foAI.foAIstate.colonisablePlanetIDs[0][1] if len(foAI.foAIstate.colonisableOutpostIDs)==0: bestOutpostSiteScore = 0 else: bestOutpostSiteScore= foAI.foAIstate.colonisableOutpostIDs[0][1] needImprovedScouting = ( bestColonySiteScore <150 or bestOutpostSiteScore < 200 ) if needImprovedScouting: if (empire.getTechStatus("CON_ORBITAL_CON") != fo.techStatus.complete): if ( "CON_ORBITAL_CON" not in researchQueueList[:2] ) and ((empire.getTechStatus("PRO_FUSION_GEN") == fo.techStatus.complete) or ( "PRO_FUSION_GEN" in researchQueueList[:1] )): res=fo.issueEnqueueTechOrder("CON_ORBITAL_CON", 1) print "Empire has poor colony/outpost prospects, so attempted to fast-track %s, got result %d"%("CON_ORBITAL_CON", res) else: pass #could add more supply tech if (empire.getTechStatus("SPY_DETECT_2") != fo.techStatus.complete): if ( "SPY_DETECT_2" not in researchQueueList[:3] ) and (empire.getTechStatus("PRO_FUSION_GEN") == fo.techStatus.complete) : if ( "CON_ORBITAL_CON" not in researchQueueList[:2] ): res=fo.issueEnqueueTechOrder("SPY_DETECT_2", 1) else: CO_idx = researchQueueList.index( "CON_ORBITAL_CON") res=fo.issueEnqueueTechOrder("SPY_DETECT_2", CO_idx+1) print "Empire has poor colony/outpost prospects, so attempted to fast-track %s, got result %d"%("CON_ORBITAL_CON", res) gotGGG = empire.getTechStatus("PRO_ORBITAL_GEN") == fo.techStatus.complete gotSymBio = empire.getTechStatus("GRO_SYMBIOTIC_BIO") == fo.techStatus.complete gotXenoGen = empire.getTechStatus("GRO_XENO_GENETICS") == fo.techStatus.complete #assess if our empire has any non-lousy colonizers, & boost gro_xeno_gen if we don't if gotGGG and gotSymBio and (not gotXenoGen) and foAI.foAIstate.aggression >= fo.aggression.cautious: mostAdequate=0 for specName in ColonisationAI.empireColonizers: environs={} thisSpec = fo.getSpecies(specName) if not thisSpec: continue for ptype in [fo.planetType.swamp, fo.planetType.radiated, fo.planetType.toxic, fo.planetType.inferno, fo.planetType.barren, fo.planetType.tundra, fo.planetType.desert, fo.planetType.terran, fo.planetType.ocean, fo.planetType.asteroids]: environ=thisSpec.getPlanetEnvironment(ptype) environs.setdefault(environ, []).append(ptype) mostAdequate = max(mostAdequate, len(environs.get( fo.planetEnvironment.adequate, []))) if mostAdequate==0: researchQueue = empire.researchQueue researchQueueList = getResearchQueueTechs() for xgTech in [ "GRO_XENO_GENETICS", "GRO_GENETIC_ENG" ]: if xgTech not in researchQueueList[:2] and empire.getTechStatus(xgTech) != fo.techStatus.complete: res=fo.issueEnqueueTechOrder(xgTech, 0) print "Empire has poor colonizers, so attempted to fast-track %s, got result %d"%(xgTech, res) researchQueue = empire.researchQueue researchQueueList = getResearchQueueTechs() inProgressTechs.clear() if researchQueueList: print "Techs currently at head of Research Queue:" for element in list(researchQueue)[:10]: if element.allocation > 0.0: inProgressTechs[element.tech]=True thisTech=fo.getTech(element.tech) missingPrereqs = [preReq for preReq in thisTech.recursivePrerequisites(empireID) if preReq not in completedTechs] unlockedItems = [(uli.name, uli.type) for uli in thisTech.unlockedItems] if not missingPrereqs: print " %25s allocated %6.2f RP -- unlockable items: %s "%(element.tech, element.allocation, unlockedItems) else: print " %25s allocated %6.2f RP -- missing preReqs: %s -- unlockable items: %s "%(element.tech, element.allocation, missingPrereqs, unlockedItems) print "" if (fo.currentTurn()==1) or ((fo.currentTurn()<5) and (len(researchQueueList)==0) ): if foAI.foAIstate.aggression <=fo.aggression.typical: newtech = TechsListsAI.primaryMetaTechsList( index=empireID%2 ) else: newtech = TechsListsAI.primaryMetaTechsList( index=empireID%2 ) #pLTsToEnqueue = (set(newtech)-(set(completedTechs)|set(researchQueueList))) pLTsToEnqueue = newtech[:] techBase = set(completedTechs+researchQueueList) techsToAdd=[] for tech in pLTsToEnqueue: if (tech not in techBase): thisTech=fo.getTech(tech) if thisTech is None: print "Error: desired tech '%s' appears to not exist"%tech continue missingPrereqs = [preReq for preReq in thisTech.recursivePrerequisites(empireID) if preReq not in techBase] techsToAdd.extend( missingPrereqs+[tech] ) techBase.update( missingPrereqs+[tech] ) cumCost=0 print " Enqueued Tech: %20s \t\t %8s \t %s"%("Name", "Cost", "CumulativeCost") for name in techsToAdd: try: enqueueRes = fo.issueEnqueueTechOrder(name, -1) if enqueueRes == 1: thisTech=fo.getTech(name) thisCost=0 if thisTech: thisCost = thisTech.researchCost(empireID) cumCost += thisCost print " Enqueued Tech: %20s \t\t %8.0f \t %8.0f" % ( name, thisCost, cumCost) else: print " Error: failed attempt to enqueued Tech: " + name except: print " Error: failed attempt to enqueued Tech: " + name print " Error: exception triggered and caught: ", traceback.format_exc() if foAI.foAIstate.aggression <= fo.aggression.cautious: researchQueueList = getResearchQueueTechs() defTechs=TechsListsAI.defenseTechs1() for defTech in defTechs: if defTech not in researchQueueList[:5] and empire.getTechStatus(defTech) != fo.techStatus.complete: res=fo.issueEnqueueTechOrder(defTech, min(3, len(researchQueueList))) print "Empire is very defensive, so attempted to fast-track %s, got result %d"%(defTech, res) if foAI.foAIstate.aggression >= fo.aggression.aggressive: researchQueueList = getResearchQueueTechs() if "CON_CONC_CAMP" in researchQueueList: insertIdx = min(40, researchQueueList.index("CON_CONC_CAMP")) else: insertIdx=max(0, min(40, len(researchQueueList)-10)) if "SHP_ASTEROID_HULLS" in researchQueueList: insertIdx = min(insertIdx, researchQueueList.index("SHP_ASTEROID_HULLS")) for ccTech in [ "CON_ARCH_PSYCH", "CON_CONC_CAMP"]: if ccTech not in researchQueueList[:insertIdx+1] and empire.getTechStatus(ccTech) != fo.techStatus.complete: res=fo.issueEnqueueTechOrder(ccTech, insertIdx) print "Empire is very aggressive, so attempted to fast-track %s, got result %d"%(ccTech, res) print"" generateDefaultResearchOrders() print "\n\nAll techs:" alltechs = fo.techs() # returns names of all techs for tname in alltechs: print tname print "\n-------------------------------\nAll unqueued techs:" #coveredTechs = newtech+completedTechs for tname in [tn for tn in alltechs if tn not in techBase]: print tname elif fo.currentTurn() >100: generateDefaultResearchOrders() #researchQueueList = getResearchQueueTechs() if fo.currentTurn() >50 and len (AIstate.empireStars.get(fo.starType.blackHole, []))!=0 and foAI.foAIstate.aggression > fo.aggression.cautious: for singTech in [ "CON_ARCH_PSYCH", "CON_CONC_CAMP", "LRN_GRAVITONICS" , "PRO_SINGULAR_GEN"]: if (empire.getTechStatus(singTech) != fo.techStatus.complete) and ( singTech not in researchQueueList[:4]) : res=fo.issueEnqueueTechOrder(singTech,0) print "have a black hole star outpost/colony, so attempted to fast-track %s, got result %d"%(singTech, res)
def generate_research_orders(): """generate research orders""" report_adjustments = False empire = fo.getEmpire() empire_id = empire.empireID enemies_sighted = foAI.foAIstate.misc.get('enemies_sighted', {}) galaxy_is_sparse = ColonisationAI.galaxy_is_sparse() print "Research Queue Management:" resource_production = empire.resourceProduction(fo.resourceType.research) print "\nTotal Current Research Points: %.2f\n" % resource_production print "Techs researched and available for use:" completed_techs = sorted(list(get_completed_techs())) tlist = completed_techs+3*[" "] tlines = zip(tlist[0::3], tlist[1::3], tlist[2::3]) for tline in tlines: print "%25s %25s %25s" % tline print # # report techs currently at head of research queue # research_queue = empire.researchQueue research_queue_list = get_research_queue_techs() inProgressTechs.clear() tech_turns_left = {} if research_queue_list: print "Techs currently at head of Research Queue:" for element in list(research_queue)[:10]: tech_turns_left[element.tech] = element.turnsLeft if element.allocation > 0.0: inProgressTechs[element.tech] = True this_tech = fo.getTech(element.tech) if not this_tech: print "Error: can't retrieve tech ", element.tech continue missing_prereqs = [preReq for preReq in this_tech.recursivePrerequisites(empire_id) if preReq not in completed_techs] # unlocked_items = [(uli.name, uli.type) for uli in this_tech.unlocked_items] unlocked_items = [uli.name for uli in this_tech.unlockedItems] if not missing_prereqs: print " %25s allocated %6.2f RP -- unlockable items: %s " % (element.tech, element.allocation, unlocked_items) else: print " %25s allocated %6.2f RP -- missing preReqs: %s -- unlockable items: %s " % (element.tech, element.allocation, missing_prereqs, unlocked_items) print # # set starting techs, or after turn 100 add any additional default techs # if (fo.currentTurn() == 1) or ((fo.currentTurn() < 5) and (len(research_queue_list) == 0)): research_index = get_research_index() new_tech = TechsListsAI.sparse_galaxy_techs(research_index) if galaxy_is_sparse else TechsListsAI.primary_meta_techs(research_index) print "Empire %s (%d) is selecting research index %d" % (empire.name, empire_id, research_index) # techs_to_enqueue = (set(new_tech)-(set(completed_techs)|set(research_queue_list))) techs_to_enqueue = new_tech[:] tech_base = set(completed_techs+research_queue_list) techs_to_add = [] for tech in techs_to_enqueue: if tech not in tech_base: this_tech = fo.getTech(tech) if this_tech is None: print "Error: desired tech '%s' appears to not exist" % tech continue missing_prereqs = [preReq for preReq in this_tech.recursivePrerequisites(empire_id) if preReq not in tech_base] techs_to_add.extend(missing_prereqs + [tech]) tech_base.update(missing_prereqs+[tech]) cum_cost = 0 print " Enqueued Tech: %20s \t\t %8s \t %s" % ("Name", "Cost", "CumulativeCost") for name in techs_to_add: try: enqueue_res = fo.issueEnqueueTechOrder(name, -1) if enqueue_res == 1: this_tech = fo.getTech(name) this_cost = 0 if this_tech: this_cost = this_tech.researchCost(empire_id) cum_cost += this_cost print " Enqueued Tech: %20s \t\t %8.0f \t %8.0f" % (name, this_cost, cum_cost) else: print " Error: failed attempt to enqueued Tech: " + name except: print " Error: failed attempt to enqueued Tech: " + name print " Error: exception triggered and caught: ", traceback.format_exc() if foAI.foAIstate.aggression <= fo.aggression.cautious: research_queue_list = get_research_queue_techs() def_techs = TechsListsAI.defense_techs_1() for def_tech in def_techs: if def_tech not in research_queue_list[:5] and not tech_is_complete(def_tech): res = fo.issueEnqueueTechOrder(def_tech, min(3, len(research_queue_list))) print "Empire is very defensive, so attempted to fast-track %s, got result %d" % (def_tech, res) if False and foAI.foAIstate.aggression >= fo.aggression.aggressive: # with current stats of Conc Camps, disabling this fast-track research_queue_list = get_research_queue_techs() if "CON_CONC_CAMP" in research_queue_list: insert_idx = min(40, research_queue_list.index("CON_CONC_CAMP")) else: insert_idx = max(0, min(40, len(research_queue_list)-10)) if "SHP_DEFLECTOR_SHIELD" in research_queue_list: insert_idx = min(insert_idx, research_queue_list.index("SHP_DEFLECTOR_SHIELD")) for cc_tech in ["CON_ARCH_PSYCH", "CON_CONC_CAMP"]: if cc_tech not in research_queue_list[:insert_idx + 1] and not tech_is_complete(cc_tech): res = fo.issueEnqueueTechOrder(cc_tech, insert_idx) msg = "Empire is very aggressive, so attempted to fast-track %s, got result %d" % (cc_tech, res) if report_adjustments: chat_human(msg) else: print msg print"" generate_default_research_order() print "\n\nAll techs:" alltechs = fo.techs() # returns names of all techs for tname in alltechs: print tname print "\n-------------------------------\nAll unqueued techs:" # coveredTechs = new_tech+completed_techs for tname in [tn for tn in alltechs if tn not in tech_base]: print tname elif fo.currentTurn() > 100: generate_default_research_order() research_queue_list = get_research_queue_techs() num_techs_accelerated = 1 # will ensure leading tech doesn't get dislodged got_ggg_tech = tech_is_complete("PRO_ORBITAL_GEN") got_sym_bio = tech_is_complete("GRO_SYMBIOTIC_BIO") got_xeno_gen = tech_is_complete("GRO_XENO_GENETICS") # # Consider accelerating techs; priority is # Supply/Detect range # xeno arch # ast / GG # gro xeno gen # distrib thought # quant net # pro sing gen # death ray 1 cleanup # # Supply range and detection range if False: # disabled for now, otherwise just to help with cold-folding / organization if len(foAI.foAIstate.colonisablePlanetIDs) == 0: best_colony_site_score = 0 else: best_colony_site_score = foAI.foAIstate.colonisablePlanetIDs.items()[0][1] if len(foAI.foAIstate.colonisableOutpostIDs) == 0: best_outpost_site_score = 0 else: best_outpost_site_score = foAI.foAIstate.colonisableOutpostIDs.items()[0][1] need_improved_scouting = (best_colony_site_score < 150 or best_outpost_site_score < 200) if need_improved_scouting: if not tech_is_complete("CON_ORBITAL_CON"): num_techs_accelerated += 1 if ("CON_ORBITAL_CON" not in research_queue_list[:1 + num_techs_accelerated]) and ( tech_is_complete("PRO_FUSION_GEN") or ("PRO_FUSION_GEN" in research_queue_list[:1 + num_techs_accelerated])): res = fo.issueEnqueueTechOrder("CON_ORBITAL_CON", num_techs_accelerated) msg = "Empire has poor colony/outpost prospects, so attempted to fast-track %s, got result %d" % ("CON_ORBITAL_CON", res) if report_adjustments: chat_human(msg) else: print msg elif not tech_is_complete("CON_CONTGRAV_ARCH"): num_techs_accelerated += 1 if ("CON_CONTGRAV_ARCH" not in research_queue_list[:1+num_techs_accelerated]) and ( tech_is_complete("CON_METRO_INFRA")): for supply_tech in [_s_tech for _s_tech in ["CON_ARCH_MONOFILS", "CON_CONTGRAV_ARCH"] if not tech_is_complete(_s_tech)]: res = fo.issueEnqueueTechOrder(supply_tech, num_techs_accelerated) msg = "Empire has poor colony/outpost prospects, so attempted to fast-track %s, got result %d" % (supply_tech, res) if report_adjustments: chat_human(msg) else: print msg elif not tech_is_complete("CON_GAL_INFRA"): num_techs_accelerated += 1 if ("CON_GAL_INFRA" not in research_queue_list[:1+num_techs_accelerated]) and ( tech_is_complete("PRO_SINGULAR_GEN")): res = fo.issueEnqueueTechOrder("CON_GAL_INFRA", num_techs_accelerated) msg = "Empire has poor colony/outpost prospects, so attempted to fast-track %s, got result %d" % ("CON_GAL_INFRA", res) if report_adjustments: chat_human(msg) else: print msg else: pass research_queue_list = get_research_queue_techs() # could add more supply tech if False and not tech_is_complete("SPY_DETECT_2"): # disabled for now, detect2 num_techs_accelerated += 1 if "SPY_DETECT_2" not in research_queue_list[:2+num_techs_accelerated] and tech_is_complete("PRO_FUSION_GEN"): if "CON_ORBITAL_CON" not in research_queue_list[:1+num_techs_accelerated]: res = fo.issueEnqueueTechOrder("SPY_DETECT_2", num_techs_accelerated) else: co_idx = research_queue_list.index("CON_ORBITAL_CON") res = fo.issueEnqueueTechOrder("SPY_DETECT_2", co_idx + 1) msg = "Empire has poor colony/outpost prospects, so attempted to fast-track %s, got result %d" % ("CON_ORBITAL_CON", res) if report_adjustments: chat_human(msg) else: print msg research_queue_list = get_research_queue_techs() # # check to accelerate xeno_arch if True: # just to help with cold-folding / organization if (ColonisationAI.gotRuins and not tech_is_complete("LRN_XENOARCH") and foAI.foAIstate.aggression >= fo.aggression.typical): if "LRN_ARTIF_MINDS" in research_queue_list: insert_idx = 7 + research_queue_list.index("LRN_ARTIF_MINDS") elif "GRO_SYMBIOTIC_BIO" in research_queue_list: insert_idx = research_queue_list.index("GRO_SYMBIOTIC_BIO") + 1 else: insert_idx = num_techs_accelerated if "LRN_XENOARCH" not in research_queue_list[:insert_idx]: for xenoTech in ["LRN_XENOARCH", "LRN_TRANSLING_THT", "LRN_PHYS_BRAIN", "LRN_ALGO_ELEGANCE"]: if not tech_is_complete(xenoTech) and xenoTech not in research_queue_list[:(insert_idx + 4)]: res = fo.issueEnqueueTechOrder(xenoTech, insert_idx) num_techs_accelerated += 1 msg = "ANCIENT_RUINS: have an ancient ruins, so attempted to fast-track %s to enable LRN_XENOARCH, got result %d" % (xenoTech, res) if report_adjustments: chat_human(msg) else: print msg research_queue_list = get_research_queue_techs() if False and not enemies_sighted: # curently disabled # params = [ (tech, gate, target_slot, add_tech_list), ] params = [("GRO_XENO_GENETICS", "PRO_EXOBOTS", "PRO_EXOBOTS", ["GRO_GENETIC_MED", "GRO_XENO_GENETICS"]), ("PRO_EXOBOTS", "PRO_SENTIENT_AUTOMATION", "PRO_SENTIENT_AUTOMATION", ["PRO_EXOBOTS"]), ("PRO_SENTIENT_AUTOMATION", "PRO_NANOTECH_PROD", "PRO_NANOTECH_PROD", ["PRO_SENTIENT_AUTOMATION"]), ("PRO_INDUSTRY_CENTER_I", "GRO_SYMBIOTIC_BIO", "GRO_SYMBIOTIC_BIO", ["PRO_ROBOTIC_PROD", "PRO_FUSION_GEN", "PRO_INDUSTRY_CENTER_I"]), ("GRO_SYMBIOTIC_BIO", "SHP_ORG_HULL", "SHP_ZORTRIUM_PLATE", ["GRO_SYMBIOTIC_BIO"]), ] for (tech, gate, target_slot, add_tech_list) in params: if tech_is_complete(tech): break if tech_turns_left.get(gate, 0) not in [0, 1, 2]: # needs to exclude -1, the flag for no predicted completion continue if target_slot in research_queue_list: target_index = 1 + research_queue_list.index(target_slot) else: target_index = num_techs_accelerated for move_tech in add_tech_list: print "for tech %s, target_slot %s, target_index:%s ; num_techs_accelerated:%s" % (move_tech, target_slot, target_index, num_techs_accelerated) if tech_is_complete(move_tech): continue if target_index <= num_techs_accelerated: num_techs_accelerated += 1 if move_tech not in research_queue_list[:1 + target_index]: res = fo.issueEnqueueTechOrder(move_tech, target_index) msg = "Research: To prioritize %s, have advanced %s to slot %d" % (tech, move_tech, target_index) if report_adjustments: chat_human(msg) else: print msg target_index += 1 # # check to accelerate asteroid or GG tech if True: # just to help with cold-folding / organization if ColonisationAI.got_ast: insert_idx = num_techs_accelerated if "GRO_SYMBIOTIC_BIO" not in research_queue_list else research_queue_list.index("GRO_SYMBIOTIC_BIO") ast_tech = "PRO_MICROGRAV_MAN" if not (tech_is_complete(ast_tech) or ast_tech in research_queue_list[:(1 + insert_idx)]): res = fo.issueEnqueueTechOrder(ast_tech, insert_idx) num_techs_accelerated += 1 msg = "Asteroids: plan to colonize an asteroid belt, so attempted to fast-track %s , got result %d" % (ast_tech, res) if report_adjustments: chat_human(msg) else: print msg research_queue_list = get_research_queue_techs() elif tech_is_complete("SHP_ZORTRIUM_PLATE"): insert_idx = (1 + insert_idx) if "LRN_FORCE_FIELD" not in research_queue_list else max(1 + insert_idx, research_queue_list.index("LRN_FORCE_FIELD") - 1) for ast_tech in ["SHP_ASTEROID_HULLS", "SHP_IMPROVED_ENGINE_COUPLINGS"]: if not tech_is_complete(ast_tech) and ast_tech not in research_queue_list[:insert_idx + 1]: res = fo.issueEnqueueTechOrder(ast_tech, insert_idx) num_techs_accelerated += 1 insert_idx += 1 msg = "Asteroids: plan to colonize an asteroid belt, so attempted to fast-track %s , got result %d" % (ast_tech, res) print msg if report_adjustments: chat_human(msg) research_queue_list = get_research_queue_techs() if ColonisationAI.got_gg and not tech_is_complete("PRO_ORBITAL_GEN"): fusion_idx = 0 if "PRO_FUSION_GEN" not in research_queue_list else (1 + research_queue_list.index("PRO_FUSION_GEN")) forcefields_idx = 0 if "LRN_FORCE_FIELD" not in research_queue_list else (1 + research_queue_list.index("LRN_FORCE_FIELD")) insert_idx = max(fusion_idx, forcefields_idx) if enemies_sighted else fusion_idx if "PRO_ORBITAL_GEN" not in research_queue_list[:insert_idx+1]: res = fo.issueEnqueueTechOrder("PRO_ORBITAL_GEN", insert_idx) num_techs_accelerated += 1 msg = "GasGiant: plan to colonize a gas giant, so attempted to fast-track %s, got result %d" % ("PRO_ORBITAL_GEN", res) print msg if report_adjustments: chat_human(msg) research_queue_list = get_research_queue_techs() # # assess if our empire has any non-lousy colonizers, & boost gro_xeno_gen if we don't if True: # just to help with cold-folding / organization if got_ggg_tech and got_sym_bio and (not got_xeno_gen) and foAI.foAIstate.aggression >= fo.aggression.cautious: most_adequate = 0 for specName in ColonisationAI.empire_colonizers: environs = {} this_spec = fo.getSpecies(specName) if not this_spec: continue for ptype in [fo.planetType.swamp, fo.planetType.radiated, fo.planetType.toxic, fo.planetType.inferno, fo.planetType.barren, fo.planetType.tundra, fo.planetType.desert, fo.planetType.terran, fo.planetType.ocean, fo.planetType.asteroids]: environ = this_spec.getPlanetEnvironment(ptype) environs.setdefault(environ, []).append(ptype) most_adequate = max(most_adequate, len(environs.get(fo.planetEnvironment.adequate, []))) if most_adequate == 0: insert_idx = num_techs_accelerated for xg_tech in ["GRO_XENO_GENETICS", "GRO_GENETIC_ENG"]: if xg_tech not in research_queue_list[:1+num_techs_accelerated] and not tech_is_complete(xg_tech): res = fo.issueEnqueueTechOrder(xg_tech, insert_idx) num_techs_accelerated += 1 msg = "Empire has poor colonizers, so attempted to fast-track %s, got result %d" % (xg_tech, res) print msg if report_adjustments: chat_human(msg) research_queue_list = get_research_queue_techs() # # check to accelerate distrib thought if True: # just to help with cold-folding / organization if not tech_is_complete("LRN_DISTRIB_THOUGHT"): got_telepathy = False for specName in ColonisationAI.empire_species: this_spec = fo.getSpecies(specName) if this_spec and ("TELEPATHIC" in list(this_spec.tags)): got_telepathy = True break if (foAI.foAIstate.aggression > fo.aggression.cautious) and (empire.population() > ([300, 100][got_telepathy])): insert_idx = num_techs_accelerated for dt_ech in ["LRN_PHYS_BRAIN", "LRN_TRANSLING_THT", "LRN_PSIONICS", "LRN_DISTRIB_THOUGHT"]: if dt_ech not in research_queue_list[:insert_idx + 2] and not tech_is_complete(dt_ech): res = fo.issueEnqueueTechOrder(dt_ech, insert_idx) num_techs_accelerated += 1 insert_idx += 1 fmt_str = "Empire has a telepathic race, so attempted to fast-track %s (got result %d)" fmt_str += " with current target_RP %.1f and current pop %.1f, on turn %d" msg = fmt_str % (dt_ech, res, resource_production, empire.population(), fo.currentTurn()) print msg if report_adjustments: chat_human(msg) research_queue_list = get_research_queue_techs() # # check to accelerate quant net if False: # disabled for now, otherwise just to help with cold-folding / organization if (foAI.foAIstate.aggression > fo.aggression.cautious) and (ColonisationAI.empire_status.get('researchers', 0) >= 40): if not tech_is_complete("LRN_QUANT_NET"): insert_idx = num_techs_accelerated # TODO determine min target slot if reenabling for qnTech in ["LRN_NDIM_SUBSPACE", "LRN_QUANT_NET"]: if qnTech not in research_queue_list[:insert_idx + 2] and not tech_is_complete(qnTech): res = fo.issueEnqueueTechOrder(qnTech, insert_idx) num_techs_accelerated += 1 insert_idx += 1 msg = "Empire has many researchers, so attempted to fast-track %s (got result %d) on turn %d" % (qnTech, res, fo.currentTurn()) print msg if report_adjustments: chat_human(msg) research_queue_list = get_research_queue_techs() # # if we own a blackhole, accelerate sing_gen and conc camp if True: # just to help with cold-folding / organization if (fo.currentTurn() > 50 and len(AIstate.empireStars.get(fo.starType.blackHole, [])) != 0 and foAI.foAIstate.aggression > fo.aggression.cautious and not tech_is_complete(AIDependencies.PRO_SINGULAR_GEN) and tech_is_complete(AIDependencies.PRO_SOL_ORB_GEN)): # sing_tech_list = [ "LRN_GRAVITONICS" , "PRO_SINGULAR_GEN"] # formerly also "CON_ARCH_PSYCH", "CON_CONC_CAMP", sing_gen_tech = fo.getTech(AIDependencies.PRO_SINGULAR_GEN) sing_tech_list = [pre_req for pre_req in sing_gen_tech.recursivePrerequisites(empire_id) if not tech_is_complete(pre_req)] sing_tech_list += [AIDependencies.PRO_SINGULAR_GEN] for singTech in sing_tech_list: if singTech not in research_queue_list[:num_techs_accelerated+1]: res = fo.issueEnqueueTechOrder(singTech, num_techs_accelerated) num_techs_accelerated += 1 msg = "have a black hole star outpost/colony, so attempted to fast-track %s, got result %d" % (singTech, res) print msg if report_adjustments: chat_human(msg) research_queue_list = get_research_queue_techs() # # if got deathray from Ruins, remove most prereqs from queue if True: # just to help with cold-folding / organization if tech_is_complete("SHP_WEAPON_4_1"): this_tech = fo.getTech("SHP_WEAPON_4_1") if this_tech: missing_prereqs = [preReq for preReq in this_tech.recursivePrerequisites(empire_id) if preReq in research_queue_list] if len(missing_prereqs) > 2: # leave plasma 4 and 3 if up to them already for preReq in missing_prereqs: # sorted(missing_prereqs, reverse=True)[2:] if preReq in research_queue_list: fo.issueDequeueTechOrder(preReq) research_queue_list = get_research_queue_techs() if "SHP_WEAPON_4_2" in research_queue_list: # (should be) idx = research_queue_list.index("SHP_WEAPON_4_2") fo.issueEnqueueTechOrder("SHP_WEAPON_4_2", max(0, idx-18))
def evaluate_invasion_planet(planet_id, secure_fleet_missions, verbose=True): """Return the invasion value (score, troops) of a planet.""" detail = [] 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, } # TODO: add more factors, as used for colonization universe = fo.getUniverse() empire_id = fo.empireID() max_jumps = 8 planet = universe.getPlanet(planet_id) if planet is None: # TODO: exclude planets with stealth higher than empireDetection print "invasion AI couldn't access any info for planet id %d" % planet_id return [0, 0] sys_partial_vis_turn = universe.getVisibilityTurnsMap(planet.systemID, empire_id).get(fo.visibility.partial, -9999) planet_partial_vis_turn = universe.getVisibilityTurnsMap(planet_id, empire_id).get(fo.visibility.partial, -9999) if planet_partial_vis_turn < sys_partial_vis_turn: print "invasion AI couldn't get current info on planet id %d (was stealthed at last sighting)" % planet_id # TODO: track detection strength, order new scouting when it goes up return [0, 0] # last time we had partial vis of the system, the planet was stealthed to us 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) pop_val = max(0.75 * planet_eval.get(planet_id, [0])[0], ColonisationAI.evaluate_planet(planet_id, MissionType.OUTPOST, None, detail)) else: pop_val = ColonisationAI.evaluate_planet(planet_id, MissionType.INVASION, species_name, detail) 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)) tech_tally = 0 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_tally += rp_cost * 4 detail.append("%s: %d" % (unlocked_tech, rp_cost * 4)) p_sys_id = planet.systemID capitol_id = PlanetUtilsAI.get_capital() least_jumps_path = [] clear_path = True if capitol_id: homeworld = universe.getPlanet(capitol_id) if homeworld: home_system_id = homeworld.systemID eval_system_id = planet.systemID if (home_system_id != INVALID_ID) and (eval_system_id != INVALID_ID): least_jumps_path = list(universe.leastJumpsPath(home_system_id, eval_system_id, empire_id)) max_jumps = len(least_jumps_path) system_status = foAI.foAIstate.systemStatus.get(p_sys_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) 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(p_sys_id) secure_targets = [p_sys_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 != p_sys_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) supply_val = 0 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)) if p_sys_id in ColonisationAI.annexable_system_ids: # TODO: extend to rings supply_val = 100 elif p_sys_id in ColonisationAI.annexable_ring1: supply_val = 200 elif p_sys_id in ColonisationAI.annexable_ring2: supply_val = 300 elif p_sys_id in ColonisationAI.annexable_ring3: supply_val = 400 if max_path_threat > 0.5 * mil_ship_rating: if max_path_threat < 3 * mil_ship_rating: supply_val *= 0.5 else: supply_val *= 0.2 threat_factor = min(1, 0.2*MilitaryAI.get_tot_mil_rating()/(sys_total_threat+0.001))**2 # devalue invasions that would require too much military force 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 + 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 + 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 = pop_val + supply_val + bld_tally + tech_tally + enemy_val - cost_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' ' - troop score: %.2f\n' ' - projected troop cost: %.1f\n' ' - threat factor: %s\n' ' - planet detail: %s\n' ' - popval: %.1f\n' ' - supplyval: %.1f\n' ' - bldval: %s\n' ' - enemyval: %s') % (planet_score, planned_troops, troop_cost, threat_factor, detail, pop_val, supply_val, bld_tally, enemy_val) return [planet_score, planned_troops]
def evaluate_invasion_planet(planet_id, empire, secure_fleet_missions, verbose=True): """Return the invasion value (score, troops) of a planet.""" detail = [] building_values = {"BLD_IMPERIAL_PALACE": 1000, "BLD_CULTURE_ARCHIVES": 1000, "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, } # TODO: add more factors, as used for colonization universe = fo.getUniverse() empire_id = empire.empireID max_jumps = 8 planet = universe.getPlanet(planet_id) if planet is None: # TODO: exclude planets with stealth higher than empireDetection print "invasion AI couldn't access any info for planet id %d" % planet_id return [0, 0] sys_partial_vis_turn = universe.getVisibilityTurnsMap(planet.systemID, empire_id).get(fo.visibility.partial, -9999) planet_partial_vis_turn = universe.getVisibilityTurnsMap(planet_id, empire_id).get(fo.visibility.partial, -9999) if planet_partial_vis_turn < sys_partial_vis_turn: print "invasion AI couldn't get current info on planet id %d (was stealthed at last sighting)" % planet_id # TODO: track detection strength, order new scouting when it goes up return [0, 0] # last time we had partial vis of the system, the planet was stealthed to us species_name = planet.speciesName species = fo.getSpecies(species_name) if not species: # 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], EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION, None, empire, detail) pop_val = max(0.75*planet_eval.get(planet_id, [0])[0], ColonisationAI.evaluate_planet(planet_id, EnumsAI.AIFleetMissionType.FLEET_MISSION_OUTPOST, None, empire, detail)) else: pop_val = ColonisationAI.evaluate_planet(planet_id, EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION, species_name, empire, detail) bld_tally = 0 for bldType in [universe.getObject(bldg).buildingTypeName for bldg in planet.buildingIDs]: bval = building_values.get(bldType, 50) bld_tally += bval detail.append("%s: %d" % (bldType, bval)) p_sys_id = planet.systemID capitol_id = PlanetUtilsAI.get_capital() least_jumps_path = [] clear_path = True if capitol_id: homeworld = universe.getPlanet(capitol_id) if homeworld: home_system_id = homeworld.systemID eval_system_id = planet.systemID if (home_system_id != -1) and (eval_system_id != -1): least_jumps_path = list(universe.leastJumpsPath(home_system_id, eval_system_id, empire_id)) max_jumps = len(least_jumps_path) system_status = foAI.foAIstate.systemStatus.get(p_sys_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) 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(p_sys_id) secure_targets = [p_sys_id] + list(this_system.planetIDs) system_secured = False for mission in secure_fleet_missions: if system_secured: break secure_fleet_id = mission.target_id s_fleet = universe.getFleet(secure_fleet_id) if not s_fleet or s_fleet.systemID != p_sys_id: continue for ai_target in mission.get_targets(EnumsAI.AIFleetMissionType.FLEET_MISSION_SECURE): target_obj = ai_target.target_obj 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 %d --- maxShields %.1f -- sysFleetThreat %.1f -- sysMonsterThreat %.1f" % ( planet.name, planet_id, planet.currentMeterValue(fo.meterType.maxShield), system_fleet_treat, system_monster_threat) supply_val = 0 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)) if p_sys_id in ColonisationAI.annexable_system_ids: # TODO: extend to rings supply_val = 100 elif p_sys_id in ColonisationAI.annexable_ring1: supply_val = 200 elif p_sys_id in ColonisationAI.annexable_ring2: supply_val = 300 elif p_sys_id in ColonisationAI.annexable_ring3: supply_val = 400 if max_path_threat > 0.5 * mil_ship_rating: if max_path_threat < 3 * mil_ship_rating: supply_val *= 0.5 else: supply_val *= 0.2 threat_factor = min(1, 0.2*MilitaryAI.totMilRating/(sys_total_threat+0.001))**2 # devalue invasions that would require too much military force build_time = 4 planned_troops = troops if system_secured else min(troops+max_jumps+build_time, max_troops) if not tech_is_complete("SHP_ORG_HULL"): troop_cost = math.ceil(planned_troops/6.0) * (40*(1+foAI.foAIstate.shipCount * AIDependencies.SHIP_UPKEEP)) else: troop_cost = math.ceil(planned_troops/6.0) * (20*(1+foAI.foAIstate.shipCount * AIDependencies.SHIP_UPKEEP)) planet_score = retaliation_risk_factor(planet.owner) * threat_factor * max(0, pop_val+supply_val+bld_tally+enemy_val-0.8*troop_cost) if clear_path: planet_score *= 1.5 invasion_score = [planet_score, planned_troops] print invasion_score, "projected Troop Cost:", troop_cost, ", threatFactor: ", threat_factor, ", planet detail ", detail, "popval, supplyval, bldval, enemyval", pop_val, supply_val, bld_tally, enemy_val return invasion_score
def survey_universe(): survey_timer.start("Categorizing Visible Planets") universe = fo.getUniverse() empire_id = fo.empireID() current_turn = fo.currentTurn() # set up / reset various variables; the 'if' is purely for code folding convenience if True: AIstate.empireStars.clear() empire_metabolisms.clear() active_growth_specials.clear() # var setup done aistate = get_aistate() for sys_id in universe.systemIDs: system = universe.getSystem(sys_id) if not system: continue local_ast = False local_gg = False empire_has_qualifying_planet = False if sys_id in AIstate.colonyTargetedSystemIDs: empire_has_qualifying_planet = True for pid in system.planetIDs: planet = universe.getPlanet(pid) if not planet: continue if pid in aistate.colonisablePlanetIDs: empire_has_qualifying_planet = True if planet.size == fo.planetSize.asteroids: local_ast = True elif planet.size == fo.planetSize.gasGiant: local_gg = True spec_name = planet.speciesName this_spec = fo.getSpecies(spec_name) owner_id = planet.owner planet_population = planet.currentMeterValue( fo.meterType.population) buildings_here = [ universe.getBuilding(bldg).buildingTypeName for bldg in planet.buildingIDs ] weapons_grade = "WEAPONS_0.0" if owner_id == empire_id: if planet_population > 0.0 and this_spec: empire_has_qualifying_planet = True for metab in [ tag for tag in this_spec.tags if tag in AIDependencies.metabolismBoostMap ]: empire_metabolisms[metab] = empire_metabolisms.get( metab, 0.0) + planet.habitableSize if this_spec.canProduceShips: pilot_val = rate_piloting_tag(spec_name) if spec_name == "SP_ACIREMA": pilot_val += 1 weapons_grade = "WEAPONS_%.1f" % pilot_val set_pilot_rating_for_planet(pid, pilot_val) yard_here = [] if "BLD_SHIPYARD_BASE" in buildings_here: set_ship_builders(spec_name, pid) yard_here = [pid] if this_spec.canColonize and planet.currentMeterValue( fo.meterType.targetPopulation) >= 3: set_colony_builders(spec_name, yard_here) set_building_locations(weapons_grade, buildings_here, pid) for special in planet.specials: if special_is_nest(special): set_have_nest() if special in AIDependencies.metabolismBoosts: set_growth_special(special, pid) if planet.focus == FocusType.FOCUS_GROWTH: active_growth_specials.setdefault(special, []).append(pid) elif owner_id != -1: if get_partial_visibility_turn( pid ) >= current_turn - 1: # only interested in immediately recent data aistate.misc.setdefault("enemies_sighted", {}).setdefault(current_turn, []).append(pid) if empire_has_qualifying_planet: if local_ast: set_have_asteroids() elif local_gg: set_have_gas_giant() if sys_id in get_owned_planets(): AIstate.empireStars.setdefault(system.starType, []).append(sys_id) sys_status = aistate.systemStatus.setdefault(sys_id, {}) if sys_status.get("fleetThreat", 0) > 0: set_colonies_is_under_attack() if sys_status.get("neighborThreat", 0) > 0: set_colonies_is_under_treat() survey_universe_lock.unlock() survey_timer.stop() # lock must be released before this, since it uses the locked functions _print_empire_species_roster()
def _calculate_planet_colonization_rating( planet_id: PlanetId, mission_type: MissionType, species_name: SpeciesName, detail: list, empire_research_list: Sequence, ) -> float: empire = fo.getEmpire() retval = 0 character = get_aistate().character discount_multiplier = character.preferred_discount_multiplier([30.0, 40.0]) species = fo.getSpecies(species_name) species_foci = [] and species and list(species.foci) tag_list = list(species.tags) if species else [] pilot_val = pilot_rating = 0 if species and species.canProduceShips: pilot_val = pilot_rating = rate_piloting_tag(species_name) if pilot_val > best_pilot_rating(): pilot_val *= 2 if pilot_val > 2: retval += discount_multiplier * 5 * pilot_val detail.append("Pilot Val %.1f" % (discount_multiplier * 5 * pilot_val)) if empire.productionPoints < 100: backup_factor = 0.0 else: backup_factor = min(1.0, (empire.productionPoints / 200.0)**2) universe = fo.getUniverse() capital_id = PlanetUtilsAI.get_capital() homeworld = universe.getPlanet(capital_id) planet = universe.getPlanet(planet_id) prospective_invasion_targets = [ pid for pid, pscore, trp in AIstate.invasionTargets[:PriorityAI.allotted_invasion_targets()] if pscore > InvasionAI.MIN_INVASION_SCORE ] if species_name != planet.speciesName and planet.speciesName and mission_type != MissionType.INVASION: return 0 this_sysid = planet.systemID if homeworld: home_system_id = homeworld.systemID eval_system_id = this_sysid if home_system_id != INVALID_ID and eval_system_id != INVALID_ID: least_jumps = universe.jumpDistance(home_system_id, eval_system_id) if least_jumps == -1: # indicates no known path return 0.0 if planet is None: vis_map = universe.getVisibilityTurnsMap(planet_id, empire.empireID) debug("Planet %d object not available; visMap: %s" % (planet_id, vis_map)) return 0 # only count existing presence if not target planet # TODO: consider neighboring sytems for smaller contribution, and bigger contributions for # local colonies versus local outposts locally_owned_planets = [ lpid for lpid in get_owned_planets_in_system(this_sysid) if lpid != planet_id ] planets_with_species = get_inhabited_planets() locally_owned_pop_ctrs = [ lpid for lpid in locally_owned_planets if lpid in planets_with_species ] # triple count pop_ctrs existing_presence = len( locally_owned_planets) + 2 * len(locally_owned_pop_ctrs) system = universe.getSystem(this_sysid) sys_supply = get_system_supply(this_sysid) planet_supply = AIDependencies.supply_by_size.get(planet.size, 0) bld_types = set( universe.getBuilding(bldg).buildingTypeName for bldg in planet.buildingIDs).intersection( AIDependencies.building_supply) planet_supply += sum( AIDependencies.building_supply[bld_type].get(int(psize), 0) for psize in [-1, planet.size] for bld_type in bld_types) supply_specials = set(planet.specials).union(system.specials).intersection( AIDependencies.SUPPLY_MOD_SPECIALS) planet_supply += sum( AIDependencies.SUPPLY_MOD_SPECIALS[_special].get(int(psize), 0) for _special in supply_specials for psize in [-1, planet.size]) ind_tag_mod = AIDependencies.SPECIES_INDUSTRY_MODIFIER.get( get_species_tag_grade(species_name, Tags.INDUSTRY), 1.0) res_tag_mod = AIDependencies.SPECIES_RESEARCH_MODIFIER.get( get_species_tag_grade(species_name, Tags.RESEARCH), 1.0) if species: supply_tag_mod = AIDependencies.SPECIES_SUPPLY_MODIFIER.get( get_species_tag_grade(species_name, Tags.SUPPLY), 1) else: supply_tag_mod = 0 # determine the potential supply provided by owning this planet, and if the planet is currently populated by # the evaluated species, then save this supply value in a cache. # The system supply value can be negative (indicates the respective number of starlane jumps to the closest supplied # system). So if this total planet supply value is non-negative, then the planet would be supply connected (to at # least a portion of the existing empire) if the planet becomes owned by the AI. planet_supply += supply_tag_mod planet_supply = max(planet_supply, 0) # planets can't have negative supply if planet.speciesName == species_name: update_planet_supply(planet_id, planet_supply + sys_supply) threat_factor = _determine_colony_threat_factor(planet_id, species_name, existing_presence) sys_partial_vis_turn = get_partial_visibility_turn(this_sysid) planet_partial_vis_turn = get_partial_visibility_turn(planet_id) if planet_partial_vis_turn < sys_partial_vis_turn: # last time we had partial vis of the system, the planet was stealthed to us # print "Colonization AI couldn't get current info on planet id %d (was stealthed at last sighting)" % planet_id return 0 # TODO: track detection strength, order new scouting when it goes up star_bonus = 0 colony_star_bonus = 0 research_bonus = 0 growth_val = 0 fixed_ind = 0 fixed_res = 0 if system: already_got_this_one = this_sysid in get_owned_planets() # TODO: Should probably consider pilot rating also for Phototropic species if "PHOTOTROPHIC" not in tag_list and pilot_rating >= best_pilot_rating( ): if system.starType == fo.starType.red and tech_is_complete( "LRN_STELLAR_TOMOGRAPHY"): star_bonus += 40 * discount_multiplier # can be used for artif'l black hole and solar hull detail.append( "Red Star for Art Black Hole for solar hull %.1f" % (40 * discount_multiplier)) elif system.starType == fo.starType.blackHole and tech_is_complete( "SHP_FRC_ENRG_COMP"): star_bonus += 100 * discount_multiplier # can be used for solar hull detail.append("Black Hole for solar hull %.1f" % (100 * discount_multiplier)) if tech_is_complete("PRO_SOL_ORB_GEN" ) or "PRO_SOL_ORB_GEN" in empire_research_list[:5]: if system.starType in [fo.starType.blue, fo.starType.white]: if not has_claimed_star(fo.starType.blue, fo.starType.white): star_bonus += 20 * discount_multiplier detail.append("PRO_SOL_ORB_GEN BW %.1f" % (20 * discount_multiplier)) elif not already_got_this_one: # still has extra value as an alternate location for solar generators star_bonus += 10 * discount_multiplier * backup_factor detail.append("PRO_SOL_ORB_GEN BW Backup Location %.1f" % (10 * discount_multiplier * backup_factor)) elif fo.currentTurn() > 100: # lock up this whole system pass # starBonus += 5 # TODO: how much? # detail.append("PRO_SOL_ORB_GEN BW LockingDownSystem %.1f"%5) if system.starType in [fo.starType.yellow, fo.starType.orange]: if not has_claimed_star(fo.starType.blue, fo.starType.white, fo.starType.yellow, fo.starType.orange): star_bonus += 10 * discount_multiplier detail.append("PRO_SOL_ORB_GEN YO %.1f" % (10 * discount_multiplier)) else: pass # starBonus +=2 # still has extra value as an alternate location for solar generators # detail.append("PRO_SOL_ORB_GEN YO Backup %.1f" % 2) if system.starType in [fo.starType.blackHole ] and fo.currentTurn() > 100: if not already_got_this_one: # whether have tech yet or not, assign some base value star_bonus += 10 * discount_multiplier * backup_factor detail.append("Black Hole %.1f" % (10 * discount_multiplier * backup_factor)) else: star_bonus += 5 * discount_multiplier * backup_factor detail.append("Black Hole Backup %.1f" % (5 * discount_multiplier * backup_factor)) if tech_is_complete(AIDependencies.PRO_SOL_ORB_GEN ): # start valuing as soon as PRO_SOL_ORB_GEN done if system.starType == fo.starType.blackHole: # pretty rare planets, good for generator this_val = 0.5 * max(population_with_industry_focus(), 20) * discount_multiplier if not has_claimed_star(fo.starType.blackHole): star_bonus += this_val detail.append("PRO_SINGULAR_GEN %.1f" % this_val) elif not is_system_star_claimed(system): # still has extra value as an alternate location for generators & for blocking enemies generators star_bonus += this_val * backup_factor detail.append("PRO_SINGULAR_GEN Backup %.1f" % (this_val * backup_factor)) elif system.starType == fo.starType.red and not has_claimed_star( fo.starType.blackHole): rfactor = (1.0 + count_claimed_stars(fo.starType.red))**-2 star_bonus += 40 * discount_multiplier * backup_factor * rfactor # can be used for artif'l black hole detail.append( "Red Star for Art Black Hole %.1f" % (40 * discount_multiplier * backup_factor * rfactor)) if tech_is_complete( "PRO_NEUTRONIUM_EXTRACTION" ) or "PRO_NEUTRONIUM_EXTRACTION" in empire_research_list[:8]: if system.starType in [fo.starType.neutron]: if not has_claimed_star(fo.starType.neutron): star_bonus += 80 * discount_multiplier # pretty rare planets, good for armor detail.append("PRO_NEUTRONIUM_EXTRACTION %.1f" % (80 * discount_multiplier)) else: # still has extra value as an alternate location for generators & for bnlocking enemies generators star_bonus += 20 * discount_multiplier * backup_factor detail.append("PRO_NEUTRONIUM_EXTRACTION Backup %.1f" % (20 * discount_multiplier * backup_factor)) if tech_is_complete( "SHP_ENRG_BOUND_MAN" ) or "SHP_ENRG_BOUND_MAN" in empire_research_list[:6]: # TODO: base this on pilot val, and also consider red stars if system.starType in [fo.starType.blackHole, fo.starType.blue]: init_val = 100 * discount_multiplier * (pilot_val or 1) if not has_claimed_star(fo.starType.blackHole, fo.starType.blue): colony_star_bonus += init_val # pretty rare planets, good for energy shipyards detail.append("SHP_ENRG_BOUND_MAN %.1f" % init_val) elif not is_system_star_claimed(system): # still has extra value as an alternate location for energy shipyard colony_star_bonus += 0.5 * init_val * backup_factor detail.append("SHP_ENRG_BOUND_MAN Backup %.1f" % (0.5 * init_val * backup_factor)) retval += star_bonus planet_specials = list(planet.specials) if "ECCENTRIC_ORBIT_SPECIAL" in planet.specials: fixed_res += discount_multiplier * 6 detail.append("ECCENTRIC_ORBIT_SPECIAL %.1f" % (discount_multiplier * 6)) if mission_type == MissionType.OUTPOST or ( mission_type == MissionType.INVASION and not species_name): if "ANCIENT_RUINS_SPECIAL" in planet.specials: # TODO: add value for depleted ancient ruins retval += discount_multiplier * 30 detail.append("Undepleted Ruins %.1f" % discount_multiplier * 30) for special in planet_specials: if "_NEST_" in special: nest_val = get_nest_rating( special, 5.0 ) * discount_multiplier # get an outpost on the nest quick retval += nest_val detail.append("%s %.1f" % (special, nest_val)) elif special == "FORTRESS_SPECIAL": fort_val = 10 * discount_multiplier retval += fort_val detail.append("%s %.1f" % (special, fort_val)) elif special == "HONEYCOMB_SPECIAL": honey_val = 0.3 * (AIDependencies.HONEYCOMB_IND_MULTIPLIER * AIDependencies.INDUSTRY_PER_POP * population_with_industry_focus() * discount_multiplier) retval += honey_val detail.append("%s %.1f" % (special, honey_val)) if planet.size == fo.planetSize.asteroids: ast_val = 0 if system: for pid in system.planetIDs: other_planet = universe.getPlanet(pid) if other_planet.size == fo.planetSize.asteroids: if pid == planet_id: continue elif pid < planet_id and planet.unowned: ast_val = 0 break elif other_planet.speciesName: if other_planet.owner == empire.empireID: ownership_factor = 1.0 elif pid in prospective_invasion_targets: ownership_factor = character.secondary_valuation_factor_for_invasion_targets( ) else: ownership_factor = 0.0 ast_val += ownership_factor * _base_asteroid_mining_val( ) * discount_multiplier retval += ast_val if ast_val > 0: detail.append("AsteroidMining %.1f" % ast_val) ast_val = 0 if tech_is_complete("SHP_ASTEROID_HULLS"): per_ast = 20 elif tech_is_complete("CON_ORBITAL_CON"): per_ast = 5 else: per_ast = 0.1 if system: for pid in system.planetIDs: other_planet = universe.getPlanet(pid) if other_planet.size == fo.planetSize.asteroids: if pid == planet_id: continue elif pid < planet_id and planet.unowned: ast_val = 0 break elif other_planet.speciesName: other_species = fo.getSpecies(other_planet.speciesName) if other_species and other_species.canProduceShips: if other_planet.owner == empire.empireID: ownership_factor = 1.0 elif pid in prospective_invasion_targets: ownership_factor = character.secondary_valuation_factor_for_invasion_targets( ) else: ownership_factor = 0.0 ast_val += ownership_factor * per_ast * discount_multiplier retval += ast_val if ast_val > 0: detail.append("AsteroidShipBuilding %.1f" % ast_val) # We will assume that if any GG in the system is populated, they all will wind up populated; cannot then hope # to build a GGG on a non-populated GG populated_gg_factor = 1.0 per_gg = 0 if planet.size == fo.planetSize.gasGiant: # TODO: Given current industry calc approach, consider bringing this max val down to actual max val of 10 if tech_is_complete("PRO_ORBITAL_GEN"): per_gg = 20 elif tech_is_complete("CON_ORBITAL_CON"): per_gg = 10 if species_name: populated_gg_factor = 0.5 else: per_gg = 5 if system: gg_list = [] orb_gen_val = 0 gg_detail = [] for pid in system.planetIDs: other_planet = universe.getPlanet(pid) if other_planet.size == fo.planetSize.gasGiant: gg_list.append(pid) if other_planet.speciesName: populated_gg_factor = 0.5 if (pid != planet_id and other_planet.owner == empire.empireID and FocusType.FOCUS_INDUSTRY in list(other_planet.availableFoci) + [other_planet.focus]): orb_gen_val += per_gg * discount_multiplier # Note, this reported value may not take into account a later adjustment from a populated gg gg_detail.append("GGG for %s %.1f" % (other_planet.name, discount_multiplier * per_gg * populated_gg_factor)) if planet_id in sorted(gg_list)[:1]: retval += orb_gen_val * populated_gg_factor detail.extend(gg_detail) else: detail.append("Won't GGG") if existing_presence: detail.append("preexisting system colony") retval = (retval + existing_presence * _get_defense_value(species_name)) * 1.5 # Fixme - sys_supply is always <= 0 leading to incorrect supply bonus score supply_val = 0 if sys_supply < 0: if sys_supply + planet_supply >= 0: supply_val += 30 * (planet_supply - max(-3, sys_supply)) else: retval += 30 * (planet_supply + sys_supply) # a penalty elif planet_supply > sys_supply and ( sys_supply < 2): # TODO: check min neighbor supply supply_val += 25 * (planet_supply - sys_supply) detail.append("sys_supply: %d, planet_supply: %d, supply_val: %.0f" % (sys_supply, planet_supply, supply_val)) retval += supply_val if threat_factor < 1.0: threat_factor = _revise_threat_factor(threat_factor, retval, this_sysid, MINIMUM_COLONY_SCORE) retval *= threat_factor detail.append("threat reducing value by %3d %%" % (100 * (1 - threat_factor))) return int(retval) else: # colonization mission if not species: return 0 supply_val = 0 if "ANCIENT_RUINS_SPECIAL" in planet.specials: retval += discount_multiplier * 50 detail.append("Undepleted Ruins %.1f" % discount_multiplier * 50) if "HONEYCOMB_SPECIAL" in planet.specials: honey_val = (AIDependencies.HONEYCOMB_IND_MULTIPLIER * AIDependencies.INDUSTRY_PER_POP * population_with_industry_focus() * discount_multiplier) if FocusType.FOCUS_INDUSTRY not in species_foci: honey_val *= -0.3 # discourage settlement by colonizers not able to use Industry Focus retval += honey_val detail.append("%s %.1f" % ("HONEYCOMB_SPECIAL", honey_val)) # Fixme - sys_supply is always <= 0 leading to incorrect supply bonus score if sys_supply <= 0: if sys_supply + planet_supply >= 0: supply_val = 40 * (planet_supply - max(-3, sys_supply)) else: supply_val = 200 * (planet_supply + sys_supply) # a penalty if species_name == "SP_SLY": # Sly are essentially stuck with lousy supply, so don't penalize for that supply_val = 0 elif planet_supply > sys_supply == 1: # TODO: check min neighbor supply supply_val = 20 * (planet_supply - sys_supply) detail.append("sys_supply: %d, planet_supply: %d, supply_val: %.0f" % (sys_supply, planet_supply, supply_val)) # if AITags != "": # print "Species %s has AITags %s"%(specName, AITags) retval += fixed_res retval += colony_star_bonus asteroid_bonus = 0 gas_giant_bonus = 0 flat_industry = 0 mining_bonus = 0 per_ggg = 10 asteroid_factor = 0.0 gg_factor = 0.0 ast_shipyard_name = "" if system and FocusType.FOCUS_INDUSTRY in species.foci: for pid in system.planetIDs: if pid == planet_id: continue p2 = universe.getPlanet(pid) if p2: if p2.size == fo.planetSize.asteroids: this_factor = 0.0 if p2.owner == empire.empireID: this_factor = 1.0 elif p2.unowned: this_factor = 0.5 elif pid in prospective_invasion_targets: this_factor = character.secondary_valuation_factor_for_invasion_targets( ) if this_factor > asteroid_factor: asteroid_factor = this_factor ast_shipyard_name = p2.name if p2.size == fo.planetSize.gasGiant: if p2.owner == empire.empireID: gg_factor = max(gg_factor, 1.0) elif p2.unowned: gg_factor = max(gg_factor, 0.5) elif pid in prospective_invasion_targets: gg_factor = max( gg_factor, character. secondary_valuation_factor_for_invasion_targets( )) if asteroid_factor > 0.0: if tech_is_complete( "PRO_MICROGRAV_MAN" ) or "PRO_MICROGRAV_MAN" in empire_research_list[:10]: flat_industry += 2 * asteroid_factor # will go into detailed industry projection detail.append("Asteroid mining ~ %.1f" % (5 * asteroid_factor * discount_multiplier)) if tech_is_complete( "SHP_ASTEROID_HULLS" ) or "SHP_ASTEROID_HULLS" in empire_research_list[:11]: if species and species.canProduceShips: asteroid_bonus = 30 * discount_multiplier * pilot_val detail.append("Asteroid ShipBuilding from %s %.1f" % (ast_shipyard_name, discount_multiplier * 30 * pilot_val)) if gg_factor > 0.0: if tech_is_complete( "PRO_ORBITAL_GEN" ) or "PRO_ORBITAL_GEN" in empire_research_list[:5]: flat_industry += per_ggg * gg_factor # will go into detailed industry projection detail.append("GGG ~ %.1f" % (per_ggg * gg_factor * discount_multiplier)) # calculate the maximum population of the species on that planet. if planet.speciesName not in AIDependencies.SPECIES_FIXED_POPULATION: max_pop_size = calc_max_pop(planet, species, detail) else: max_pop_size = AIDependencies.SPECIES_FIXED_POPULATION[ planet.speciesName] detail.append("Fixed max population of %.2f" % max_pop_size) if max_pop_size <= 0: detail.append( "Non-positive population projection for species '%s', so no colonization value" % (species and species.name)) return 0 for special in [ "MINERALS_SPECIAL", "CRYSTALS_SPECIAL", "ELERIUM_SPECIAL" ]: if special in planet_specials: mining_bonus += 1 has_blackhole = has_claimed_star(fo.starType.blackHole) ind_tech_map_flat = AIDependencies.INDUSTRY_EFFECTS_FLAT_NOT_MODIFIED_BY_SPECIES ind_tech_map_before_species_mod = AIDependencies.INDUSTRY_EFFECTS_PER_POP_MODIFIED_BY_SPECIES ind_tech_map_after_species_mod = AIDependencies.INDUSTRY_EFFECTS_PER_POP_NOT_MODIFIED_BY_SPECIES ind_mult = 1 for tech in ind_tech_map_before_species_mod: if tech_is_complete(tech) and ( tech != AIDependencies.PRO_SINGULAR_GEN or has_blackhole): ind_mult += ind_tech_map_before_species_mod[tech] ind_mult = ind_mult * max( ind_tag_mod, 0.5 * (ind_tag_mod + res_tag_mod)) # TODO: report an actual calc for research value for tech in ind_tech_map_after_species_mod: if tech_is_complete(tech) and ( tech != AIDependencies.PRO_SINGULAR_GEN or has_blackhole): ind_mult += ind_tech_map_after_species_mod[tech] max_ind_factor = 0 for tech in ind_tech_map_flat: if tech_is_complete(tech): fixed_ind += discount_multiplier * ind_tech_map_flat[tech] if FocusType.FOCUS_INDUSTRY in species.foci: if "TIDAL_LOCK_SPECIAL" in planet.specials: ind_mult += 1 max_ind_factor += AIDependencies.INDUSTRY_PER_POP * mining_bonus max_ind_factor += AIDependencies.INDUSTRY_PER_POP * ind_mult cur_pop = 1.0 # assume an initial colonization value if planet.speciesName != "": cur_pop = planet.currentMeterValue(fo.meterType.population) elif tech_is_complete("GRO_LIFECYCLE_MAN"): cur_pop = 3.0 cur_industry = planet.currentMeterValue(fo.meterType.industry) ind_val = _project_ind_val(cur_pop, max_pop_size, cur_industry, max_ind_factor, flat_industry, discount_multiplier) detail.append("ind_val %.1f" % ind_val) # used to give preference to closest worlds for special in [ spec for spec in planet_specials if spec in AIDependencies.metabolismBoosts ]: # TODO: also consider potential future benefit re currently unpopulated planets gbonus = (discount_multiplier * AIDependencies.INDUSTRY_PER_POP * ind_mult * empire_metabolisms.get( AIDependencies.metabolismBoosts[special], 0) ) # due to growth applicability to other planets growth_val += gbonus detail.append("Bonus for %s: %.1f" % (special, gbonus)) if FocusType.FOCUS_RESEARCH in species.foci: research_bonus += discount_multiplier * 2 * AIDependencies.RESEARCH_PER_POP * max_pop_size if "ANCIENT_RUINS_SPECIAL" in planet.specials or "ANCIENT_RUINS_DEPLETED_SPECIAL" in planet.specials: research_bonus += discount_multiplier * 2 * AIDependencies.RESEARCH_PER_POP * max_pop_size * 5 detail.append("Ruins Research") if "TEMPORAL_ANOMALY_SPECIAL" in planet.specials: research_bonus += discount_multiplier * 2 * AIDependencies.RESEARCH_PER_POP * max_pop_size * 25 detail.append("Temporal Anomaly Research") if AIDependencies.COMPUTRONIUM_SPECIAL in planet.specials: comp_bonus = (0.5 * AIDependencies.TECH_COST_MULTIPLIER * AIDependencies.RESEARCH_PER_POP * AIDependencies.COMPUTRONIUM_RES_MULTIPLIER * population_with_research_focus() * discount_multiplier) if have_computronium(): comp_bonus *= backup_factor research_bonus += comp_bonus detail.append(AIDependencies.COMPUTRONIUM_SPECIAL) retval += (max(ind_val + asteroid_bonus + gas_giant_bonus, research_bonus, growth_val) + fixed_ind + fixed_res + supply_val) if existing_presence: detail.append("preexisting system colony") retval = (retval + existing_presence * _get_defense_value(species_name)) * 2 if threat_factor < 1.0: threat_factor = _revise_threat_factor(threat_factor, retval, this_sysid, MINIMUM_COLONY_SCORE) retval *= threat_factor detail.append("threat reducing value by %3d %%" % (100 * (1 - threat_factor))) return retval
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] color = empire.colour part_meters = ship.partMeters meter = planet.getMeter(fo.meterType.population) inspect( fo, instances=[ meter, part_meters, color, 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.acceptPeaceProposal), fleets_int_vector, part_type, prod_queue, prod_queue.allocatedPP, prod_queue[0], research_queue, research_queue[0], empire.getSitRep(0), universe.getBuilding(building) ], classes_to_ignore=( 'IntSet', 'StringSet', 'IntIntMap', 'ShipSlotVec', 'VisibilityIntMap', 'IntDblMap', 'IntBoolMap', 'ItemSpecVec', 'PairIntInt_IntMap', 'IntSetSet', 'StringVec', 'IntPairVec', 'IntFltMap', 'MeterTypeStringPair', 'MeterTypeMeterMap', 'universeObject', # this item cannot be get from generate orders 'diplomaticStatusUpdate', ), path='AI' ) exit(1) # exit game to main menu no need to play anymore.
def getColonyFleets(): "get colony fleets" allColonyFleetIDs = FleetUtilsAI.getEmpireFleetIDsByRole(AIFleetMissionType.FLEET_MISSION_COLONISATION) AIstate.colonyFleetIDs = FleetUtilsAI.extractFleetIDsWithoutMissionTypes(allColonyFleetIDs) # get suppliable systems and planets universe = fo.getUniverse() empire = fo.getEmpire() empireID = empire.empireID capitalID = empire.capitalID homeworld = universe.getPlanet(capitalID) speciesName = homeworld.speciesName species = fo.getSpecies(speciesName) fleetSupplyableSystemIDs = empire.fleetSupplyableSystemIDs fleetSupplyablePlanetIDs = PlanetUtilsAI.getPlanetsInSystemsIDs(fleetSupplyableSystemIDs) print "" print " fleetSupplyableSystemIDs: " + str(list(fleetSupplyableSystemIDs)) print " fleetSupplyablePlanetIDs: " + str(fleetSupplyablePlanetIDs) print "" # get outpost and colonization planets exploredSystemIDs = empire.exploredSystemIDs print "Explored SystemIDs: " + str(list(exploredSystemIDs)) exploredPlanetIDs = PlanetUtilsAI.getPlanetsInSystemsIDs(exploredSystemIDs) print "Explored PlanetIDs: " + str(exploredPlanetIDs) print "" allOwnedPlanetIDs = PlanetUtilsAI.getAllOwnedPlanetIDs(exploredPlanetIDs) print "All Owned and Populated PlanetIDs: " + str(allOwnedPlanetIDs) empireOwnedPlanetIDs = PlanetUtilsAI.getOwnedPlanetsByEmpire(universe.planetIDs, empireID) print "Empire Owned PlanetIDs: " + str(empireOwnedPlanetIDs) unpopulatedPlanetIDs = list(set(exploredPlanetIDs) - set(allOwnedPlanetIDs)) print "Unpopulated PlanetIDs: " + str(unpopulatedPlanetIDs) print "" colonyTargetedPlanetIDs = getColonyTargetedPlanetIDs( universe.planetIDs, AIFleetMissionType.FLEET_MISSION_COLONISATION, empireID ) print "Colony Targeted PlanetIDs: " + str(colonyTargetedPlanetIDs) colonyFleetIDs = FleetUtilsAI.getEmpireFleetIDsByRole(AIFleetMissionType.FLEET_MISSION_COLONISATION) if not colonyFleetIDs: print "Available Colony Fleets: 0" else: print "Colony FleetIDs: " + str( FleetUtilsAI.getEmpireFleetIDsByRole(AIFleetMissionType.FLEET_MISSION_COLONISATION) ) numColonyFleets = len(FleetUtilsAI.extractFleetIDsWithoutMissionTypes(colonyFleetIDs)) print "Colony Fleets Without Missions: " + str(numColonyFleets) print "" outpostTargetedPlanetIDs = getOutpostTargetedPlanetIDs( universe.planetIDs, AIFleetMissionType.FLEET_MISSION_OUTPOST, empireID ) print "Outpost Targeted PlanetIDs: " + str(outpostTargetedPlanetIDs) outpostFleetIDs = FleetUtilsAI.getEmpireFleetIDsByRole(AIFleetMissionType.FLEET_MISSION_OUTPOST) if not outpostFleetIDs: print "Available Outpost Fleets: 0" else: print "Outpost FleetIDs: " + str( FleetUtilsAI.getEmpireFleetIDsByRole(AIFleetMissionType.FLEET_MISSION_OUTPOST) ) numOutpostFleets = len(FleetUtilsAI.extractFleetIDsWithoutMissionTypes(outpostFleetIDs)) print "Outpost Fleets Without Missions: " + str(numOutpostFleets) evaluatedColonyPlanetIDs = list(set(unpopulatedPlanetIDs) - set(colonyTargetedPlanetIDs)) # print "Evaluated Colony PlanetIDs: " + str(evaluatedColonyPlanetIDs) evaluatedOutpostPlanetIDs = list(set(unpopulatedPlanetIDs) - set(outpostTargetedPlanetIDs)) # print "Evaluated Outpost PlanetIDs: " + str(evaluatedOutpostPlanetIDs) evaluatedColonyPlanets = assignColonisationValues( evaluatedColonyPlanetIDs, AIFleetMissionType.FLEET_MISSION_COLONISATION, fleetSupplyablePlanetIDs, species, empire, ) removeLowValuePlanets(evaluatedColonyPlanets) sortedPlanets = evaluatedColonyPlanets.items() sortedPlanets.sort(lambda x, y: cmp(x[1], y[1]), reverse=True) print "" print "Settleable Colony PlanetIDs:" 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) evaluatedOutpostPlanets = assignColonisationValues( evaluatedOutpostPlanetIDs, AIFleetMissionType.FLEET_MISSION_OUTPOST, fleetSupplyablePlanetIDs, species, empire ) removeLowValuePlanets(evaluatedOutpostPlanets) sortedOutposts = evaluatedOutpostPlanets.items() sortedOutposts.sort(lambda x, y: cmp(x[1], y[1]), reverse=True) print "Settleable Outpost PlanetIDs:" for evaluationPair in sortedOutposts: print " ID|Score: " + str(evaluationPair) print "" # export outposts for other AI modules AIstate.colonisableOutpostIDs = sortedOutposts