Beispiel #1
0
def calculateResearchPriority():
    "calculates the AI empire's demand for research"

    universe = fo.getUniverse()
    empire = fo.getEmpire()
    empireID = empire.empireID
    gotAlgo = empire.getTechStatus("LRN_ALGO_ELEGANCE") == fo.techStatus.complete

    
    totalPP = empire.productionPoints
    totalRP = empire.resourceProduction(fo.resourceType.research)
    # get current industry production & Target
    ownedPlanetIDs = PlanetUtilsAI.getOwnedPlanetsByEmpire(universe.planetIDs, empireID)
    planets = map(universe.getPlanet,  ownedPlanetIDs)
    targetRP = sum( map( lambda x: x.currentMeterValue(fo.meterType.targetResearch),  planets) )

    if  (fo.currentTurn() < 20) or not gotAlgo:
        researchPriority = 60 # mid industry , high research at beginning of game to get easy gro tech and to get research booster Algotrithmic Elegance
    elif fo.currentTurn() < 30:
        researchPriority = 30 # mid industry , mid research 
    elif fo.currentTurn() < 40:
        researchPriority = 20 # high  industry , low research 
    else:
        researchPriority = 15 # high  industry , low research 


    print  ""
    print  "Research Production (current/target) : ( %.1f / %.1f )"%(totalRP,  targetRP)
    print  "Priority for Research: " + str(researchPriority)

    return researchPriority
Beispiel #2
0
def calculateIndustryPriority():
    "calculates the demand for industry"

    universe = fo.getUniverse()
    empire = fo.getEmpire()
    empireID = empire.empireID
    # get current industry production & Target
    industryProduction = empire.resourceProduction(fo.resourceType.industry)
    ownedPlanetIDs = PlanetUtilsAI.getOwnedPlanetsByEmpire(universe.planetIDs, empireID)
    planets = map(universe.getPlanet,  ownedPlanetIDs)
    targetPP = sum( map( lambda x: x.currentMeterValue(fo.meterType.targetIndustry),  planets) )

    if fo.currentTurn() < 20:
        industryPriority = 20 # mid industry , high research at beginning of game to get easy gro tech
    elif fo.currentTurn() < 30:
        industryPriority = 25 # mid industry , mid research 
    elif fo.currentTurn() < 40:
        industryPriority = 40 # high  industry , mid research 
    elif fo.currentTurn() < 50:
        industryPriority = 50 # high  industry , mid research 
    else:
        industryPriority = 60 # high  industry , low-mid research 


    # increase demand for industry industry production is low
    #industryPriority = 380 / (industryProduction + 0.001)

    print ""
    print "Industry Production (current/target) : ( %.1f / %.1f )  at turn %s"%(industryProduction,  targetPP,  fo.currentTurn())
    print "Priority for Industry: " + str(industryPriority)

    return industryPriority
Beispiel #3
0
 def __border_exploration_update(self):
     universe = fo.getUniverse()
     exploration_center = PlanetUtilsAI.get_capital_sys_id()
     # a bad state probably from an old savegame, or else empire has lost (or almost has)
     if exploration_center == INVALID_ID:
         exploration_center = self.__origin_home_system_id
     ExplorationAI.graph_flags.clear()
     if fo.currentTurn() < 50:
         print "-------------------------------------------------"
         print "Border Exploration Update (relative to %s)" % universe.getSystem(exploration_center)
         print "-------------------------------------------------"
     if self.visBorderSystemIDs == {INVALID_ID}:
         self.visBorderSystemIDs.clear()
         self.visBorderSystemIDs.add(exploration_center)
     for sys_id in list(self.visBorderSystemIDs):  # This set is modified during iteration.
         if fo.currentTurn() < 50:
             print "Considering border system %s" % universe.getSystem(sys_id)
         ExplorationAI.follow_vis_system_connections(sys_id, exploration_center)
     newly_explored = ExplorationAI.update_explored_systems()
     nametags = []
     for sys_id in newly_explored:
         newsys = universe.getSystem(sys_id)
         # an explored system *should* always be able to be gotten
         nametags.append("ID:%4d -- %-20s" % (sys_id, (newsys and newsys.name) or "name unknown"))
     if newly_explored:
         print "-------------------------------------------------"
         print "Newly explored systems:\n%s" % "\n".join(nametags)
         print "-------------------------------------------------"
Beispiel #4
0
def calculateMilitaryPriority():
    "calculates the demand for military ships by military targeted systems"
    global unmetThreat

    universe = fo.getUniverse()
    empire = fo.getEmpire()
    empireID = empire.empireID
    capitalID = PlanetUtilsAI.getCapital()
    if capitalID is not None and capitalID != -1:
        homeworld = universe.getPlanet(capitalID)
    else:
        return 0# no capitol (not even a capitol-in-the-making), means can't produce any ships
        
    have_mod_weaps = ( empire.getTechStatus("SHP_WEAPON_1_4") == fo.techStatus.complete or
                                   empire.getTechStatus("SHP_WEAPON_2_1") == fo.techStatus.complete or
                                   empire.getTechStatus("SHP_WEAPON_4_1") == fo.techStatus.complete )
        
    allottedInvasionTargets = 1+ int(fo.currentTurn()/25)
    targetPlanetIDs =  [pid for pid, pscore, trp in AIstate.invasionTargets[:allottedInvasionTargets] ] + [pid for pid,  pscore in foAI.foAIstate.colonisablePlanetIDs[:allottedColonyTargets]  ] + [pid for pid,  pscore in foAI.foAIstate.colonisableOutpostIDs[:allottedColonyTargets]  ]

    mySystems = set( AIstate.popCtrSystemIDs ).union( AIstate.outpostSystemIDs   )
    targetSystems = set( PlanetUtilsAI.getSystems(targetPlanetIDs)  )

    curShipRating = ProductionAI.curBestMilShipRating()
    cSRR = curShipRating**0.5

    unmetThreat = 0.0
    currentTurn=fo.currentTurn()
    shipsNeeded=0
    defenses_needed = 0
    for sysID in mySystems.union(targetSystems) :
        status=foAI.foAIstate.systemStatus.get( sysID,  {} )
        myRating = status.get('myFleetRating',  0)
        my_defenses = status.get('mydefenses',  {}).get('overall', 0)
        baseMonsterThreat = status.get('monsterThreat', 0)
        #scale monster threat so that in early - mid game big monsters don't over-drive military production
        if currentTurn>200:
            monsterThreat = baseMonsterThreat
        elif currentTurn>100:
            if baseMonsterThreat <2000:
                monsterThreat = baseMonsterThreat
            else:
                monsterThreat = 2000 + (currentTurn/100.0 - 1) *(baseMonsterThreat-2000)
        else:
            monsterThreat = 0
        if sysID in mySystems:
            threatRoot = status.get('fleetThreat', 0)**0.5 + 0.8*status.get('max_neighbor_threat', 0)**0.5 + 0.2*status.get('neighborThreat', 0)**0.5 + monsterThreat**0.5 + status.get('planetThreat', 0)**0.5
        else:
            threatRoot = status.get('fleetThreat', 0)**0.5  + monsterThreat**0.5 + status.get('planetThreat', 0)**0.5
        shipsNeeded += math.ceil(( max(0,   (threatRoot - (myRating**0.5 + my_defenses**0.5)))**2)/curShipRating)

    #militaryPriority = int( 40 + max(0,  75*unmetThreat / curShipRating) )
    militaryPriority = int( 40 + max(0,  75*shipsNeeded) )
    if not have_mod_weaps:
        militaryPriority /= 2
    #print "Calculating Military Priority:  40 + 75 * unmetThreat/curShipRating \n\t  Priority: %d    \t unmetThreat  %.0f        curShipRating: %.0f"%(militaryPriority,  unmetThreat,  curShipRating)
    print "Calculating Military Priority:  40 + 75 * shipsNeeded \n\t  Priority: %d   \t shipsNeeded %d   \t unmetThreat  %.0f        curShipRating: %.0f"%(militaryPriority, shipsNeeded,   unmetThreat,  curShipRating)
    return max( militaryPriority,  0)
Beispiel #5
0
    def log_war_declaration(self, initiating_empire_id, recipient_empire_id):
        """Keep a record of war declarations made or received by this empire."""

        # if war declaration is made on turn 1, don't hold it against them
        if fo.currentTurn() == 1:
            return
        war_declarations = self.diplomatic_logs.setdefault('war_declarations', {})
        log_index = (initiating_empire_id, recipient_empire_id)
        war_declarations.setdefault(log_index, []).append(fo.currentTurn())
Beispiel #6
0
def calculateMilitaryPriority():
    "calculates the demand for military ships by military targeted systems"

    universe = fo.getUniverse()
    empire = fo.getEmpire()
    empireID = empire.empireID
    capitalID = PlanetUtilsAI.getCapital()
    if capitalID:
        homeworld = universe.getPlanet(capitalID)
    else:
        return 0# no capitol (not even a capitol-in-the-making), means can't produce any ships
    allottedInvasionTargets = 1+ int(fo.currentTurn()/25)
    targetPlanetIDs =  [pid for pid, pscore, trp in AIstate.invasionTargets[:allottedInvasionTargets] ] + [pid for pid,  pscore in foAI.foAIstate.colonisablePlanetIDs[:allottedColonyTargets]  ] + [pid for pid,  pscore in foAI.foAIstate.colonisableOutpostIDs[:allottedColonyTargets]  ]
    
    mySystems = set( AIstate.popCtrSystemIDs ).union( AIstate.outpostSystemIDs   )
    targetSystems = set( PlanetUtilsAI.getSystems(targetPlanetIDs)  )
    
    curShipRating = ProductionAI.curBestMilShipRating()
    cSRR = curShipRating**0.5

    unmetThreat = 0.0
    currentTurn=fo.currentTurn()
    shipsNeeded=0
    for sysID in mySystems.union(targetSystems) :
        status=foAI.foAIstate.systemStatus.get( sysID,  {} )
        myAttack,  myHealth =0, 0
        for fid in status.get('myfleets', []) :
            rating= foAI.foAIstate.fleetStatus.get(fid,  {}).get('rating', {})
            myAttack += rating.get('attack', 0)
            myHealth += rating.get('health', 0)
        myRating = myAttack*myHealth
        baseMonsterThreat = status.get('monsterThreat', 0)
        if currentTurn>200:
            monsterThreat = baseMonsterThreat
        elif currentTurn>100:
            if baseMonsterThreat <2000:
                monsterThreat = baseMonsterThreat
            else:
                monsterThreat = 2000 + (currentTurn/100.0 - 1) *(baseMonsterThreat-2000)
        else:
            monsterThreat = 0
            
        threatRoot = status.get('fleetThreat', 0)**0.5 + status.get('planetThreat', 0)**0.5 + monsterThreat**0.5
        if sysID in mySystems:
             threatRoot +=  (0.3* status.get('neighborThreat', 0))**0.5   
        else:
             threatRoot +=  (0.1* status.get('neighborThreat', 0))**0.5   
        threat = threatRoot**2
        unmetThreat += max( 0,  threat - myRating )
        shipsNeeded += math.ceil( max(0,   (threatRoot/cSRR)- (myRating/curShipRating)**0.5 ) )
        
    #militaryPriority = int( 40 + max(0,  75*unmetThreat / curShipRating) )  
    militaryPriority = int( 40 + max(0,  75*shipsNeeded) )  
    #print "Calculating Military Priority:  40 + 75 * unmetThreat/curShipRating \n\t  Priority: %d    \t unmetThreat  %.0f        curShipRating: %.0f"%(militaryPriority,  unmetThreat,  curShipRating)
    print "Calculating Military Priority:  40 + 75 * shipsNeeded \n\t  Priority: %d   \t shipsNeeded %d   \t unmetThreat  %.0f        curShipRating: %.0f"%(militaryPriority, shipsNeeded,   unmetThreat,  curShipRating)
    return max( militaryPriority,  0)
Beispiel #7
0
def calculateResearchPriority():
    "calculates the AI empire's demand for research"

    universe = fo.getUniverse()
    empire = fo.getEmpire()
    empireID = empire.empireID
    
    industryPriority = foAI.foAIstate.getPriority(EnumsAI.AIPriorityType.PRIORITY_RESOURCE_PRODUCTION)
    
    gotAlgo = empire.getTechStatus("LRN_ALGO_ELEGANCE") == fo.techStatus.complete
    researchQueueList = ResearchAI.getResearchQueueTechs()
    orbGenTech = "PRO_ORBITAL_GEN"
        
    totalPP = empire.productionPoints
    totalRP = empire.resourceProduction(fo.resourceType.research)
    industrySurge=   (foAI.foAIstate.aggression > fo.aggression.cautious) and  ( totalPP <(30*(foAI.foAIstate.aggression))  )  and (orbGenTech  in researchQueueList[:3]  or  empire.getTechStatus(orbGenTech) == fo.techStatus.complete)
    # get current industry production & Target
    ownedPlanetIDs = PlanetUtilsAI.getOwnedPlanetsByEmpire(universe.planetIDs, empireID)
    planets = map(universe.getPlanet,  ownedPlanetIDs)
    targetRP = sum( map( lambda x: x.currentMeterValue(fo.meterType.targetResearch),  planets) )

    styleIndex = empireID%2
    cutoffSets =  [ [25, 45, 70  ],  [35,  50,  70  ]   ]
    cutoffs = cutoffSets[styleIndex  ] 
    settings = [ [2, .6, .4, .35  ],  [1.4,  .7,  .4, .35   ]   ][styleIndex  ] 
    
    if industrySurge and True:
        researchPriority =  0.2 * industryPriority
    else:
        if  (fo.currentTurn() < cutoffs[0]) or not gotAlgo:
            researchPriority = settings[0] * industryPriority # high research at beginning of game to get easy gro tech and to get research booster Algotrithmic Elegance
        elif fo.currentTurn() < cutoffs[1]:
            researchPriority = settings[1] * industryPriority# med-high research 
        elif fo.currentTurn() < cutoffs[2]:
            researchPriority = settings[2] * industryPriority # med-high  industry 
        else:
            researchQueue = list(empire.researchQueue)
            researchPriority = settings[3] * industryPriority # high  industry , low research 
            if len(researchQueue) == 0 :
                researchPriority = 0 # done with research
            elif len(researchQueue) <5 and researchQueue[-1].allocation > 0 :
                researchPriority =  len(researchQueue) # barely not done with research 
            elif len(researchQueue) <10 and researchQueue[-1].allocation > 0 :
                researchPriority = 4+ len(researchQueue) # almost done with research 
            elif len(researchQueue) <20 and researchQueue[int(len(researchQueue)/2)].allocation > 0 :
                researchPriority = 0.5 * researchPriority # closing in on end of research 
            elif len(researchQueue) <20:
                researchPriority = 0.7*researchPriority # high  industry , low research 

    print  ""
    print  "Research Production (current/target) : ( %.1f / %.1f )"%(totalRP,  targetRP)
    print  "Priority for Research: " + str(researchPriority)

    return researchPriority
Beispiel #8
0
def calculateMilitaryPriority():
    "calculates the demand for military ships by military targeted systems"

    universe = fo.getUniverse()
    empire = fo.getEmpire()
    empireID = empire.empireID
    capitalID = PlanetUtilsAI.getCapital()
    homeworld = universe.getPlanet(capitalID)
    if homeworld:
        homeSystemID = homeworld.systemID
    else:
        homeSystemID=-1

    totalThreat = 0
    for sysStatus in foAI.foAIstate.systemStatus.values():
        totalThreat += max(0, (sysStatus.get('fleetThreat', 0) + sysStatus.get('planetThreat', 0)  - 0.7*sysStatus.get('monsterThreat', 0) + sysStatus.get('neighborThreat', 0)   )) #being safe; should never be neg since fleetThreat should include monsterThreat
    totalFleetRating = 0
    for fleetStatus in foAI.foAIstate.fleetStatus.values():
        totalFleetRating += fleetStatus.get('rating', {}).get('overall', 0)

    
    #numMilitaryTargetedSystemIDs = len(AIstate.militaryTargetedSystemIDs)
    #militaryShipIDs = FleetUtilsAI.getEmpireFleetIDsByRole(AIFleetMissionType.FLEET_MISSION_MILITARY)
    #numMilitaryShips = len(FleetUtilsAI.extractFleetIDsWithoutMissionTypes(militaryShipIDs))

    curShipRating = curBestMilShipRating()

    if fo.currentTurn() < 20:
        threatBias = 0
    elif fo.currentTurn() < 40:
        threatBias = 10
    elif fo.currentTurn() < 60:
        threatBias = 80
    elif fo.currentTurn() < 80:
        threatBias = 100
    else:
        threatBias = 200
    if threatBias > 0:
        threatBias = max(threatBias,  curShipRating)
    visibleSystemIDs = foAI.foAIstate.visInteriorSystemIDs.keys() + foAI.foAIstate. visBorderSystemIDs.keys()
    accessibleSystemIDs = [sysID for sysID in visibleSystemIDs if  universe.systemsConnected(sysID, homeSystemID, empireID) ]
    totalBias = len(accessibleSystemIDs) * threatBias

    # build one more military ship than military targeted systems
    #militaryPriority = 100 * ((numMilitaryTargetedSystemIDs +2) - numMilitaryShips) / (numMilitaryTargetedSystemIDs + 1)
    militaryPriority = int( 40 + max(0,  15*((1.25*totalThreat +threatBias  -  totalFleetRating ) / curShipRating)) )
    print "Military Priority Calc:  int( 40 + max(0,  10*((1.25*totalThreat(%d)  -  totalFleetRating(%d)  ) / curShipRating(%d)  )) ) = %d"%(totalThreat,  totalFleetRating,  curShipRating, militaryPriority)
    # print ""
    # print "Number of Military Ships Without Missions: " + str(numMilitaryShips)
    # print "Number of Military Targeted Systems: " + str(numMilitaryTargetedSystemIDs)
    # print "Priority for Military Ships: " + str(militaryPriority)

    return max( militaryPriority,  0)
Beispiel #9
0
def calculateColonisationPriority():
    """calculates the demand for colony ships by colonisable planets"""
    global allottedColonyTargets, colony_growth_barrier
    enemies_sighted = foAI.foAIstate.misc.get("enemies_sighted", {})
    galaxy_is_sparse = ColonisationAI.galaxy_is_sparse()
    total_pp = fo.getEmpire().productionPoints
    num_colonies = len(list(AIstate.popCtrIDs))
    # significant growth barrier for low aggression, negligible for high aggression
    colony_growth_barrier = 2 + ((0.5 + foAI.foAIstate.aggression) ** 2) * fo.currentTurn() / 50.0
    colonyCost = AIDependencies.COLONY_POD_COST * (1 + AIDependencies.COLONY_POD_UPKEEP * num_colonies)
    turnsToBuild = 8  # TODO: check for susp anim pods, build time 10
    mil_prio = foAI.foAIstate.get_priority(EnumsAI.AIPriorityType.PRIORITY_PRODUCTION_MILITARY)
    allottedPortion = [[[0.6, 0.8], [0.3, 0.4]], [[0.8, 0.9], [0.3, 0.4]]][galaxy_is_sparse][any(enemies_sighted)][
        fo.empireID() % 2
    ]
    # if ( foAI.foAIstate.get_priority(EnumsAI.AIPriorityType.PRIORITY_PRODUCTION_COLONISATION)
    # > 2 * foAI.foAIstate.get_priority(EnumsAI.AIPriorityType.PRIORITY_PRODUCTION_MILITARY)):
    # allottedPortion *= 1.5
    if mil_prio < 100:
        allottedPortion *= 2
    elif mil_prio < 200:
        allottedPortion *= 1.5
    elif fo.currentTurn() > 100:
        allottedPortion *= 0.75 ** (num_colonies / 10.0)
    # allottedColonyTargets = 1+ int(fo.currentTurn()/50)
    allottedColonyTargets = 1 + int(total_pp * turnsToBuild * allottedPortion / colonyCost)
    outpost_prio = foAI.foAIstate.get_priority(EnumsAI.AIPriorityType.PRIORITY_PRODUCTION_OUTPOST)
    # if have any outposts to build, don't build colony ships TODO: make more complex assessment
    if outpost_prio > 0 or num_colonies > colony_growth_barrier:
        return 0.0

    if num_colonies > colony_growth_barrier:
        return 0.0
    numColonisablePlanetIDs = len(
        [pid for (pid, (score, _)) in foAI.foAIstate.colonisablePlanetIDs.items() if score > 60][
            : allottedColonyTargets + 2
        ]
    )
    if numColonisablePlanetIDs == 0:
        return 1

    colonyshipIDs = FleetUtilsAI.get_empire_fleet_ids_by_role(EnumsAI.AIFleetMissionType.FLEET_MISSION_COLONISATION)
    numColonyships = len(FleetUtilsAI.extract_fleet_ids_without_mission_types(colonyshipIDs))
    colonisationPriority = 60 * (1 + numColonisablePlanetIDs - numColonyships) / (numColonisablePlanetIDs + 1)

    # print
    # print "Number of Colony Ships : " + str(numColonyships)
    # print "Number of Colonisable planets : " + str(numColonisablePlanetIDs)
    # print "Priority for colony ships : " + str(colonisationPriority)

    if colonisationPriority < 1:
        return 0
    return colonisationPriority
Beispiel #10
0
def calculateResearchPriority():
    "calculates the AI empire's demand for research"

    universe = fo.getUniverse()
    empire = fo.getEmpire()
    empireID = empire.empireID
    gotAlgo = empire.getTechStatus("LRN_ALGO_ELEGANCE") == fo.techStatus.complete
    researchQueueList = getResearchQueueTechs()
    orbGenTech = "PRO_ORBITAL_GEN"
        
    totalPP = empire.productionPoints
    totalRP = empire.resourceProduction(fo.resourceType.research)
    industrySurge=   (foAI.foAIstate.aggression > fo.aggression.cautious) and  ( totalPP <(20*(foAI.foAIstate.aggression))  )  and (orbGenTech  in researchQueueList[:2]  or  empire.getTechStatus(orbGenTech) == fo.techStatus.complete)
    # get current industry production & Target
    ownedPlanetIDs = PlanetUtilsAI.getOwnedPlanetsByEmpire(universe.planetIDs, empireID)
    planets = map(universe.getPlanet,  ownedPlanetIDs)
    targetRP = sum( map( lambda x: x.currentMeterValue(fo.meterType.targetResearch),  planets) )

    styleIndex = empireID%2
    styleAdjustmentMap = {0:0,  1:0}#TODO: decide if I want to do anything with this
    styleAdjustment = styleAdjustmentMap.get( styleIndex,  0 )
    cutoffs =  [ [30, 40, 60  ],  [35,  50,  70  ]   ][styleIndex  ] #1 doing better
    settings = [ [50, 40, 35, 30  ],  [50,  40,  30,  25  ]   ][styleIndex  ] 
    
    #cutoffs = [ [40, 65, 90  ],  [40,  90,  150  ]   ][styleIndex  ] #1 doing better
    if industrySurge and False:
        researchPriority =  10+styleAdjustment
    else:
        if  (fo.currentTurn() < cutoffs[0]) or not gotAlgo:
            researchPriority = settings[0] # mid industry , high research at beginning of game to get easy gro tech and to get research booster Algotrithmic Elegance
        elif fo.currentTurn() < cutoffs[1]:
            researchPriority = settings[1] +styleAdjustment# mid industry , mid research 
        elif fo.currentTurn() < cutoffs[2]:
            researchPriority = settings[2]+styleAdjustment # high  industry , low research 
        else:
            researchQueue = list(empire.researchQueue)
            researchPriority = settings[3]+styleAdjustment # high  industry , low research 
            if len(researchQueue) == 0 :
                researchPriority = 0 # done with research
            elif len(researchQueue) <5 and researchQueue[-1].allocation > 0 :
                researchPriority =  len(researchQueue) # barely not done with research 
            elif len(researchQueue) <10 and researchQueue[-1].allocation > 0 :
                researchPriority = 2 # almost done with research 
            elif len(researchQueue) <20 and researchQueue[int(len(researchQueue)/2)].allocation > 0 :
                researchPriority = 5 # closing in on end of research 
            elif len(researchQueue) <20:
                researchPriority = 10 # high  industry , low research 

    print  ""
    print  "Research Production (current/target) : ( %.1f / %.1f )"%(totalRP,  targetRP)
    print  "Priority for Research: " + str(researchPriority)

    return researchPriority
Beispiel #11
0
def follow_vis_system_connections(start_system_id, home_system_id):
    universe = fo.getUniverse()
    empire_id = fo.empireID()
    exploration_list = [start_system_id]
    aistate = get_aistate()
    while exploration_list:
        cur_system_id = exploration_list.pop()
        if cur_system_id in graph_flags:
            continue
        graph_flags.add(cur_system_id)
        system = universe.getSystem(cur_system_id)
        if cur_system_id in aistate.visBorderSystemIDs:
            pre_vis = "a border system"
        elif cur_system_id in aistate.visInteriorSystemIDs:
            pre_vis = "an interior system"
        else:
            pre_vis = "an unknown system"
        system_header = "*** system %s;" % system
        if fo.currentTurn() < 50:
            visibility_turn_list = sorted(universe.getVisibilityTurnsMap(cur_system_id, empire_id).items(),
                                          key=lambda x: x[0].numerator)
            visibility_info = ', '.join('%s: %s' % (vis.name, turn) for vis, turn in visibility_turn_list)
            debug("%s previously %s. Visibility per turn: %s " % (system_header, pre_vis, visibility_info))
            status_info = []
        else:
            status_info = [system_header]

        has_been_visible = get_partial_visibility_turn(cur_system_id) > 0
        is_connected = universe.systemsConnected(cur_system_id, home_system_id, -1)  # self.empire_id)
        status_info.append("    -- is%s partially visible" % ("" if has_been_visible else " not"))
        status_info.append("    -- is%s visibly connected to homesystem" % ("" if is_connected else " not"))
        if has_been_visible:
            sys_status = aistate.systemStatus.setdefault(cur_system_id, {})
            aistate.visInteriorSystemIDs.add(cur_system_id)
            aistate.visBorderSystemIDs.discard(cur_system_id)
            neighbors = set(universe.getImmediateNeighbors(cur_system_id, empire_id))
            sys_status.setdefault('neighbors', set()).update(neighbors)
            if neighbors:
                status_info.append(" -- has neighbors %s" % sorted(neighbors))
                for sys_id in neighbors:
                    if sys_id not in aistate.exploredSystemIDs:
                        aistate.unexploredSystemIDs.add(sys_id)
                    if (sys_id not in graph_flags) and (sys_id not in aistate.visInteriorSystemIDs):
                        aistate.visBorderSystemIDs.add(sys_id)
                        exploration_list.append(sys_id)
        if fo.currentTurn() < 50:
            debug('\n'.join(status_info))
            debug("----------------------------------------------------------")
Beispiel #12
0
    def refresh(self):
        """Turn start AIstate cleanup/refresh."""
        universe = fo.getUniverse()
        # checks exploration border & clears roles/missions of missing fleets & updates fleet locs & threats
        fleetsLostBySystem.clear()
        invasionTargets[:] = []
        exploration_center = PlanetUtilsAI.get_capital_sys_id()
        if exploration_center == -1:  # a bad state probably from an old savegame, or else empire has lost (or almost has)
            exploration_center = self.__origin_home_system_id

        # check if planets in cache is still present. Remove destroyed.
        for system_id, info in sorted(self.systemStatus.items()):
            planet_dict = info.get('planets', {})
            cache_planet_set = set(planet_dict)
            system_planet_set = set(universe.getSystem(system_id).planetIDs)
            diff = cache_planet_set - system_planet_set
            if diff:
                print "Removing destroyed planets from systemStatus for system %s: planets to be removed: %s" % (system_id, sorted(diff))
                for key in diff:
                    del planet_dict[key]

        ExplorationAI.graphFlags.clear()
        if fo.currentTurn() < 50:
            print "-------------------------------------------------"
            print "Border Exploration Update (relative to %s)" % (PlanetUtilsAI.sys_name_ids([exploration_center, -1])[0])
            print "-------------------------------------------------"
        if self.visBorderSystemIDs.keys() == [-1]:
            self.visBorderSystemIDs.clear()
            self.visBorderSystemIDs[exploration_center] = 1
        for sys_id in self.visBorderSystemIDs.keys():  # This dict modified during iteration.
            if fo.currentTurn() < 50:
                print "Considering border system %s" % (PlanetUtilsAI.sys_name_ids([sys_id, -1])[0])
            ExplorationAI.follow_vis_system_connections(sys_id, exploration_center)
        newly_explored = ExplorationAI.update_explored_systems()
        nametags = []
        for sys_id in newly_explored:
            newsys = universe.getSystem(sys_id)
            nametags.append("ID:%4d -- %-20s" % (sys_id, (newsys and newsys.name) or "name unknown"))  # an explored system *should* always be able to be gotten
        if newly_explored:
            print "-------------------------------------------------"
            print "Newly explored systems:\n%s" % "\n".join(nametags)
            print "-------------------------------------------------"
        # cleanup fleet roles
        # self.update_fleet_locs()
        self.__clean_fleet_roles()
        self.__clean_fleet_missions(FleetUtilsAI.get_empire_fleet_ids())
        print "Fleets lost by system: %s" % fleetsLostBySystem
        self.update_system_status()
Beispiel #13
0
    def clean(self):
        "turn start AIstate cleanup"

        fleetsLostBySystem.clear()
        fleetsLostByID.clear()
        invasionTargets[:]=[]

        ExplorationAI.graphFlags.clear()
        if fo.currentTurn() < 50:
            print "-------------------------------------------------"
            print "Border Exploration Update"
            print "-------------------------------------------------"
        for sysID in list(self.visBorderSystemIDs):
            ExplorationAI.followVisSystemConnections(sysID,  self.origHomeSystemID)
        newlyExplored = ExplorationAI.updateExploredSystems()
        nametags=[]
        universe = fo.getUniverse()
        for sysID in newlyExplored:
            newsys = universe.getSystem(sysID)
            nametags.append(  "ID:%4d -- %20s"%(sysID, (newsys and newsys.name) or"name unknown"  )    )# an explored system *should* always be able to be gotten
        if newlyExplored:
            print "-------------------------------------------------"
            print "newly explored systems: \n"+"\n".join(nametags)
            print "-------------------------------------------------"
        # cleanup fleet roles
        #self.updateFleetLocs()
        self.__cleanFleetRoles()
        self.__cleanAIFleetMissions(FleetUtilsAI.getEmpireFleetIDs())
        print "Fleets lost by system: %s"%fleetsLostBySystem
        self.updateSystemStatus()
        ExplorationAI.updateScoutFleets() #should do this after clearing dead  fleets, currently should be already done here
Beispiel #14
0
    def end(self):
        """
        Stop timer, output result, clear checks.
        If dumping to file, if headers are not match to prev, new header line will be added.
        """
        turn = fo.currentTurn()
        self.stop()
        if not self.timers:
            return
        max_header = max(len(x[0]) for x in self.timers)
        line_max_size = max_header + 14
        print
        print ('Timing for %s:' % self.timer_name)
        print '=' * line_max_size
        for name, val in self.timers:
            print "%-*s %8d msec" % (max_header, name, val)
        print '-' * line_max_size
        print ("Total: %8d msec" % sum(x[1] for x in self.timers)).rjust(line_max_size)

        if self.write_log and DUMP_TO_FILE:
            headers = make_header('Turn', *[x[0] for x in self.timers])
            if self.headers != headers:
                self._write(''.join(headers) + '\n' + ''.join(['-' * (len(x) - 2) + '  ' for x in headers]))
                self.headers = headers

            row = []
            for header, val in zip(self.headers, [turn] + [x[1] for x in self.timers]):
                row.append('%*s ' % (len(header) - 2, int(val)))
            self._write(''.join(row))
        self.timers = []  # clear times
Beispiel #15
0
def calculateExplorationPriority():
    """calculates the demand for scouts by unexplored systems"""
    global scoutsNeeded

    universe = fo.getUniverse()
    empire = fo.getEmpire()
    numUnexploredSystems = len( ExplorationAI.borderUnexploredSystemIDs )  #len(foAI.foAIstate.get_explorable_systems(AIExplorableSystemType.EXPLORABLE_SYSTEM_UNEXPLORED))
    numScouts = sum( [ foAI.foAIstate.fleetStatus.get(fid, {}).get('nships', 0) for fid in FleetUtilsAI.get_empire_fleet_ids_by_role(
        EnumsAI.AIFleetMissionType.FLEET_MISSION_EXPLORATION)] ) # FleetUtilsAI.get_empire_fleet_ids_by_role(AIFleetMissionType.FLEET_MISSION_EXPLORATION)
    productionQueue = empire.productionQueue
    queuedScoutShips=0
    for queue_index in range(0, len(productionQueue)):
        element=productionQueue[queue_index]
        if element.buildType == EnumsAI.AIEmpireProductionTypes.BT_SHIP:
            if foAI.foAIstate.get_ship_role(element.designID) == EnumsAI.AIShipRoleType.SHIP_ROLE_CIVILIAN_EXPLORATION :
                queuedScoutShips += element.remaining * element.blocksize

    milShips = MilitaryAI.num_milships
    # intent of the following calc is essentially 
    # new_scouts_needed = min(need_cap_A, need_cap_B, base_need) - already_got_or_queued
    # where need_cap_A is to help prevent scouting needs from swamping military needs, and 
    # need_cap_B is to help regulate investment into scouting while the empire is small.
    # These caps could perhaps instead be tied more directly to military priority and 
    # total empire production.
    scoutsNeeded = max(0, min( 4+int(milShips/5), 4+int(fo.currentTurn()/50) , 2+ numUnexploredSystems**0.5 ) - numScouts - queuedScoutShips )
    explorationPriority = int(40*scoutsNeeded)

    print
    print "Number of Scouts : " + str(numScouts)
    print "Number of Unexplored systems: " + str(numUnexploredSystems)
    print "military size: ", milShips
    print "Priority for scouts : " + str(explorationPriority)

    return explorationPriority
Beispiel #16
0
def cur_best_mil_ship_rating(include_designs=False):
    """Find the best military ship we have available in this turn and return its rating.

    :param include_designs: toggles if available designs are considered or only existing ships
    :return: float: rating of the best ship
    """
    current_turn = fo.currentTurn()
    if current_turn in best_ship_rating_cache:
        best_rating = best_ship_rating_cache[current_turn]
        if include_designs:
            best_design_rating = ProductionAI.cur_best_military_design_rating()
            best_rating = max(best_rating, best_design_rating)
        return best_rating
    best_rating = 0.001
    universe = fo.getUniverse()
    for fleet_id in FleetUtilsAI.get_empire_fleet_ids_by_role(MissionType.MILITARY):
        fleet = universe.getFleet(fleet_id)
        for ship_id in fleet.shipIDs:
            ship = universe.getShip(ship_id)
            if ship:
                ship_info = [(ship.id, ship.designID, ship.speciesName)]
                ship_rating = foAI.foAIstate.rate_psuedo_fleet(ship_info=ship_info)['overall']
                best_rating = max(best_rating, ship_rating)
    best_ship_rating_cache[current_turn] = best_rating
    if include_designs:
        best_design_rating = ProductionAI.cur_best_military_design_rating()
        best_rating = max(best_rating, best_design_rating)
    return max(best_rating, 0.001)
Beispiel #17
0
def calculateExplorationPriority():
    """calculates the demand for scouts by unexplored systems"""
    global scoutsNeeded

    universe = fo.getUniverse()
    empire = fo.getEmpire()
    numUnexploredSystems = len( ExplorationAI.borderUnexploredSystemIDs )  #len(foAI.foAIstate.get_explorable_systems(AIExplorableSystemType.EXPLORABLE_SYSTEM_UNEXPLORED))
    numScouts = sum( [ foAI.foAIstate.fleetStatus.get(fid, {}).get('nships', 0) for fid in ExplorationAI.currentScoutFleetIDs] ) # FleetUtilsAI.get_empire_fleet_ids_by_role(AIFleetMissionType.FLEET_MISSION_EXPLORATION)
    productionQueue = empire.productionQueue
    queuedScoutShips=0
    for queue_index in range(0, len(productionQueue)):
        element=productionQueue[queue_index]
        if element.buildType == EnumsAI.AIEmpireProductionTypes.BT_SHIP:
            if foAI.foAIstate.get_ship_role(element.designID) == EnumsAI.AIShipRoleType.SHIP_ROLE_CIVILIAN_EXPLORATION :
                queuedScoutShips += element.remaining * element.blocksize

    milShips = MilitaryAI.num_milships
    scoutsNeeded = max(0, min( 4+int(milShips/5), 4+int(fo.currentTurn()/50) , 2+ numUnexploredSystems**0.5 ) - numScouts - queuedScoutShips )
    explorationPriority = int(40*scoutsNeeded)

    print
    print "Number of Scouts : " + str(numScouts)
    print "Number of Unexplored systems: " + str(numUnexploredSystems)
    print "military size: ", milShips
    print "Priority for scouts : " + str(explorationPriority)

    return explorationPriority
Beispiel #18
0
def generateOrders():
    empire = fo.getEmpire()
    print "Empire:  " + empire.name + " TURN: " + str(fo.currentTurn())
    print "Capital: " + str(empire.capitalID)

    # turn cleanup
    splitFleet()

    identifyShipDesigns()
    identifyFleetsRoles()
    foAIstate.clean(ExplorationAI.getHomeSystemID(), FleetUtilsAI.getEmpireFleetIDs())
    # ...missions
    # ...demands/priorities

    # call AI modules
    PriorityAI.calculatePriorities()
    ExplorationAI.assignScoutsToExploreSystems()
    ColonisationAI.assignColonyFleetsToColonise()
    InvasionAI.assignInvasionFleetsToInvade()
    FleetUtilsAI.generateAIFleetOrdersForAIFleetMissions()
    FleetUtilsAI.issueAIFleetOrdersForAIFleetMissions()
    ResearchAI.generateResearchOrders()
    ProductionAI.generateProductionOrders()
    ResourcesAI.generateResourcesOrders()    

    foAIstate.afterTurnCleanup()
    fo.doneTurn()
Beispiel #19
0
def calculateLearningPriority():
    """calculates the demand for techs learning category"""
    currentturn = fo.currentTurn()
    if currentturn == 1:
        return 100
    elif currentturn > 1:
        return 0
Beispiel #20
0
 def wrapper():
     if foAI.foAIstate is None:
         return function()
     else:
         cache = foAI.foAIstate.misc.setdefault('caches', {}).setdefault(function.__name__, {})
         this_turn = fo.currentTurn()
         return cache[this_turn] if this_turn in cache else cache.setdefault(this_turn, function())
Beispiel #21
0
def generateResourcesOrders(): #+
    "generate resources focus orders"

    timer= [ time() ]
    ## calculate top resource priority
    ##topResourcePriority()
    timer.append( time() )
    ## set resource foci of planets
    ##setCapitalIDResourceFocus()
    timer.append( time() )
    #------------------------------
    ##setGeneralPlanetResourceFocus()
    setPlanetResourceFoci()
    timer.append( time() )
    #-------------------------------
    ##setAsteroidsResourceFocus()
    timer.append( time() )
    ##setGasGiantsResourceFocus()
    timer.append( time() )

    printResourcesPriority()
    timer.append( time() )

    if doResourceTiming and timer_entries==__timerEntries1:
        times = [timer[i] - timer[i-1] for i in range(1,  len(timer) ) ]
        timeFmt = "%30s: %8d msec  "
        print "ResourcesAI Time Requirements:"
        for mod,  modTime in zip(timer_entries,  times):
            print timeFmt%((30*' '+mod)[-30:],  int(1000*modTime))
        if resourceTimerFile:
            resourceTimerFile.write(  __timerFileFmt%tuple( [ fo.currentTurn() ]+map(lambda x: int(1000*x),  times )) +'\n')
            resourceTimerFile.flush()
Beispiel #22
0
 def print_resource_ai_footer():
     empire = fo.getEmpire()
     pp, rp = empire.productionPoints, empire.resourceProduction(fo.resourceType.research)
     # Next string used in charts. Don't modify it!
     print "Current Output (turn %4d) RP/PP : %.2f ( %.1f / %.1f )" % (fo.currentTurn(), rp / (pp + 0.0001), rp, pp)
     print "------------------------"
     print "ResourcesAI Time Requirements:"
Beispiel #23
0
def _calculate_exploration_priority():
    """Calculates the demand for scouts by unexplored systems."""
    empire = fo.getEmpire()
    num_unexplored_systems = len(ExplorationAI.borderUnexploredSystemIDs)
    num_scouts = sum([foAI.foAIstate.fleetStatus.get(fid, {}).get('nships', 0) for fid in FleetUtilsAI.get_empire_fleet_ids_by_role(
        MissionType.EXPLORATION)])
    production_queue = empire.productionQueue
    queued_scout_ships = 0
    for queue_index in range(0, len(production_queue)):
        element = production_queue[queue_index]
        if element.buildType == EmpireProductionTypes.BT_SHIP:
            if foAI.foAIstate.get_ship_role(element.designID) == ShipRoleType.CIVILIAN_EXPLORATION:
                queued_scout_ships += element.remaining * element.blocksize

    mil_ships = MilitaryAI.get_num_military_ships()
    # intent of the following calc is essentially
    # new_scouts_needed = min(need_cap_A, need_cap_B, base_need) - already_got_or_queued
    # where need_cap_A is to help prevent scouting needs from swamping military needs, and
    # need_cap_B is to help regulate investment into scouting while the empire is small.
    # These caps could perhaps instead be tied more directly to military priority and
    # total empire production.
    desired_number_of_scouts = int(min(4 + mil_ships/5, 4 + fo.currentTurn()/50.0, 2 + num_unexplored_systems**0.5))
    scouts_needed = max(0, desired_number_of_scouts - (num_scouts + queued_scout_ships))
    exploration_priority = int(40 * scouts_needed)

    print
    print "Number of Scouts: %s" % num_scouts
    print "Number of Unexplored systems: %s" % num_unexplored_systems
    print "Military size: %s" % mil_ships
    print "Priority for scouts: %s" % exploration_priority

    return exploration_priority
Beispiel #24
0
def cur_best_mil_ship_rating(include_designs=False):
    """Find the best military ship we have available in this turn and return its rating.

    :param include_designs: toggles if available designs are considered or only existing ships
    :return: float: rating of the best ship
    """
    current_turn = fo.currentTurn()
    if current_turn in _best_ship_rating_cache:
        best_rating = _best_ship_rating_cache[current_turn]
        if include_designs:
            best_design_rating = ProductionAI.cur_best_military_design_rating()
            best_rating = max(best_rating, best_design_rating)
        return best_rating
    best_rating = 0.001
    universe = fo.getUniverse()
    for fleet_id in FleetUtilsAI.get_empire_fleet_ids_by_role(MissionType.MILITARY):
        fleet = universe.getFleet(fleet_id)
        for ship_id in fleet.shipIDs:
            ship_rating = CombatRatingsAI.ShipCombatStats(ship_id).get_rating(enemy_stats=foAI.foAIstate.get_standard_enemy())
            best_rating = max(best_rating, ship_rating)
    _best_ship_rating_cache[current_turn] = best_rating
    if include_designs:
        best_design_rating = ProductionAI.cur_best_military_design_rating()
        best_rating = max(best_rating, best_design_rating)
    return max(best_rating, 0.001)
Beispiel #25
0
def _calculate_learning_priority():
    """Calculates the demand for techs learning category."""
    turn = fo.currentTurn()
    if turn == 1:
        return 100
    elif turn > 1:
        return 0
Beispiel #26
0
 def get_prev_turn_uid(self):
     """
     Return uid of previous turn.
     If called during the first turn after loading a saved game that had an AI version not yet using uids
     will return default value.
     """
     return self.turn_uids.get(fo.currentTurn() - 1, '0')
Beispiel #27
0
 def __report_system_threats(self):
     """Print a table with system threats to the logfile."""
     current_turn = fo.currentTurn()
     if current_turn >= 100:
         return
     threat_table = Table([
         Text('System'), Text('Vis.'), Float('Total'), Float('by Monsters'), Float('by Fleets'),
         Float('by Planets'), Float('1 jump away'), Float('2 jumps'), Float('3 jumps')],
         table_name="System Threat Turn %d" % current_turn
     )
     universe = fo.getUniverse()
     for sys_id in universe.systemIDs:
         sys_status = self.systemStatus.get(sys_id, {})
         system = universe.getSystem(sys_id)
         threat_table.add_row([
             system,
             "Yes" if sys_status.get('currently_visible', False) else "No",
             sys_status.get('totalThreat', 0),
             sys_status.get('monsterThreat', 0),
             sys_status.get('fleetThreat', 0),
             sys_status.get('planetThreat', 0),
             sys_status.get('neighborThreat', 0.0),
             sys_status.get('jump2_threat', 0.0),
             sys_status.get('jump3_threat', 0.0),
         ])
     info(threat_table)
 def wrapper():
     if get_aistate() is None:
         return func()
     else:
         cache = get_aistate().misc.setdefault('caches', {}).setdefault(func.__name__, {})
         this_turn = fo.currentTurn()
         return cache[this_turn] if this_turn in cache else cache.setdefault(this_turn, func())
Beispiel #29
0
def calculateMilitaryPriority():
    "calculates the demand for military ships by military targeted systems"

    universe = fo.getUniverse()
    empire = fo.getEmpire()
    empireID = empire.empireID
    capitalID = PlanetUtilsAI.getCapital()
    if capitalID:
        homeworld = universe.getPlanet(capitalID)
    else:
        return 0# no capitol (not even a capitol-in-the-making), means can't produce any ships
    allottedInvasionTargets = 1+ int(fo.currentTurn()/25)
    targetPlanetIDs =  [pid for pid, pscore, trp in AIstate.invasionTargets[:allottedInvasionTargets] ] + [pid for pid,  pscore in foAI.foAIstate.colonisablePlanetIDs[:allottedColonyTargets]  ] + [pid for pid,  pscore in foAI.foAIstate.colonisableOutpostIDs[:allottedColonyTargets]  ]
    
    mySystems = set( AIstate.popCtrSystemIDs ).union( AIstate.outpostSystemIDs   )
    targetSystems = set( PlanetUtilsAI.getSystems(targetPlanetIDs)  )
    
    curShipRating = curBestMilShipRating()

    unmetThreat = 0.0
    currentTurn=fo.currentTurn()
    for sysID in mySystems.union(targetSystems) :
        status=foAI.foAIstate.systemStatus.get( sysID,  {} )
        myAttack,  myHealth =0, 0
        for fid in status.get('myfleets', []) :
            rating= foAI.foAIstate.fleetStatus.get(fid,  {}).get('rating', {})
            myAttack += rating.get('attack', 0)
            myHealth += rating.get('health', 0)
        myRating = myAttack*myHealth
        baseMonsterThreat = status.get('monsterThreat', 0)
        if currentTurn>200:
            monsterThreat = baseMonsterThreat
        elif currentTurn>100:
            if baseMonsterThreat <2000:
                monsterThreat = baseMonsterThreat
            else:
                monsterThreat = 2000 + (currentTurn/100.0 - 1) *(baseMonsterThreat-2000)
        else:
            monsterThreat = 0
        if sysID in mySystems:
            threat = status.get('fleetThreat', 0) + status.get('planetThreat', 0) + 0.3* status.get('neighborThreat', 0)   
        else:
            threat = status.get('fleetThreat', 0) + status.get('planetThreat', 0) + 0.1* status.get('neighborThreat', 0)   
        unmetThreat += max( 0,  threat + monsterThreat - myRating )
        
    militaryPriority = int( 40 + max(0,  75*unmetThreat / curShipRating) )  
    return max( militaryPriority,  0)
def dump_universe():
    """Dump the universe but not more than once per turn."""
    cur_turn = fo.currentTurn()

    if (not hasattr(dump_universe, "last_dump") or
            dump_universe.last_dump < cur_turn):
        dump_universe.last_dump = cur_turn
        fo.getUniverse().dump()  # goes to debug logger
Beispiel #31
0
 def get_current_turn_uid(self):
     """
     Return uid of current turn.
     """
     return self.turn_uids.setdefault(fo.currentTurn(), self.generate_uid())
def _calculate_research_priority():
    """Calculates the AI empire's demand for research."""
    universe = fo.getUniverse()
    empire = fo.getEmpire()
    empire_id = empire.empireID
    current_turn = fo.currentTurn()
    enemies_sighted = foAI.foAIstate.misc.get('enemies_sighted', {})
    recent_enemies = [x for x in enemies_sighted if x > current_turn - 8]

    industry_priority = foAI.foAIstate.get_priority(
        PriorityType.RESOURCE_PRODUCTION)

    got_algo = tech_is_complete(AIDependencies.LRN_ALGO_ELEGANCE)
    got_quant = tech_is_complete(AIDependencies.LRN_QUANT_NET)
    research_queue_list = ResearchAI.get_research_queue_techs()
    orb_gen_tech = AIDependencies.PRO_ORBITAL_GEN
    got_orb_gen = tech_is_complete(orb_gen_tech)
    mgrav_prod_tech = AIDependencies.PRO_MICROGRAV_MAN
    got_mgrav_prod = tech_is_complete(mgrav_prod_tech)
    # got_solar_gen = tech_is_complete(AIDependencies.PRO_SOL_ORB_GEN)

    milestone_techs = [
        "PRO_SENTIENT_AUTOMATION", "LRN_DISTRIB_THOUGHT", "LRN_QUANT_NET",
        "SHP_WEAPON_2_4", "SHP_WEAPON_3_2", "SHP_WEAPON_4_2"
    ]
    milestones_done = [
        mstone for mstone in milestone_techs if tech_is_complete(mstone)
    ]
    print "Research Milestones accomplished at turn %d: %s" % (current_turn,
                                                               milestones_done)

    total_pp = empire.productionPoints
    total_rp = empire.resourceProduction(fo.resourceType.research)
    industry_surge = (
        foAI.foAIstate.character.may_surge_industry(total_pp, total_rp)
        and (((orb_gen_tech in research_queue_list[:2] or got_orb_gen)
              and state.have_gas_giant) or
             ((mgrav_prod_tech in research_queue_list[:2] or got_mgrav_prod)
              and state.have_asteroids))
        and (not (len(AIstate.popCtrIDs) >= 12)))
    # get current industry production & Target
    owned_planet_ids = PlanetUtilsAI.get_owned_planets_by_empire(
        universe.planetIDs)
    planets = map(universe.getPlanet, owned_planet_ids)
    target_rp = sum(
        map(lambda x: x.currentMeterValue(fo.meterType.targetResearch),
            planets))
    galaxy_is_sparse = ColonisationAI.galaxy_is_sparse()
    enemies_sighted = foAI.foAIstate.misc.get('enemies_sighted', {})

    style_index = foAI.foAIstate.character.preferred_research_cutoff([0, 1])
    if foAI.foAIstate.character.may_maximize_research():
        style_index += 1

    cutoff_sets = [[25, 45, 70, 110], [30, 45, 70, 150], [25, 40, 80, 160]]
    cutoffs = cutoff_sets[style_index]
    settings = [[1.3, .7, .5, .4, .35], [1.4, 0.8, 0.6, 0.5, 0.35],
                [1.4, 0.8, 0.6, 0.5, 0.4]][style_index]

    if (current_turn < cutoffs[0]) or (not got_algo) or (
        (style_index == 0) and not got_orb_gen and
        (current_turn < cutoffs[1])):
        research_priority = settings[
            0] * industry_priority  # high research at beginning of game to get easy gro tech and to get research booster Algotrithmic Elegance
    elif (not got_orb_gen) or (current_turn < cutoffs[1]):
        research_priority = settings[1] * industry_priority  # med-high research
    elif current_turn < cutoffs[2]:
        research_priority = settings[2] * industry_priority  # med-high industry
    elif current_turn < cutoffs[3]:
        research_priority = settings[3] * industry_priority  # med-high industry
    else:
        research_queue = list(empire.researchQueue)
        research_priority = settings[
            4] * industry_priority  # high industry , low research
        if len(research_queue) == 0:
            research_priority = 0  # done with research
        elif len(research_queue) < 5 and research_queue[-1].allocation > 0:
            research_priority = len(
                research_queue
            ) * 0.01 * industry_priority  # barely not done with research
        elif len(research_queue) < 10 and research_queue[-1].allocation > 0:
            research_priority = (
                4 + 2 * len(research_queue)
            ) * 0.01 * industry_priority  # almost done with research
        elif len(research_queue) < 20 and research_queue[int(
                len(research_queue) / 2)].allocation > 0:
            research_priority *= 0.7  # closing in on end of research
    if industry_surge:
        if galaxy_is_sparse and not any(enemies_sighted):
            research_priority *= 0.5
        else:
            research_priority *= 0.8

    if ((tech_is_complete("SHP_WEAPON_2_4")
         or tech_is_complete("SHP_WEAPON_4_1"))
            and tech_is_complete(AIDependencies.PROD_AUTO_NAME)):
        # industry_factor = [ [0.25, 0.2], [0.3, 0.25], [0.3, 0.25] ][style_index ]
        # researchPriority = min(researchPriority, industry_factor[got_solar_gen]*industryPriority)
        research_priority *= 0.9
    if got_quant:
        research_priority = min(research_priority + 0.1 * industry_priority,
                                research_priority * 1.3)
    research_priority = int(research_priority)
    print "Research Production (current/target) : ( %.1f / %.1f )" % (
        total_rp, target_rp)
    print "Priority for Research: %d (new target ~ %d RP)" % (
        research_priority, total_pp * research_priority / industry_priority)

    if len(enemies_sighted) < (
            2 + current_turn / 20.0):  # TODO: adjust for colonisation priority
        research_priority *= 1.2
    if (current_turn > 20) and (len(recent_enemies) > 3):
        research_priority *= 0.8
    return research_priority
Beispiel #33
0
    def issue_fleet_orders(self):
        """issues AIFleetOrders which can be issued in system and moves to next one if is possible"""
        # TODO: priority
        order_completed = True

        debug(
            "\nChecking orders for fleet %s (on turn %d), with mission type %s and target %s",
            self.fleet.get_object(),
            fo.currentTurn(),
            self.type or "No mission",
            self.target or "No Target",
        )
        if MissionType.INVASION == self.type:
            self._check_retarget_invasion()
        just_issued_move_order = False
        last_move_target_id = INVALID_ID
        # Note: the following abort check somewhat assumes only one major mission type
        for fleet_order in self.orders:
            if isinstance(
                    fleet_order,
                (OrderColonize, OrderOutpost,
                 OrderInvade)) and self._check_abort_mission(fleet_order):
                return
        aistate = get_aistate()
        for fleet_order in self.orders:
            if just_issued_move_order and self.fleet.get_object(
            ).systemID != last_move_target_id:
                # having just issued a move order, we will normally stop issuing orders this turn, except that if there
                # are consecutive move orders we will consider moving through the first destination rather than stopping
                # Without the below noinspection directive, PyCharm is concerned about the 2nd part of the test
                # noinspection PyTypeChecker
                if not isinstance(fleet_order,
                                  OrderMove) or self.need_to_pause_movement(
                                      last_move_target_id, fleet_order):
                    break
            debug("Checking order: %s" % fleet_order)
            self.check_mergers(context=str(fleet_order))
            if fleet_order.can_issue_order(verbose=False):
                # only move if all other orders completed
                if isinstance(fleet_order, OrderMove) and order_completed:
                    debug("Issuing fleet order %s" % fleet_order)
                    fleet_order.issue_order()
                    just_issued_move_order = True
                    last_move_target_id = fleet_order.target.id
                elif not isinstance(fleet_order, OrderMove):
                    debug("Issuing fleet order %s" % fleet_order)
                    fleet_order.issue_order()
                else:
                    debug(
                        "NOT issuing (even though can_issue) fleet order %s" %
                        fleet_order)
                status_words = tuple(
                    ["not", ""][_s]
                    for _s in [fleet_order.order_issued, fleet_order.executed])
                debug("Order %s issued and %s fully executed." % status_words)
                if not fleet_order.executed:
                    order_completed = False
            else:  # check that we're not held up by a Big Monster
                if fleet_order.order_issued:
                    # A previously issued order that wasn't instantly executed must have had cirumstances change so that
                    # the order can't currently be reissued (or perhaps simply a savegame has been reloaded on the same
                    # turn the order was issued).
                    if not fleet_order.executed:
                        order_completed = False
                    # Go on to the next order.
                    continue
                debug("CAN'T issue fleet order %s because:" % fleet_order)
                fleet_order.can_issue_order(verbose=True)
                if isinstance(fleet_order, OrderMove):
                    this_system_id = fleet_order.target.id
                    this_status = aistate.systemStatus.setdefault(
                        this_system_id, {})
                    threat_threshold = fo.currentTurn(
                    ) * MilitaryAI.cur_best_mil_ship_rating() / 4.0
                    if this_status.get("monsterThreat", 0) > threat_threshold:
                        # if this move order is not this mil fleet's final destination, and blocked by Big Monster,
                        # release and hope for more effective reassignment
                        if (self.type not in (MissionType.MILITARY,
                                              MissionType.SECURE)
                                or fleet_order != self.orders[-1]):
                            debug(
                                "Aborting mission due to being blocked by Big Monster at system %d, threat %d"
                                % (this_system_id,
                                   aistate.systemStatus[this_system_id]
                                   ["monsterThreat"]))
                            debug("Full set of orders were:")
                            for this_order in self.orders:
                                debug(" - %s" % this_order)
                            self.clear_fleet_orders()
                            self.clear_target()
                            return
                break  # do not order the next order until this one is finished.
        else:  # went through entire order list
            if order_completed:
                debug("Final order is completed")
                orders = self.orders
                last_order = orders[-1] if orders else None
                universe = fo.getUniverse()

                if last_order and isinstance(last_order, OrderColonize):
                    planet = universe.getPlanet(last_order.target.id)
                    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 and not planet.initialMeterValue(
                            fo.meterType.population):
                        warning(
                            "Fleet %s has tentatively completed its "
                            "colonize mission but will wait to confirm population.",
                            self.fleet,
                        )
                        debug("    Order details are %s" % last_order)
                        debug(
                            "    Order is valid: %s; issued: %s; executed: %s"
                            % (last_order.is_valid(), last_order.order_issued,
                               last_order.executed))
                        if not last_order.is_valid():
                            source_target = last_order.fleet
                            target_target = last_order.target
                            debug(
                                "        source target validity: %s; target target validity: %s "
                                % (bool(source_target), bool(target_target)))
                        return  # colonize order must not have completed yet
                clear_all = True
                last_sys_target = INVALID_ID
                if last_order and isinstance(last_order, OrderMilitary):
                    last_sys_target = last_order.target.id
                    # not doing this until decide a way to release from a SECURE mission
                    # if (MissionType.SECURE == self.type) or
                    secure_targets = set(AIstate.colonyTargetedSystemIDs +
                                         AIstate.outpostTargetedSystemIDs +
                                         AIstate.invasionTargetedSystemIDs)
                    if last_sys_target in secure_targets:  # consider a secure mission
                        if last_sys_target in AIstate.colonyTargetedSystemIDs:
                            secure_type = "Colony"
                        elif last_sys_target in AIstate.outpostTargetedSystemIDs:
                            secure_type = "Outpost"
                        elif last_sys_target in AIstate.invasionTargetedSystemIDs:
                            secure_type = "Invasion"
                        else:
                            secure_type = "Unidentified"
                        debug(
                            "Fleet %d has completed initial stage of its mission "
                            "to secure system %d (targeted for %s), "
                            "may release a portion of ships" %
                            (self.fleet.id, last_sys_target, secure_type))
                        clear_all = False

                # for PROTECT_REGION missions, only release fleet if no more threat
                if self.type == MissionType.PROTECT_REGION:
                    # use military logic code below to determine if can release
                    # any or even all of the ships.
                    clear_all = False
                    last_sys_target = self.target.id
                    debug(
                        "Check if PROTECT_REGION mission with target %d is finished.",
                        last_sys_target)

                fleet_id = self.fleet.id
                if clear_all:
                    if orders:
                        debug(
                            "Fleet %d has completed its mission; clearing all orders and targets."
                            % self.fleet.id)
                        debug("Full set of orders were:")
                        for this_order in orders:
                            debug("\t\t %s" % this_order)
                        self.clear_fleet_orders()
                        self.clear_target()
                        if aistate.get_fleet_role(fleet_id) in (
                                MissionType.MILITARY, MissionType.SECURE):
                            allocations = MilitaryAI.get_military_fleets(
                                mil_fleets_ids=[fleet_id],
                                try_reset=False,
                                thisround="Fleet %d Reassignment" % fleet_id)
                            if allocations:
                                MilitaryAI.assign_military_fleets_to_systems(
                                    use_fleet_id_list=[fleet_id],
                                    allocations=allocations)
                    else:  # no orders
                        debug("No Current Orders")
                else:
                    potential_threat = combine_ratings(
                        MilitaryAI.get_system_local_threat(last_sys_target),
                        MilitaryAI.get_system_neighbor_threat(last_sys_target),
                    )
                    threat_present = potential_threat > 0
                    debug("Fleet threat present? %s", threat_present)
                    target_system = universe.getSystem(last_sys_target)
                    if not threat_present and target_system:
                        for pid in target_system.planetIDs:
                            planet = universe.getPlanet(pid)
                            if (planet and planet.owner != fo.empireID()
                                    and planet.currentMeterValue(
                                        fo.meterType.maxDefense) > 0):
                                debug("Found local planetary threat: %s",
                                      planet)
                                threat_present = True
                                break
                    if not threat_present:
                        debug(
                            "No current threat in target system; releasing a portion of ships."
                        )
                        # at least first stage of current task is done;
                        # release extra ships for potential other deployments
                        new_fleets = FleetUtilsAI.split_fleet(self.fleet.id)
                        if self.type == MissionType.PROTECT_REGION:
                            self.clear_fleet_orders()
                            self.clear_target()
                            new_fleets.append(self.fleet.id)
                    else:
                        debug(
                            "Threat remains in target system; Considering to release some ships."
                        )
                        new_fleets = []
                        fleet_portion_to_remain = self._portion_of_fleet_needed_here(
                        )
                        if fleet_portion_to_remain >= 1:
                            debug(
                                "Can not release fleet yet due to large threat."
                            )
                        elif fleet_portion_to_remain > 0:
                            debug(
                                "Not all ships are needed here - considering releasing a few"
                            )
                            # TODO: Rate against specific enemy threat cause
                            fleet_remaining_rating = CombatRatingsAI.get_fleet_rating(
                                fleet_id)
                            fleet_min_rating = fleet_portion_to_remain * fleet_remaining_rating
                            debug("Starting rating: %.1f, Target rating: %.1f",
                                  fleet_remaining_rating, fleet_min_rating)
                            allowance = CombatRatingsAI.rating_needed(
                                fleet_remaining_rating, fleet_min_rating)
                            debug(
                                "May release ships with total rating of %.1f",
                                allowance)
                            ship_ids = list(self.fleet.get_object().shipIDs)
                            for ship_id in ship_ids:
                                ship_rating = CombatRatingsAI.get_ship_rating(
                                    ship_id)
                                debug(
                                    "Considering to release ship %d with rating %.1f",
                                    ship_id, ship_rating)
                                if ship_rating > allowance:
                                    debug(
                                        "Remaining rating insufficient. Not released."
                                    )
                                    continue
                                debug("Splitting from fleet.")
                                new_fleet_id = FleetUtilsAI.split_ship_from_fleet(
                                    fleet_id, ship_id)
                                if assertion_fails(
                                        new_fleet_id
                                        and new_fleet_id != INVALID_ID):
                                    break
                                new_fleets.append(new_fleet_id)
                                fleet_remaining_rating = CombatRatingsAI.rating_difference(
                                    fleet_remaining_rating, ship_rating)
                                allowance = CombatRatingsAI.rating_difference(
                                    fleet_remaining_rating, fleet_min_rating)
                                debug(
                                    "Remaining fleet rating: %.1f - Allowance: %.1f",
                                    fleet_remaining_rating, allowance)
                            if new_fleets:
                                aistate.get_fleet_role(fleet_id,
                                                       force_new=True)
                                aistate.update_fleet_rating(fleet_id)
                                aistate.ensure_have_fleet_missions(new_fleets)
                        else:
                            debug(
                                "Planetary defenses are deemed sufficient. Release fleet."
                            )
                            new_fleets = FleetUtilsAI.split_fleet(
                                self.fleet.id)

                    new_military_fleets = []
                    for fleet_id in new_fleets:
                        if aistate.get_fleet_role(
                                fleet_id) in COMBAT_MISSION_TYPES:
                            new_military_fleets.append(fleet_id)
                    allocations = []
                    if new_military_fleets:
                        allocations = MilitaryAI.get_military_fleets(
                            mil_fleets_ids=new_military_fleets,
                            try_reset=False,
                            thisround="Fleet Reassignment %s" %
                            new_military_fleets,
                        )
                    if allocations:
                        MilitaryAI.assign_military_fleets_to_systems(
                            use_fleet_id_list=new_military_fleets,
                            allocations=allocations)
Beispiel #34
0
    def log_peace_request(self, initiating_empire_id, recipient_empire_id):
        """Keep a record of peace requests made or received by this empire."""

        peace_requests = self.diplomatic_logs.setdefault('peace_requests', {})
        log_index = (initiating_empire_id, recipient_empire_id)
        peace_requests.setdefault(log_index, []).append(fo.currentTurn())
Beispiel #35
0
def _calculate_military_priority():
    """Calculates the demand for military ships by military targeted systems."""
    global unmetThreat

    universe = fo.getUniverse()
    capital_id = PlanetUtilsAI.get_capital()
    if capital_id is None or capital_id == INVALID_ID:
        return 0  # no capitol (not even a capitol-in-the-making), means can't produce any ships

    have_l1_weaps = (tech_is_complete("SHP_WEAPON_1_4")
                     or (tech_is_complete("SHP_WEAPON_1_3")
                         and tech_is_complete("SHP_MIL_ROBO_CONT"))
                     or tech_is_complete("SHP_WEAPON_2_1")
                     or tech_is_complete("SHP_WEAPON_4_1"))
    have_l2_weaps = tech_is_complete("SHP_WEAPON_2_3") or tech_is_complete(
        "SHP_WEAPON_4_1")
    aistate = get_aistate()
    enemies_sighted = aistate.misc.get("enemies_sighted", {})

    target_planet_ids = ([
        pid for pid, pscore, trp in
        AIstate.invasionTargets[:allotted_invasion_targets()]
    ] + [
        pid for pid, pscore in list(aistate.colonisablePlanetIDs.items())
        [:allottedColonyTargets]
    ] + [
        pid for pid, pscore in list(aistate.colonisableOutpostIDs.items())
        [:allottedColonyTargets]
    ])

    my_systems = set(get_owned_planets())
    target_systems = set(PlanetUtilsAI.get_systems(target_planet_ids))

    cur_ship_rating = cur_best_military_design_rating()
    current_turn = fo.currentTurn()
    ships_needed = 0
    defense_ships_needed = 0
    ships_needed_allocation = []
    for sys_id in my_systems.union(target_systems):
        status = aistate.systemStatus.get(sys_id, {})
        my_rating = status.get("myFleetRating", 0)
        my_defenses = status.get("mydefenses", {}).get("overall", 0)
        base_monster_threat = status.get("monsterThreat", 0)
        # scale monster threat so that in early - mid game big monsters don't over-drive military production
        monster_threat = base_monster_threat
        if current_turn > 200:
            pass
        elif current_turn > 100:
            if base_monster_threat >= 2000:
                monster_threat = 2000 + (current_turn / 100.0 -
                                         1) * (base_monster_threat - 2000)
        elif current_turn > 30:
            if base_monster_threat >= 2000:
                monster_threat = 0
        else:
            if base_monster_threat > 200:
                monster_threat = 0
        if sys_id in my_systems:
            threat_root = (status.get("fleetThreat", 0)**0.5 +
                           0.8 * status.get("max_neighbor_threat", 0)**0.5 +
                           0.2 * status.get("neighborThreat", 0)**0.5 +
                           monster_threat**0.5 +
                           status.get("planetThreat", 0)**0.5)
        else:
            threat_root = (status.get("fleetThreat", 0)**0.5 +
                           monster_threat**0.5 +
                           status.get("planetThreat", 0)**0.5)
        ships_needed_here = math.ceil(
            (max(0, (threat_root - (my_rating**0.5 + my_defenses**0.5)))**2) /
            cur_ship_rating)
        ships_needed += ships_needed_here
        ships_needed_allocation.append(
            (universe.getSystem(sys_id), ships_needed_here))
        if sys_id in my_systems:
            defense_ships_needed += ships_needed_here

    part1 = min(1 * fo.currentTurn(), 40)
    part2 = max(0, int(75 * ships_needed))
    military_priority = part1 + part2
    if not have_l1_weaps:
        military_priority /= 2.0
    elif not (have_l2_weaps and enemies_sighted):
        military_priority /= 1.5
    fmt_string = "Calculating Military Priority:  min(t,40) + max(0,75 * ships_needed) \n\t  Priority: %d  \t ships_needed: %d \t defense_ships_needed: %d \t curShipRating: %.0f \t l1_weaps: %s \t enemies_sighted: %s"
    debug(fmt_string % (military_priority, ships_needed, defense_ships_needed,
                        cur_ship_rating, have_l1_weaps, enemies_sighted))
    debug("Source of milship demand: %s" % ships_needed_allocation)

    military_priority *= aistate.character.military_priority_scaling()
    return max(military_priority, 0)
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 = get_species_tag_value(species_name, Tags.INDUSTRY)
    res_tag_mod = get_species_tag_value(species_name, Tags.RESEARCH)
    if species:
        supply_tag_mod = get_species_tag_value(species_name, Tags.SUPPLY)
    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
    detail.append("star_bonus=%.1f" % 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:
            retval = (retval + existing_presence *
                      _get_defense_value(species_name)) * 1.5
            detail.append("preexisting system colony => %.1f" % retval)

        # 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)
        # temp hack, AI builds too many colonies on tiny planets, reduce supply val
        supply_val *= 0.5
        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)

        infl_val = rate_influence(planet, species, max_pop_size)
        detail.append("infl_val %.1f" % infl_val)

        retval += (max(ind_val + asteroid_bonus + gas_giant_bonus,
                       research_bonus, growth_val, infl_val) + fixed_ind +
                   fixed_res + supply_val)
        detail.append(
            f" max({ind_val:.1f}+{asteroid_bonus:.1f}+{gas_giant_bonus:.1f},"
            f" {research_bonus:.1f}, {growth_val:.1f}, {infl_val:.1f})"
            f" + {fixed_ind:.1f} + {fixed_res:.1f} + {supply_val:.1f}")
        if existing_presence:
            retval = (retval +
                      existing_presence * _get_defense_value(species_name)) * 2
            detail.append("preexisting system colony => %.1f" % retval)
        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
Beispiel #37
0
def assign_scouts_to_explore_systems():
    # TODO: use Graph Theory to explore closest systems
    universe = fo.getUniverse()
    capital_sys_id = PlanetUtilsAI.get_capital_sys_id()
    # order fleets to explore
    if not border_unexplored_system_ids or (capital_sys_id == INVALID_ID):
        return
    exp_systems_by_dist = sorted(
        (universe.linearDistance(capital_sys_id, x), x)
        for x in border_unexplored_system_ids)
    print "Exploration system considering following system-distance pairs:\n  %s" % (
        "\n  ".join("%3d: %5.1f" % (sys_id, dist)
                    for (dist, sys_id) in exp_systems_by_dist))
    explore_list = [sys_id for dist, sys_id in exp_systems_by_dist]

    already_covered, available_scouts = get_current_exploration_info()

    print "Explorable system IDs: %s" % explore_list
    print "Already targeted: %s" % already_covered
    needs_vis = foAI.foAIstate.misc.setdefault('needs_vis', [])
    check_list = foAI.foAIstate.needsEmergencyExploration + needs_vis + explore_list
    if INVALID_ID in check_list:  # shouldn't normally happen, unless due to bug elsewhere
        for sys_list, name in [(foAI.foAIstate.needsEmergencyExploration,
                                "foAI.foAIstate.needsEmergencyExploration"),
                               (needs_vis, "needs_vis"),
                               (explore_list, "explore_list")]:
            if INVALID_ID in sys_list:
                error("INVALID_ID found in " + name, exc_info=True)
    # emergency coverage can be due to invasion detection trouble, etc.
    needs_coverage = [
        sys_id for sys_id in check_list
        if sys_id not in already_covered and sys_id != INVALID_ID
    ]
    print "Needs coverage: %s" % needs_coverage

    print "Available scouts & AIstate locs: %s" % [
        (x, foAI.foAIstate.fleetStatus.get(x, {}).get('sysID', INVALID_ID))
        for x in available_scouts
    ]
    print "Available scouts & universe locs: %s" % [
        (x, universe.getFleet(x).systemID) for x in available_scouts
    ]
    if not needs_coverage or not available_scouts:
        return

    available_scouts = set(available_scouts)
    sent_list = []
    while available_scouts and needs_coverage:
        this_sys_id = needs_coverage.pop(0)
        sys_status = foAI.foAIstate.systemStatus.setdefault(this_sys_id, {})
        if this_sys_id not in explore_list:  # doesn't necessarily need direct visit
            if universe.getVisibility(this_sys_id,
                                      fo.empireID()) >= fo.visibility.partial:
                # already got visibility; remove from visit lists and skip
                if this_sys_id in needs_vis:
                    del needs_vis[needs_vis.index(this_sys_id)]
                if this_sys_id in foAI.foAIstate.needsEmergencyExploration:
                    del foAI.foAIstate.needsEmergencyExploration[
                        foAI.foAIstate.needsEmergencyExploration.index(
                            this_sys_id)]
                print "system id %d already currently visible; skipping exploration" % this_sys_id
                continue
        # TODO: if blocked byu monster, try to find nearby system from which to see this system
        if (not foAI.foAIstate.character.may_explore_system(
                sys_status.setdefault('monsterThreat', 0)) or
            (fo.currentTurn() < 20 and
             foAI.foAIstate.systemStatus[this_sys_id]['monsterThreat'] > 200)):
            print "Skipping exploration of system %d due to Big Monster, threat %d" % (
                this_sys_id,
                foAI.foAIstate.systemStatus[this_sys_id]['monsterThreat'])
            continue
        this_fleet_list = FleetUtilsAI.get_fleets_for_mission(
            target_stats={},
            min_stats={},
            cur_stats={},
            starting_system=this_sys_id,
            fleet_pool_set=available_scouts,
            fleet_list=[])
        if not this_fleet_list:
            print "Seem to have run out of scouts while trying to cover sys_id %d" % this_sys_id
            break  # must have ran out of scouts
        fleet_id = this_fleet_list[0]
        fleet_mission = foAI.foAIstate.get_fleet_mission(fleet_id)
        target = universe_object.System(this_sys_id)
        if MoveUtilsAI.can_travel_to_system_and_return_to_resupply(
                fleet_id, fleet_mission.get_location_target(), target):
            fleet_mission.set_target(MissionType.EXPLORATION, target)
            sent_list.append(this_sys_id)
        else:  # system too far out, skip it, but can add scout back to available pool
            print "sys_id %d too far out for fleet ( ID %d ) to reach" % (
                this_sys_id, fleet_id)
            available_scouts.update(this_fleet_list)
    print "Sent scouting fleets to sysIDs : %s" % sent_list
    return
    # pylint: disable=pointless-string-statement
    """
Beispiel #38
0
def set_planet_resource_foci():
    """set resource focus of planets """
    newFoci = {}

    print "\n============================"
    print "Collecting info to assess Planet Focus Changes\n"
    universe = fo.getUniverse()
    empire = fo.getEmpire()
    currentTurn = fo.currentTurn()
    # set the random seed (based on galaxy seed, empire ID and current turn)
    # for game-reload consistency
    freq = min(3, (max(5, currentTurn - 80)) / 4.0)**(1.0 / 3)
    if not (limitAssessments and
            (abs(currentTurn - lastFociCheck[0]) < 1.5 * freq) and
            (random.random() < 1.0 / freq)):
        lastFociCheck[0] = currentTurn
        resource_timer.start("getPlanets")
        empirePlanetIDs = list(
            PlanetUtilsAI.get_owned_planets_by_empire(universe.planetIDs))
        resource_timer.start("Filter")
        resource_timer.start("Priority")
        # TODO: take into acct splintering of resource groups
        # fleetSupplyableSystemIDs = empire.fleetSupplyableSystemIDs
        # fleetSupplyablePlanetIDs = PlanetUtilsAI.get_planets_in__systems_ids(fleetSupplyableSystemIDs)
        ppPrio = foAI.foAIstate.get_priority(
            AIPriorityType.PRIORITY_RESOURCE_PRODUCTION)
        rpPrio = foAI.foAIstate.get_priority(
            AIPriorityType.PRIORITY_RESOURCE_RESEARCH)
        priorityRatio = float(rpPrio) / (ppPrio + 0.0001)
        resource_timer.start("Shuffle")
        # not supporting Growth for general planets until also adding code to make sure would actually benefit
        # shuffle(generalPlanetIDs)
        resource_timer.start("Targets")
        planets = map(universe.getPlanet, empirePlanetIDs)
        planetMap.clear()
        planetMap.update(zip(empirePlanetIDs, planets))
        if useGrowth:
            for metab, metabIncPop in ColonisationAI.empire_metabolisms.items(
            ):
                for special in [
                        aspec
                        for aspec in AIDependencies.metabolismBoostMap.get(
                            metab, [])
                        if aspec in ColonisationAI.available_growth_specials
                ]:
                    rankedPlanets = []
                    for pid in ColonisationAI.available_growth_specials[
                            special]:
                        planet = planetMap[pid]
                        cur_focus = planet.focus
                        pop = planet.currentMeterValue(fo.meterType.population)
                        if (pop > metabIncPop - 2 * planet.size) or (
                                GFocus not in planet.availableFoci
                        ):  # not enough benefit to lose local production, or can't put growth focus here
                            continue
                        for special2 in ["COMPUTRONIUM_SPECIAL"]:
                            if special2 in planet.specials:
                                break
                        else:  # didn't have any specials that would override interest in growth special
                            print "Considering Growth Focus for %s (%d) with special %s; planet has pop %.1f and %s metabolism incremental pop is %.1f" % (
                                planet.name, pid, special, pop, metab,
                                metabIncPop)
                            if cur_focus == GFocus:
                                pop -= 4  # discourage changing current focus to minimize focus-changing penalties
                            rankedPlanets.append((pop, pid, cur_focus))
                    if not rankedPlanets:
                        continue
                    rankedPlanets.sort()
                    print "Considering Growth Focus choice for special %s; possible planet pop, id pairs are %s" % (
                        metab, rankedPlanets)
                    for spSize, spPID, cur_focus in rankedPlanets:  # index 0 should be able to set focus, but just in case...
                        result = 1
                        if cur_focus != GFocus:
                            result = fo.issueChangeFocusOrder(spPID, GFocus)
                        if result == 1:
                            newFoci[spPID] = GFocus
                            if spPID in empirePlanetIDs:
                                del empirePlanetIDs[empirePlanetIDs.index(
                                    spPID)]
                            print "%s focus of planet %s (%d) at Growth Focus" % (
                                ["set", "left"][cur_focus == GFocus],
                                planetMap[spPID].name, spPID)
                            break
                        else:
                            print "failed setting focus of planet %s (%d) at Growth Focus; focus left at %s" % (
                                planetMap[spPID].name, spPID,
                                planetMap[spPID].focus)
        already_have_comp_moon = False
        for pid in empirePlanetIDs:
            planet = planetMap[pid]
            if "COMPUTRONIUM_SPECIAL" in planet.specials and RFocus in planet.availableFoci and not already_have_comp_moon:
                curFocus = planet.focus
                newFoci[pid] = RFocus
                result = 0
                if curFocus != RFocus:
                    result = fo.issueChangeFocusOrder(pid, RFocus)
                    if result == 1:
                        universe.updateMeterEstimates(empirePlanetIDs)
                if curFocus == RFocus or result == 1:
                    already_have_comp_moon = True
                    print "%s focus of planet %s (%d) (with Computronium Moon) at Research Focus" % (
                        ["set", "left"
                         ][curFocus == RFocus], planetMap[pid].name, pid)
                    if pid in empirePlanetIDs:
                        del empirePlanetIDs[empirePlanetIDs.index(pid)]
                    continue
            if ((([
                    bld.buildingTypeName
                    for bld in map(universe.getObject, planet.buildingIDs)
                    if bld.buildingTypeName in
                ["BLD_CONC_CAMP", "BLD_CONC_CAMP_REMNANT"]
            ] != []) or ([
                    ccspec for ccspec in planet.specials if ccspec in
                ["CONC_CAMP_MASTER_SPECIAL", "CONC_CAMP_SLAVE_SPECIAL"]
            ] != [])) and IFocus in planet.availableFoci):
                curFocus = planet.focus
                newFoci[pid] = IFocus
                result = 0
                if curFocus != IFocus:
                    result = fo.issueChangeFocusOrder(pid, IFocus)
                    if result == 1:
                        print(
                            "Tried setting %s for Concentration Camp planet %s (%d) with species %s and current focus %s, got result %d and focus %s"
                            % (newFoci[pid], planet.name, pid,
                               planet.speciesName, curFocus, result,
                               planetMap[pid].focus))
                        universe.updateMeterEstimates(empirePlanetIDs)
                    if (result != 1) or planetMap[pid].focus != IFocus:
                        newplanet = universe.getPlanet(pid)
                        print(
                            "Error: Failed setting %s for Concentration Camp planet %s (%d) with species %s and current focus %s, but new planet copy shows %s"
                            % (newFoci[pid], planetMap[pid].name, pid,
                               planetMap[pid].speciesName,
                               planetMap[pid].focus, newplanet.focus))
                if curFocus == IFocus or result == 1:
                    print "%s focus of planet %s (%d) (with Concentration Camps/Remnants) at Industry Focus" % (
                        ["set", "left"
                         ][curFocus == IFocus], planetMap[pid].name, pid)
                    if pid in empirePlanetIDs:
                        del empirePlanetIDs[empirePlanetIDs.index(pid)]
                    continue
            # TODO: Was getting a key error mid-game without the below check for "pid in currentOutput" -- needs further investigation
            if pid in currentOutput and PFocus in planet.availableFoci and assess_protection_focus(
                    pid):
                curFocus = planet.focus
                newFoci[pid] = PFocus
                result = 0
                if curFocus != PFocus:
                    result = fo.issueChangeFocusOrder(pid, PFocus)
                    if result == 1:
                        print(
                            "Tried setting %s for planet %s (%d) with species %s and current focus %s, got result %d and focus %s"
                            % (newFoci[pid], planet.name, pid,
                               planet.speciesName, curFocus, result,
                               planetMap[pid].focus))
                        universe.updateMeterEstimates(empirePlanetIDs)
                    if (result != 1) or planetMap[pid].focus != PFocus:
                        newplanet = universe.getPlanet(pid)
                        print(
                            "Error: Failed setting %s for planet %s (%d) with species %s and current focus %s, but new planet copy shows %s"
                            % (newFoci[pid], planetMap[pid].name, pid,
                               planetMap[pid].speciesName,
                               planetMap[pid].focus, newplanet.focus))
                if curFocus == PFocus or result == 1:
                    print "%s focus of planet %s (%d) at Protection(Defense) Focus" % (
                        ["set", "left"
                         ][curFocus == PFocus], planetMap[pid].name, pid)
                    if pid in empirePlanetIDs:
                        del empirePlanetIDs[empirePlanetIDs.index(pid)]
                    continue

        # pp, rp = get_resource_target_totals(empirePlanetIDs, planetMap)
        pp, rp = get_resource_target_totals(planetMap.keys())
        print "\n-----------------------------------------"
        print "Making Planet Focus Change Determinations\n"

        ratios = []
        # for each planet, calculate RP:PP value ratio at which industry/Mining focus and research focus would have the same total value, & sort by that
        # include a bias to slightly discourage changing foci
        curTargetPP = 0.001
        curTargetRP = 0.001
        resource_timer.start("Loop")  # loop
        has_force = tech_is_complete("CON_FRC_ENRG_STRC")
        preset_ids = set(planetMap.keys()) - set(empirePlanetIDs)
        ctPP0, ctRP0 = 0, 0
        for pid in preset_ids:
            nPP, nRP = newTargets.get(pid, {}).get(planetMap[pid].focus,
                                                   [0, 0])
            curTargetPP += nPP
            curTargetRP += nRP
            iPP, iRP = newTargets.get(pid, {}).get(IFocus, [0, 0])
            ctPP0 += iPP
            ctRP0 += iRP

        id_set = set(empirePlanetIDs)
        for adj_round in [1, 2, 3, 4]:
            maxi_ratio = ctRP0 / max(
                0.01, ctPP0)  # should only change between rounds 1 and 2
            for pid in list(id_set):
                if adj_round == 1:  # tally max Industry
                    iPP, iRP = newTargets.get(pid, {}).get(IFocus, [0, 0])
                    ctPP0 += iPP
                    ctRP0 += iRP
                    continue
                II, IR = newTargets[pid][IFocus]
                RI, RR = newTargets[pid][RFocus]
                CI, CR = currentOutput[pid][IFocus], currentOutput[pid][RFocus]
                research_penalty = (currentFocus[pid] != RFocus)
                # calculate factor F at which II + F * IR == RI + F * RR =====> F = ( II-RI ) / (RR-IR)
                thisFactor = (II - RI) / max(
                    0.01, RR - IR
                )  # don't let denominator be zero for planets where focus doesn't change RP
                planet = planetMap[pid]
                if adj_round == 2:  # take research at planets with very cheap research
                    if (maxi_ratio < priorityRatio) and (
                            curTargetRP <
                            priorityRatio * ctPP0) and (thisFactor <= 1.0):
                        curTargetPP += RI
                        curTargetRP += RR
                        newFoci[pid] = RFocus
                        id_set.discard(pid)
                    continue
                if adj_round == 3:  # take research at planets where can do reasonable balance
                    if has_force or (foAI.foAIstate.aggression <
                                     fo.aggression.aggressive) or (
                                         curTargetRP >= priorityRatio * ctPP0):
                        continue
                    pop = planet.currentMeterValue(fo.meterType.population)
                    t_pop = planet.currentMeterValue(
                        fo.meterType.targetPopulation)
                    # if AI is aggressive+, and this planet in range where temporary Research focus can get an additional RP at cost of 1 PP, and still need some RP, then do it
                    if pop < t_pop - 5:
                        continue
                    if (CI > II + 8) or (((RR > II) or (
                        (RR - CR) >= 1 + 2 * research_penalty)) and
                                         ((RR - IR) >= 3) and
                                         ((CR - IR) >= 0.7 *
                                          ((II - CI) *
                                           (1 + 0.1 * research_penalty)))):
                        curTargetPP += CI - 1 - research_penalty
                        curTargetRP += CR + 1
                        newFoci[pid] = RFocus
                        id_set.discard(pid)
                    continue
                # adj_round == 4 assume default IFocus
                curTargetPP += II  # icurTargets initially calculated by Industry focus, which will be our default focus
                curTargetRP += IR
                newFoci[pid] = IFocus
                ratios.append((thisFactor, pid))

        ratios.sort()
        printedHeader = False
        fociMap = {
            IFocus: "Industry",
            RFocus: "Research",
            MFocus: "Mining",
            GFocus: "Growth",
            PFocus: "Defense"
        }
        gotAlgo = tech_is_complete("LRN_ALGO_ELEGANCE")
        for ratio, pid in ratios:
            do_research = False  # (newFoci[pid]==RFocus)
            if (priorityRatio < (curTargetRP / (curTargetPP + 0.0001))
                ) and not do_research:  # we have enough RP
                if ratio < 1.1 and foAI.foAIstate.aggression > fo.aggression.cautious:  # but wait, RP is still super cheap relative to PP, maybe will take more RP
                    if priorityRatio < 1.5 * (
                            curTargetRP / (curTargetPP + 0.0001)
                    ):  # yeah, really a glut of RP, stop taking RP
                        break
                else:  # RP not super cheap & we have enough, stop taking it
                    break
            II, IR = newTargets[pid][IFocus]
            RI, RR = newTargets[pid][RFocus]
            # if currentFocus[pid] == MFocus:
            # II = max( II, newTargets[pid][MFocus][0] )
            if do_research or (
                    gotAlgo and
                ((ratio > 2.0 and curTargetPP < 15) or
                 (ratio > 2.5 and curTargetPP < 25 and II > 5) or
                 (ratio > 3.0 and curTargetPP < 40 and II > 5) or
                 (ratio > 4.0 and curTargetPP < 100 and II > 10) or
                 ((curTargetRP + RR - IR) / max(0.001, curTargetPP - II + RI) >
                  2 * priorityRatio))
            ):  # we already have algo elegance and more RP would be too expensive, or overkill
                if not printedHeader:
                    printedHeader = True
                    print "Rejecting further Research Focus choices as too expensive:"
                    print "%34s|%20s|%15s |%15s|%15s |%15s |%15s" % (
                        "                      Planet ", " current RP/PP ",
                        " current target RP/PP ", "current Focus ",
                        "  rejectedFocus ", " rejected target RP/PP ",
                        "rejected RP-PP EQF")
                    oldFocus = currentFocus[pid]
                    cPP, cRP = currentOutput[pid][IFocus], currentOutput[pid][
                        RFocus]
                    otPP, otRP = newTargets[pid].get(oldFocus, (0, 0))
                    ntPP, ntRP = newTargets[pid].get(RFocus, (0, 0))
                    print "pID (%3d) %22s | c: %5.1f / %5.1f | cT: %5.1f / %5.1f |  cF: %8s | nF: %8s | cT: %5.1f / %5.1f | %.2f" % (
                        pid, planetMap[pid].name, cRP, cPP, otRP, otPP,
                        fociMap.get(oldFocus, 'unknown'), fociMap[RFocus],
                        ntRP, ntPP, ratio)
                    continue  # RP is getting too expensive, but might be willing to still allocate from a planet with less PP to lose
            # if planetMap[pid].currentMeterValue(fo.meterType.targetPopulation) >0: #only set to research if pop won't die out
            newFoci[pid] = RFocus
            curTargetRP += (RR - IR)
            curTargetPP -= (II - RI)
        print "============================"
        print "Planet Focus Assignments to achieve target RP/PP ratio of %.2f from current ratio of %.2f ( %.1f / %.1f )" % (
            priorityRatio, rp / (pp + 0.0001), rp, pp)
        print "Max Industry assignments would result in target RP/PP ratio of %.2f ( %.1f / %.1f )" % (
            ctRP0 / (ctPP0 + 0.0001), ctRP0, ctPP0)
        print "-------------------------------------"
        print "%34s|%20s|%15s |%15s|%15s |%15s " % (
            "                      Planet ", " current RP/PP ",
            " current target RP/PP ", "current Focus ", "  newFocus ",
            " new target RP/PP ")
        totalChanged = 0
        for id_set in empirePlanetIDs, preset_ids:
            for pid in id_set:
                canFocus = planetMap[pid].currentMeterValue(
                    fo.meterType.targetPopulation) > 0
                oldFocus = currentFocus[pid]
                newFocus = newFoci.get(pid, IFocus)
                cPP, cRP = currentOutput[pid][IFocus], currentOutput[pid][
                    RFocus]
                otPP, otRP = newTargets[pid].get(oldFocus, (0, 0))
                ntPP, ntRP = otPP, otRP
                if newFocus != oldFocus and newFocus in planetMap[
                        pid].availableFoci:  # planetMap[pid].focus
                    totalChanged += 1
                    if newFocus != planetMap[pid].focus:
                        result = fo.issueChangeFocusOrder(pid, newFocus)
                        if result == 1:
                            ntPP, ntRP = newTargets[pid].get(newFocus, (0, 0))
                        else:
                            print "Trouble changing focus of planet %s (%d) to %s" % (
                                planetMap[pid].name, pid, newFocus)
                print "pID (%3d) %22s | c: %5.1f / %5.1f | cT: %5.1f / %5.1f |  cF: %8s | nF: %8s | cT: %5.1f / %5.1f " % (
                    pid, planetMap[pid].name, cRP, cPP, otRP, otPP,
                    fociMap.get(oldFocus,
                                'unknown'), fociMap[newFocus], ntRP, ntPP)
            print "-------------------------------------"
        print "-------------------------------------"
        print "Final Ratio Target (turn %4d) RP/PP : %.2f ( %.1f / %.1f ) after %d Focus changes" % (
            fo.currentTurn(), curTargetRP /
            (curTargetPP + 0.0001), curTargetRP, curTargetPP, totalChanged)
        resource_timer.end()
    aPP, aRP = empire.productionPoints, empire.resourceProduction(
        fo.resourceType.research)
    # Next string used in charts. Don't modify it!
    print "Current Output (turn %4d) RP/PP : %.2f ( %.1f / %.1f )" % (
        fo.currentTurn(), aRP / (aPP + 0.0001), aRP, aPP)
    print "------------------------"
    print "ResourcesAI Time Requirements:"
Beispiel #39
0
def assign_scouts_to_explore_systems():
    # TODO: use Graph Theory to explore closest systems
    universe = fo.getUniverse()
    capital_sys_id = PlanetUtilsAI.get_capital_sys_id()
    # order fleets to explore
    if not border_unexplored_system_ids or (capital_sys_id == INVALID_ID):
        return
    exp_systems_by_dist = sorted(
        (universe.linearDistance(capital_sys_id, x), x)
        for x in border_unexplored_system_ids)
    debug(
        "Exploration system considering following system-distance pairs:\n  %s"
        % ("\n  ".join("%3d: %5.1f" % (sys_id, dist)
                       for (dist, sys_id) in exp_systems_by_dist)))
    explore_list = [sys_id for dist, sys_id in exp_systems_by_dist]

    already_covered, available_scouts = get_current_exploration_info()

    debug("Explorable system IDs: %s" % explore_list)
    debug("Already targeted: %s" % already_covered)
    aistate = get_aistate()
    needs_vis = aistate.misc.setdefault("needs_vis", [])
    check_list = aistate.needsEmergencyExploration + needs_vis + explore_list
    if INVALID_ID in check_list:  # shouldn't normally happen, unless due to bug elsewhere
        for sys_list, name in [
            (aistate.needsEmergencyExploration,
             "aistate.needsEmergencyExploration"),
            (needs_vis, "needs_vis"),
            (explore_list, "explore_list"),
        ]:
            if INVALID_ID in sys_list:
                error("INVALID_ID found in " + name, exc_info=True)
    # emergency coverage can be due to invasion detection trouble, etc.
    debug("Check list: %s" % check_list)
    needs_coverage = [
        sys_id for sys_id in check_list
        if sys_id not in already_covered and sys_id != INVALID_ID
    ]
    debug("Needs coverage: %s" % needs_coverage)

    debug("Available scouts & AIstate locs: %s" %
          [(x, aistate.fleetStatus.get(x, {}).get("sysID", INVALID_ID))
           for x in available_scouts])
    debug("Available scouts & universe locs: %s" %
          [(x, universe.getFleet(x).systemID) for x in available_scouts])
    if not needs_coverage or not available_scouts:
        return

    # clean up targets which can not or don't need to be scouted
    for sys_id in list(needs_coverage):
        if sys_id not in explore_list:  # doesn't necessarily need direct visit
            if universe.getVisibility(sys_id,
                                      fo.empireID()) >= fo.visibility.partial:
                # already got visibility; remove from visit lists and skip
                if sys_id in needs_vis:
                    del needs_vis[needs_vis.index(sys_id)]
                if sys_id in aistate.needsEmergencyExploration:
                    del aistate.needsEmergencyExploration[
                        aistate.needsEmergencyExploration.index(sys_id)]
                debug(
                    "system id %d already currently visible; skipping exploration"
                    % sys_id)
                needs_coverage.remove(sys_id)
                continue

        # skip systems threatened by monsters
        sys_status = aistate.systemStatus.setdefault(sys_id, {})
        if not aistate.character.may_explore_system(
                sys_status.setdefault("monsterThreat", 0)) or (
                    fo.currentTurn() < 20
                    and aistate.systemStatus[sys_id]["monsterThreat"] > 0):
            debug(
                "Skipping exploration of system %d due to Big Monster, threat %d"
                % (sys_id, aistate.systemStatus[sys_id]["monsterThreat"]))
            needs_coverage.remove(sys_id)
            continue

    # find the jump distance for all possible scout-system pairings
    options = []
    available_scouts = set(available_scouts)
    for fleet_id in available_scouts:
        start = TargetSystem(get_fleet_position(fleet_id))
        for sys_id in needs_coverage:
            target = TargetSystem(sys_id)
            path = MoveUtilsAI.can_travel_to_system(fleet_id,
                                                    start,
                                                    target,
                                                    ensure_return=True)
            if not path:
                continue
            num_jumps = len(
                path) - 1  # -1 as path contains the original system
            options.append((num_jumps, fleet_id, sys_id))

    # Apply a simple, greedy heuristic to match scouts to nearby systems:
    # Always choose the shortest possible path from the remaining scout-system pairing.
    # This is clearly not optimal in the general case but it works well enough for now.
    # TODO: Consider using a more sophisticated assignment algorithm
    options.sort()
    while options:
        debug("Remaining options: %s" % options)
        _, fleet_id, sys_id = options[0]
        fleet_mission = aistate.get_fleet_mission(fleet_id)
        target = TargetSystem(sys_id)
        info("Sending fleet %d to explore %s" % (fleet_id, target))
        fleet_mission.set_target(MissionType.EXPLORATION, target)
        options = [
            option for option in options
            if option[1] != fleet_id and option[2] != sys_id
        ]
        available_scouts.remove(fleet_id)
        needs_coverage.remove(sys_id)

    debug("Exploration assignment finished.")
    debug("Unassigned scouts: %s" % available_scouts)
    debug("Unassigned exploration targets: %s" % needs_coverage)
Beispiel #40
0
def generateOrders():  # pylint: disable=invalid-name
    """Called once per turn to tell the Python AI to generate and issue orders to control its empire.
    at end of this function, fo.doneTurn() should be called to indicate to the client that orders are finished
    and can be sent to the server for processing."""
    empire = fo.getEmpire()
    if empire is None:
        print "This client has no empire. Doing nothing to generate orders."
        try:
            # early abort if no empire. no need to do meter calculations
            # on last-seen gamestate if nothing can be ordered anyway...
            #
            # note that doneTurn() is issued on behalf of the client network
            # id, not the empire id, so not having a correct empire id does
            # not invalidate doneTurn()
            fo.doneTurn()
        except Exception as e:
            print_error(e)
        return

    if empire.eliminated:
        print "This empire has been eliminated. Aborting order generation"
        try:
            # early abort if already eliminated. no need to do meter calculations
            # on last-seen gamestate if nothing can be ordered anyway...
            fo.doneTurn()
        except Exception as e:
            print_error(e)
        return

    # This code block is required for correct AI work.
    print "Meter / Resource Pool updating..."
    fo.initMeterEstimatesDiscrepancies()
    fo.updateMeterEstimates(False)
    fo.updateResourcePools()

    turn = fo.currentTurn()
    turn_uid = foAIstate.set_turn_uid()
    print "\n\n\n", "=" * 20,
    print "Starting turn %s (%s) of game: %s" % (turn, turn_uid,
                                                 foAIstate.uid),
    print "=" * 20, "\n"

    turn_timer.start("AI planning")
    # set the random seed (based on galaxy seed, empire name and current turn)
    # for game-reload consistency.
    random_seed = str(
        fo.getGalaxySetupData().seed) + "%05d%s" % (turn, fo.getEmpire().name)
    random.seed(random_seed)

    universe = fo.getUniverse()
    empire = fo.getEmpire()
    planet_id = PlanetUtilsAI.get_capital()
    planet = None
    if planet_id is not None:
        planet = universe.getPlanet(planet_id)
    aggression_name = get_trait_name_aggression(foAIstate.character)
    print "***************************************************************************"
    print "*******  Log info for AI progress chart script. Do not modify.   **********"
    print("Generating Orders")
    print(
        "EmpireID: {empire.empireID}"
        " Name: {empire.name}_{empire.empireID}_pid:{p_id}_{p_name}RIdx_{res_idx}_{aggression}"
        " Turn: {turn}").format(empire=empire,
                                p_id=fo.playerID(),
                                p_name=fo.playerName(),
                                res_idx=ResearchAI.get_research_index(),
                                turn=turn,
                                aggression=aggression_name.capitalize())
    print "EmpireColors: {0.colour.r} {0.colour.g} {0.colour.b} {0.colour.a}".format(
        empire)
    if planet:
        print "CapitalID: " + str(
            planet_id
        ) + " Name: " + planet.name + " Species: " + planet.speciesName
    else:
        print "CapitalID: None Currently Name: None Species: None "
    print "***************************************************************************"
    print "***************************************************************************"

    if turn == 1:
        declare_war_on_all()
        human_player = fo.empirePlayerID(1)
        greet = diplomatic_corp.get_first_turn_greet_message()
        fo.sendChatMessage(
            human_player, '%s (%s): [[%s]]' %
            (empire.name, get_trait_name_aggression(
                foAIstate.character), greet))

    # turn cleanup !!! this was formerly done at start of every turn -- not sure why
    foAIstate.split_new_fleets()

    foAIstate.refresh(
    )  # checks exploration border & clears roles/missions of missing fleets & updates fleet locs & threats
    foAIstate.report_system_threats()
    print("Calling AI Modules")
    # call AI modules
    action_list = [
        ColonisationAI.survey_universe,
        ProductionAI.find_best_designs_this_turn,
        PriorityAI.calculate_priorities,
        ExplorationAI.assign_scouts_to_explore_systems,
        ColonisationAI.assign_colony_fleets_to_colonise,
        InvasionAI.assign_invasion_fleets_to_invade,
        MilitaryAI.assign_military_fleets_to_systems,
        FleetUtilsAI.generate_fleet_orders_for_fleet_missions,
        FleetUtilsAI.issue_fleet_orders_for_fleet_missions,
        ResearchAI.generate_research_orders,
        ProductionAI.generate_production_orders,
        ResourcesAI.generate_resources_orders,
    ]

    for action in action_list:
        try:
            main_timer.start(action.__name__)
            action()
            main_timer.stop()
        except Exception as e:
            print_error(e, location=action.__name__)
    main_timer.stop_print_and_clear()
    turn_timer.stop_print_and_clear()
    turn_timer.start("Server_Processing")

    try:
        fo.doneTurn()
    except Exception as e:
        print_error(e)  # TODO move it to cycle above

    if using_statprof:
        try:
            statprof.stop()
            statprof.display()
            statprof.start()
        except:
            pass
Beispiel #41
0
def send_colony_ships(colony_fleet_ids, evaluated_planets, mission_type):
    """sends a list of colony ships to a list of planet_value_pairs"""
    fleet_pool = colony_fleet_ids[:]
    try_all = False
    if mission_type == MissionType.OUTPOST:
        cost = 20 + outpod_pod_cost()
    else:
        try_all = True
        cost = 20 + colony_pod_cost_turns()[1]
        if fo.currentTurn() < 50:
            cost *= 0.4  # will be making fast tech progress so value is underestimated
        elif fo.currentTurn() < 80:
            cost *= 0.8  # will be making fast-ish tech progress so value is underestimated

    potential_targets = [
        (pid, (score, specName))
        for (pid, (score, specName)) in evaluated_planets
        if score > (0.8 * cost) and score > MINIMUM_COLONY_SCORE
    ]

    debug("Colony/outpost ship matching: fleets %s to planets %s" % (fleet_pool, evaluated_planets))

    if try_all:
        debug("Trying best matches to current colony ships")
        best_scores = dict(evaluated_planets)
        potential_targets = []
        for pid, ratings in _all_colony_opportunities.items():
            for rating in ratings:
                if rating[0] >= 0.75 * best_scores.get(pid, [9999])[0]:
                    potential_targets.append((pid, rating))
        potential_targets.sort(key=itemgetter(1), reverse=True)

    # added a lot of checking because have been getting mysterious exception, after too many recursions to get info
    fleet_pool = set(fleet_pool)
    universe = fo.getUniverse()
    for fid in fleet_pool:
        fleet = universe.getFleet(fid)
        if not fleet or fleet.empty:
            warning("Bad fleet ( ID %d ) given to colonization routine; will be skipped" % fid)
            fleet_pool.remove(fid)
            continue
        report_str = "Fleet ID (%d): %d ships; species: " % (fid, fleet.numShips)
        for sid in fleet.shipIDs:
            ship = universe.getShip(sid)
            if not ship:
                report_str += "NoShip, "
            else:
                report_str += "%s, " % ship.speciesName
        debug(report_str)
    debug("")
    already_targeted = []
    # for planetID_value_pair in evaluatedPlanets:
    aistate = get_aistate()
    while fleet_pool and potential_targets:
        target = potential_targets.pop(0)
        if target in already_targeted:
            continue
        planet_id = target[0]
        if planet_id in already_targeted:
            continue
        planet = universe.getPlanet(planet_id)
        sys_id = planet.systemID
        if (
            aistate.systemStatus.setdefault(sys_id, {}).setdefault("monsterThreat", 0) > 2000
            or fo.currentTurn() < 20
            and aistate.systemStatus[sys_id]["monsterThreat"] > 200
        ):
            debug(
                "Skipping colonization of system %s due to Big Monster, threat %d"
                % (universe.getSystem(sys_id), aistate.systemStatus[sys_id]["monsterThreat"])
            )
            already_targeted.append(planet_id)
            continue

        # make sure not to run into stationary guards
        if ExplorationAI.system_could_have_unknown_stationary_guard(sys_id):
            ExplorationAI.request_emergency_exploration(sys_id)
            continue

        this_spec = target[1][1]
        found_fleets = []
        try:
            this_fleet_list = FleetUtilsAI.get_fleets_for_mission(
                target_stats={},
                min_stats={},
                cur_stats={},
                starting_system=sys_id,
                species=this_spec,
                fleet_pool_set=fleet_pool,
                fleet_list=found_fleets,
            )
        except Exception as e:
            error(e, exc_info=True)
            continue
        if not this_fleet_list:
            fleet_pool.update(found_fleets)  # just to be safe
            continue  # must have no compatible colony/outpost ships
        fleet_id = this_fleet_list[0]
        already_targeted.append(planet_id)
        ai_target = TargetPlanet(planet_id)
        aistate.get_fleet_mission(fleet_id).set_target(mission_type, ai_target)
Beispiel #42
0
def _calculate_industry_priority():  # currently only used to print status
    """calculates the demand for industry"""
    universe = fo.getUniverse()
    empire = fo.getEmpire()
    # get current industry production & Target
    industry_production = empire.resourceProduction(fo.resourceType.industry)
    owned_planet_ids = PlanetUtilsAI.get_owned_planets_by_empire(universe.planetIDs)
    planets = map(universe.getPlanet, owned_planet_ids)
    target_pp = sum(map(lambda x: x.currentMeterValue(fo.meterType.targetIndustry), planets))

    # currently, previously set to 50 in calculatePriorities(), this is just for reporting
    industry_priority = foAI.foAIstate.get_priority(PriorityType.RESOURCE_PRODUCTION)

    print
    print "Industry Production (current/target) : ( %.1f / %.1f ) at turn %s" % (industry_production, target_pp, fo.currentTurn())
    print "Priority for Industry: %s" % industry_priority
    return industry_priority
Beispiel #43
0
def _calculate_military_priority():
    """Calculates the demand for military ships by military targeted systems."""
    global unmetThreat

    universe = fo.getUniverse()
    capital_id = PlanetUtilsAI.get_capital()
    if capital_id is None or capital_id == -1:
        return 0  # no capitol (not even a capitol-in-the-making), means can't produce any ships
        
    have_l1_weaps = (tech_is_complete("SHP_WEAPON_1_4") or
                     (tech_is_complete("SHP_WEAPON_1_3") and tech_is_complete("SHP_MIL_ROBO_CONT")) or
                     tech_is_complete("SHP_WEAPON_2_1") or
                     tech_is_complete("SHP_WEAPON_4_1"))
    have_l2_weaps = (tech_is_complete("SHP_WEAPON_2_3") or
                     tech_is_complete("SHP_WEAPON_4_1"))
    enemies_sighted = foAI.foAIstate.misc.get('enemies_sighted', {})
        
    allotted_invasion_targets = 1 + int(fo.currentTurn()/25)
    target_planet_ids = [pid for pid, pscore, trp in AIstate.invasionTargets[:allotted_invasion_targets]] + [pid for pid, pscore in foAI.foAIstate.colonisablePlanetIDs.items()[:allottedColonyTargets]] + [pid for pid, pscore in foAI.foAIstate.colonisableOutpostIDs.items()[:allottedColonyTargets]]

    my_systems = set(AIstate.popCtrSystemIDs).union(AIstate.outpostSystemIDs)
    target_systems = set(PlanetUtilsAI.get_systems(target_planet_ids))

    cur_ship_rating = ProductionAI.cur_best_military_design_rating()
    current_turn = fo.currentTurn()
    ships_needed = 0
    defense_ships_needed = 0
    ships_needed_allocation = []
    for sys_id in my_systems.union(target_systems):
        status = foAI.foAIstate.systemStatus.get(sys_id, {})
        my_rating = status.get('myFleetRating', 0)
        my_defenses = status.get('mydefenses', {}).get('overall', 0)
        base_monster_threat = status.get('monsterThreat', 0)
        # scale monster threat so that in early - mid game big monsters don't over-drive military production
        monster_threat = base_monster_threat
        if current_turn > 200:
            pass
        elif current_turn > 100:
            if base_monster_threat >= 2000:
                monster_threat = 2000 + (current_turn / 100.0 - 1) * (base_monster_threat - 2000)
        elif current_turn > 30:
            if base_monster_threat >= 2000:
                monster_threat = 0
        else:
            if base_monster_threat > 200:
                monster_threat = 0
        if sys_id in my_systems:
            threat_root = status.get('fleetThreat', 0)**0.5 + 0.8*status.get('max_neighbor_threat', 0)**0.5 + 0.2*status.get('neighborThreat', 0)**0.5 + monster_threat**0.5 + status.get('planetThreat', 0)**0.5
        else:
            threat_root = status.get('fleetThreat', 0)**0.5 + monster_threat**0.5 + status.get('planetThreat', 0)**0.5
        ships_needed_here = math.ceil((max(0, (threat_root - (my_rating ** 0.5 + my_defenses ** 0.5))) ** 2) / cur_ship_rating)
        ships_needed += ships_needed_here
        ships_needed_allocation.append((universe.getSystem(sys_id), ships_needed_here))
        if sys_id in my_systems:
            defense_ships_needed += ships_needed_here

    part1 = min(1 * fo.currentTurn(), 40)
    part2 = max(0, int(75 * ships_needed))
    military_priority = part1 + part2
    if not have_l1_weaps:
        military_priority /= 2.0
    elif not (have_l2_weaps and enemies_sighted):
        military_priority /= 1.5
    fmt_string = "Calculating Military Priority:  min(t,40) + max(0,75 * ships_needed) \n\t  Priority: %d  \t ships_needed: %d \t defense_ships_needed: %d \t curShipRating: %.0f \t l1_weaps: %s \t enemies_sighted: %s"
    print fmt_string % (military_priority, ships_needed, defense_ships_needed, cur_ship_rating, have_l1_weaps, enemies_sighted)
    print "Source of milship demand: ", ships_needed_allocation
    
    if foAI.foAIstate.aggression < fo.aggression.typical:
        military_priority *= (1.0 + foAI.foAIstate.aggression) / (1.0 + fo.aggression.typical)
    return max(military_priority, 0)
Beispiel #44
0
def _calculate_invasion_priority():
    """Calculates the demand for troop ships by opponent planets."""
    
    global allottedInvasionTargets
    if foAI.foAIstate.aggression <= fo.aggression.turtle:
        return 0
    
    empire = fo.getEmpire()
    enemies_sighted = foAI.foAIstate.misc.get('enemies_sighted', {})
    multiplier = 1
    num_colonies = len(list(AIstate.popCtrIDs))
    if num_colonies > colony_growth_barrier:
        return 0.0
    
    if len(foAI.foAIstate.colonisablePlanetIDs) > 0:
        best_colony_score = max(2, foAI.foAIstate.colonisablePlanetIDs.items()[0][1][0])
    else:
        best_colony_score = 2

    if foAI.foAIstate.aggression == fo.aggression.beginner and fo.currentTurn() < 150:
        return 0

    allottedInvasionTargets = 1 + int(fo.currentTurn() / 25)
    total_val = 0
    troops_needed = 0
    for pid, pscore, trp in AIstate.invasionTargets[:allottedInvasionTargets]:
        if pscore > best_colony_score:
            multiplier += 1
            total_val += 2 * pscore
        else:
            total_val += pscore
        troops_needed += trp + 4  # ToDo: This seems like it could be improved by some dynamic calculation of buffer

    if total_val == 0:
        return 0

    production_queue = empire.productionQueue
    queued_troop_capacity = 0
    for queue_index in range(0, len(production_queue)):
        element = production_queue[queue_index]
        if element.buildType == EmpireProductionTypes.BT_SHIP:
            if foAI.foAIstate.get_ship_role(element.designID) in [ShipRoleType.MILITARY_INVASION,
                                                                  ShipRoleType.BASE_INVASION]:
                design = fo.getShipDesign(element.designID)
                queued_troop_capacity += element.remaining * element.blocksize * design.troopCapacity
    _, best_design, _ = ProductionAI.get_best_ship_info(PriorityType.PRODUCTION_INVASION)
    if best_design:
        troops_per_best_ship = best_design.troopCapacity
    else:
        return 1e-6  # if we can not build troop ships, we don't want to build (non-existing) invasion ships

    # don't count troop bases here as these cannot be redeployed after misplaning
    # troopFleetIDs = FleetUtilsAI.get_empire_fleet_ids_by_role(MissionType.INVASION)\
    #                 + FleetUtilsAI.get_empire_fleet_ids_by_role(MissionType.ORBITAL_INVASION)
    troop_fleet_ids = FleetUtilsAI.get_empire_fleet_ids_by_role(MissionType.INVASION)
    total_troop_capacity = sum([FleetUtilsAI.count_troops_in_fleet(fid) for fid in troop_fleet_ids])
    troop_ships_needed = \
        math.ceil((troops_needed - (total_troop_capacity + queued_troop_capacity)) / troops_per_best_ship)

    # invasion_priority = max( 10+ 200*max(0, troop_ships_needed ) , int(0.1* total_val) )
    invasion_priority = multiplier * (30 + 150*max(0, troop_ships_needed))
    if not ColonisationAI.colony_status.get('colonies_under_attack', []):
        if not ColonisationAI.colony_status.get('colonies_under_threat', []):
            invasion_priority *= 2.0
        else:
            invasion_priority *= 1.5
    if not enemies_sighted:
        invasion_priority *= 1.5
        
    if invasion_priority < 0:
        return 0
    if foAI.foAIstate.aggression == fo.aggression.beginner:
        return 0.5 * invasion_priority
    else:
        return invasion_priority
Beispiel #45
0
def generateOrders():  # pylint: disable=invalid-name
    """
    Called once per turn to tell the Python AI to generate
    and issue orders, i.e. to control its empire.

    After leaving this function, the AI's turn will be finished
    and its orders will be sent to the server.
    """
    try:
        rules = fo.getGameRules()
        debug("Defined game rules:")
        for rule_name, rule_value in rules.getRulesAsStrings().items():
            debug("%s: %s", rule_name, rule_value)
        debug("Rule RULE_NUM_COMBAT_ROUNDS value: " +
              str(rules.getInt("RULE_NUM_COMBAT_ROUNDS")))
    except Exception as e:
        error("Exception %s when trying to get game rules" % e, exc_info=True)

    # If nothing can be ordered anyway, exit early.
    # Note that there is no need to update meters etc. in this case.
    empire = fo.getEmpire()
    if empire is None:
        fatal("This client has no empire. Aborting order generation.")
        return

    if empire.eliminated:
        info("This empire has been eliminated. Aborting order generation.")
        return

    # This code block is required for correct AI work.
    info("Meter / Resource Pool updating...")
    fo.initMeterEstimatesDiscrepancies()
    fo.updateMeterEstimates(False)
    fo.updateResourcePools()

    turn = fo.currentTurn()
    aistate = get_aistate()
    turn_uid = aistate.set_turn_uid()
    debug("\n\n\n" + "=" * 20)
    debug("Starting turn %s (%s) of game: %s" % (turn, turn_uid, aistate.uid))
    debug("=" * 20 + "\n")

    turn_timer.start("AI planning")
    # set the random seed (based on galaxy seed, empire name and current turn)
    # for game-reload consistency.
    random_seed = str(
        fo.getGalaxySetupData().seed) + "%05d%s" % (turn, fo.getEmpire().name)
    random.seed(random_seed)

    universe = fo.getUniverse()
    empire = fo.getEmpire()
    planet_id = PlanetUtilsAI.get_capital()
    planet = None
    if planet_id is not None:
        planet = universe.getPlanet(planet_id)
    aggression_name = get_trait_name_aggression(aistate.character)
    debug(
        "***************************************************************************"
    )
    debug(
        "*******  Log info for AI progress chart script. Do not modify.   **********"
    )
    debug("Generating Orders")
    debug(
        "EmpireID: {empire.empireID}"
        " Name: {empire.name}_{empire.empireID}_pid:{p_id}_{p_name}RIdx_{res_idx}_{aggression}"
        " Turn: {turn}".format(empire=empire,
                               p_id=fo.playerID(),
                               p_name=fo.playerName(),
                               res_idx=ResearchAI.get_research_index(),
                               turn=turn,
                               aggression=aggression_name.capitalize()))
    debug(
        "EmpireColors: {0.colour[0]} {0.colour[1]} {0.colour[2]} {0.colour[3]}"
        .format(empire))
    if planet:
        debug("CapitalID: " + str(planet_id) + " Name: " + planet.name +
              " Species: " + planet.speciesName)
    else:
        debug("CapitalID: None Currently Name: None Species: None ")
    debug(
        "***************************************************************************"
    )
    debug(
        "***************************************************************************"
    )

    # When loading a savegame, the AI will already have issued orders for this turn.
    # To avoid duplicate orders, generally try not to replay turns. However, for debugging
    # purposes it is often useful to replay the turn and observe varying results after
    # code changes. Set the replay_after_load flag in the AI config to let the AI issue
    # new orders after a game load. Note that the orders from the original savegame are
    # still being issued and the AIstate was saved after those orders were issued.
    # TODO: Consider adding an option to clear AI orders after load (must save AIstate at turn start then)
    if fo.currentTurn() == aistate.last_turn_played:
        info("The AIstate indicates that this turn was already played.")
        if not check_bool(get_option_dict().get('replay_turn_after_load',
                                                'False')):
            info(
                "Aborting new order generation. Orders from savegame will still be issued."
            )
            return
        info("Issuing new orders anyway.")

    if turn == 1:
        human_player = fo.empirePlayerID(1)
        greet = diplomatic_corp.get_first_turn_greet_message()
        fo.sendChatMessage(
            human_player, '%s (%s): [[%s]]' %
            (empire.name, get_trait_name_aggression(aistate.character), greet))

    aistate.prepare_for_new_turn()
    debug("Calling AI Modules")
    # call AI modules
    action_list = [
        ColonisationAI.survey_universe,
        ProductionAI.find_best_designs_this_turn,
        PriorityAI.calculate_priorities,
        ExplorationAI.assign_scouts_to_explore_systems,
        ColonisationAI.assign_colony_fleets_to_colonise,
        InvasionAI.assign_invasion_fleets_to_invade,
        MilitaryAI.assign_military_fleets_to_systems,
        FleetUtilsAI.generate_fleet_orders_for_fleet_missions,
        FleetUtilsAI.issue_fleet_orders_for_fleet_missions,
        ResearchAI.generate_research_orders,
        ProductionAI.generate_production_orders,
        ResourcesAI.generate_resources_orders,
    ]

    for action in action_list:
        try:
            main_timer.start(action.__name__)
            action()
            main_timer.stop()
        except Exception as e:
            error("Exception %s while trying to %s" % (e, action.__name__),
                  exc_info=True)
    main_timer.stop_print_and_clear()
    turn_timer.stop_print_and_clear()

    turn_timer.start("Server_Processing")

    aistate.last_turn_played = fo.currentTurn()

    if using_statprof:
        try:
            statprof.stop()
            statprof.display()
            statprof.start()
        except:  # noqa: E722
            pass
Beispiel #46
0
    def __clean_fleet_roles(self, just_resumed=False):
        """Removes fleetRoles if a fleet has been lost, and update fleet Ratings."""
        for sys_id in self.systemStatus:
            self.systemStatus[sys_id]['myFleetRating'] = 0
            self.systemStatus[sys_id]['myFleetRatingVsPlanets'] = 0

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

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

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

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

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

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

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

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

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

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

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

        secure_ai_fleet_missions = foAI.foAIstate.get_fleet_missions_with_any_mission_types(
            [MissionType.SECURE])

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

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

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

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

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

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

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

    # export invasion targeted systems for other AI modules
    AIstate.invasionTargetedSystemIDs = list(all_invasion_targeted_system_ids)
    invasion_timer.stop(section_name="evaluating %d target planets" %
                        (len(evaluated_planet_ids)))
    invasion_timer.stop_print_and_clear()
Beispiel #48
0
    def update_system_status(self):
        print 10 * "=", "Updating System Threats", 10 * "="
        universe = fo.getUniverse()
        empire = fo.getEmpire()
        empire_id = fo.empireID()
        destroyed_object_ids = universe.destroyedObjectIDs(empire_id)
        supply_unobstructed_systems = set(empire.supplyUnobstructedSystems)
        min_hidden_attack = 4
        min_hidden_health = 8
        system_id_list = universe.systemIDs  # will normally look at this, the list of all known systems

        # for use in debugging
        verbose = False

        # assess enemy fleets that may have been momentarily visible
        cur_e_fighters = {
            CombatRatingsAI.default_ship_stats().get_stats(hashable=True): [0]
        }  # start with a dummy entry
        old_e_fighters = {
            CombatRatingsAI.default_ship_stats().get_stats(hashable=True): [0]
        }  # start with a dummy entry
        enemy_fleet_ids = []
        enemies_by_system = {}
        my_fleets_by_system = {}
        fleet_spot_position = {}
        saw_enemies_at_system = {}
        my_milship_rating = MilitaryAI.cur_best_mil_ship_rating()
        current_turn = fo.currentTurn()
        for fleet_id in universe.fleetIDs:
            fleet = universe.getFleet(fleet_id)
            if fleet is None:
                continue
            if not fleet.empty:
                # TODO: check if currently in system and blockaded before accepting destination as location
                this_system_id = (fleet.nextSystemID != INVALID_ID
                                  and fleet.nextSystemID) or fleet.systemID
                if fleet.ownedBy(empire_id):
                    if fleet_id not in destroyed_object_ids:
                        my_fleets_by_system.setdefault(this_system_id,
                                                       []).append(fleet_id)
                        fleet_spot_position.setdefault(fleet.systemID,
                                                       []).append(fleet_id)
                else:
                    dead_fleet = fleet_id in destroyed_object_ids
                    if not fleet.ownedBy(-1) and (fleet.hasArmedShips
                                                  or fleet.hasFighterShips):
                        ship_stats = CombatRatingsAI.FleetCombatStats(
                            fleet_id).get_ship_stats(hashable=True)
                        e_f_dict = [
                            cur_e_fighters, old_e_fighters
                        ][dead_fleet]  # track old/dead enemy fighters for rating assessments in case not enough current info
                        for stats in ship_stats:
                            attacks = stats[0]
                            if attacks:
                                e_f_dict.setdefault(stats, [0])[0] += 1
                    partial_vis_turn = universe.getVisibilityTurnsMap(
                        fleet_id, empire_id).get(fo.visibility.partial, -9999)
                    if not dead_fleet:
                        # TODO: consider checking death of individual ships.  If ships had been moved from this fleet
                        # into another fleet, we might have witnessed their death in that other fleet but if this fleet
                        # had not been seen since before that transfer then the ships might also still be listed here.
                        sys_status = self.systemStatus.setdefault(
                            this_system_id, {})
                        sys_status['enemy_ship_count'] = sys_status.get(
                            'enemy_ship_count', 0) + len(fleet.shipIDs)
                        if partial_vis_turn >= current_turn - 1:  # only interested in immediately recent data
                            saw_enemies_at_system[fleet.systemID] = True
                            enemy_fleet_ids.append(fleet_id)
                            enemies_by_system.setdefault(this_system_id,
                                                         []).append(fleet_id)
                            if not fleet.ownedBy(-1):
                                self.misc.setdefault('enemies_sighted',
                                                     {}).setdefault(
                                                         current_turn,
                                                         []).append(fleet_id)
                                rating = CombatRatingsAI.get_fleet_rating(
                                    fleet_id,
                                    enemy_stats=CombatRatingsAI.
                                    get_empire_standard_fighter())
                                if rating > 0.25 * my_milship_rating:
                                    self.misc.setdefault(
                                        'dangerous_enemies_sighted',
                                        {}).setdefault(current_turn,
                                                       []).append(fleet_id)
        e_f_dict = [cur_e_fighters, old_e_fighters][len(cur_e_fighters) == 1]
        std_fighter = sorted([(v, k) for k, v in e_f_dict.items()])[-1][1]
        self.__empire_standard_enemy = std_fighter
        self.empire_standard_enemy_rating = self.get_standard_enemy(
        ).get_rating()
        # TODO: If no current information available, rate against own fighters

        # assess fleet and planet threats & my local fleets
        for sys_id in system_id_list:
            sys_status = self.systemStatus.setdefault(sys_id, {})
            system = universe.getSystem(sys_id)
            if verbose:
                print "AIState threat evaluation for %s" % system
            # update fleets
            sys_status['myfleets'] = my_fleets_by_system.get(sys_id, [])
            sys_status['myFleetsAccessible'] = fleet_spot_position.get(
                sys_id, [])
            local_enemy_fleet_ids = enemies_by_system.get(sys_id, [])
            sys_status['localEnemyFleetIDs'] = local_enemy_fleet_ids
            if system:
                sys_status['name'] = system.name
                for fid in system.fleetIDs:
                    if fid in destroyed_object_ids:  # TODO: double check are these checks/deletes necessary?
                        self.delete_fleet_info(
                            fid)  # this is safe even if fleet wasn't mine
                        continue
                    fleet = universe.getFleet(fid)
                    if not fleet or fleet.empty:
                        self.delete_fleet_info(
                            fid)  # this is safe even if fleet wasn't mine
                        continue

            # update threats
            sys_vis_dict = universe.getVisibilityTurnsMap(
                sys_id, fo.empireID())
            partial_vis_turn = sys_vis_dict.get(fo.visibility.partial, -9999)
            mob_ratings = []  # for mobile unowned monster fleets
            lost_fleet_rating = 0
            enemy_ratings = []
            monster_ratings = []
            mobile_fleets = []
            for fid in local_enemy_fleet_ids:
                fleet = universe.getFleet(fid)
                if not fleet:
                    continue
                fleet_rating = CombatRatingsAI.get_fleet_rating(
                    fid,
                    enemy_stats=CombatRatingsAI.get_empire_standard_fighter())
                if fleet.speed == 0:
                    monster_ratings.append(fleet_rating)
                    if verbose:
                        print "\t immobile enemy fleet %s has rating %.1f" % (
                            fleet, fleet_rating)
                else:
                    if verbose:
                        print "\t mobile enemy fleet %s has rating %.1f" % (
                            fleet, fleet_rating)
                    mobile_fleets.append(fid)
                    if fleet.unowned:
                        mob_ratings.append(fleet_rating)
                    else:
                        enemy_ratings.append(fleet_rating)
            enemy_rating = CombatRatingsAI.combine_ratings_list(enemy_ratings)
            monster_rating = CombatRatingsAI.combine_ratings_list(
                monster_ratings)
            mob_rating = CombatRatingsAI.combine_ratings_list(mob_ratings)
            if fleetsLostBySystem.get(sys_id, []):
                lost_fleet_rating = CombatRatingsAI.combine_ratings_list(
                    fleetsLostBySystem[sys_id])
            if not system or partial_vis_turn == -9999:  # under current visibility rules should not be possible to have any losses or other info here, but just in case...
                if verbose:
                    print "Have never had partial vis for system %d ( %s ) -- basing threat assessment on old info and lost ships" % (
                        sys_id, sys_status.get('name', "name unknown"))
                sys_status.setdefault('local_fleet_threats', set())
                sys_status['planetThreat'] = 0
                sys_status['fleetThreat'] = int(
                    max(
                        CombatRatingsAI.combine_ratings(
                            enemy_rating, mob_rating),
                        0.98 * sys_status.get('fleetThreat', 0),
                        1.1 * lost_fleet_rating - monster_rating))
                sys_status['monsterThreat'] = int(
                    max(monster_rating,
                        0.98 * sys_status.get('monsterThreat', 0),
                        1.1 * lost_fleet_rating - enemy_rating - mob_rating))
                sys_status['enemy_threat'] = int(
                    max(enemy_rating, 0.98 * sys_status.get('enemy_threat', 0),
                        1.1 * lost_fleet_rating - monster_rating - mob_rating))
                sys_status['mydefenses'] = {
                    'overall': 0,
                    'attack': 0,
                    'health': 0
                }
                sys_status['totalThreat'] = sys_status['fleetThreat']
                sys_status['regional_fleet_threats'] = sys_status[
                    'local_fleet_threats'].copy()
                continue

            # have either stale or current info
            pattack = 0
            phealth = 0
            mypattack, myphealth = 0, 0
            for pid in system.planetIDs:
                prating = self.assess_planet_threat(pid,
                                                    sighting_age=current_turn -
                                                    partial_vis_turn)
                planet = universe.getPlanet(pid)
                if not planet:
                    continue
                if planet.owner == self.empireID:  # TODO: check for diplomatic status
                    mypattack += prating['attack']
                    myphealth += prating['health']
                else:
                    if [
                            special for special in planet.specials
                            if "_NEST_" in special
                    ]:
                        sys_status['nest_threat'] = 100
                    pattack += prating['attack']
                    phealth += prating['health']
            sys_status['planetThreat'] = pattack * phealth
            sys_status['mydefenses'] = {
                'overall': mypattack * myphealth,
                'attack': mypattack,
                'health': myphealth
            }

            if max(
                    sys_status.get('totalThreat', 0), pattack * phealth
            ) >= 0.6 * lost_fleet_rating:  # previous threat assessment could account for losses, ignore the losses now
                lost_fleet_rating = 0

            # TODO use sitrep combat info rather than estimating stealthed enemies by fleets lost to them
            # TODO also only consider past stealthed fleet threat to still be present if the system is still obstructed
            # TODO: track visibility across turns in order to distinguish the blip of visibility in (losing) combat,
            # which FO currently treats as being for the previous turn, partially superseding the previous visibility for that turn
            if not partial_vis_turn == current_turn:  # (universe.getVisibility(sys_id, self.empire_id) >= fo.visibility.partial):
                sys_status.setdefault('local_fleet_threats', set())
                sys_status['currently_visible'] = False
                # print "Stale visibility for system %d ( %s ) -- last seen %d, current Turn %d -- basing threat assessment on old info and lost ships"%(sys_id, sys_status.get('name', "name unknown"), partial_vis_turn, currentTurn)
                sys_status['fleetThreat'] = int(
                    max(
                        CombatRatingsAI.combine_ratings(
                            enemy_rating, mob_rating),
                        0.98 * sys_status.get('fleetThreat', 0),
                        2.0 * lost_fleet_rating -
                        max(sys_status.get('monsterThreat', 0),
                            monster_rating)))
                sys_status['enemy_threat'] = int(
                    max(
                        enemy_rating, 0.98 * sys_status.get('enemy_threat', 0),
                        1.1 * lost_fleet_rating -
                        max(sys_status.get('monsterThreat', 0),
                            monster_rating)))
                sys_status['monsterThreat'] = int(
                    max(monster_rating,
                        0.98 * sys_status.get('monsterThreat', 0)))
                # sys_status['totalThreat'] = ((pattack + enemy_attack + monster_attack) ** 0.8) * ((phealth + enemy_health + monster_health)** 0.6)  # reevaluate this
                sys_status['totalThreat'] = max(
                    CombatRatingsAI.combine_ratings_list([
                        enemy_rating, mob_rating, monster_rating,
                        pattack * phealth
                    ]), 2 * lost_fleet_rating,
                    0.98 * sys_status.get('totalThreat', 0))
            else:  # system considered visible #TODO: reevaluate as visibility rules change
                sys_status['currently_visible'] = True
                sys_status['local_fleet_threats'] = set(mobile_fleets)
                sys_status['fleetThreat'] = int(
                    max(
                        CombatRatingsAI.combine_ratings(
                            enemy_rating, mob_rating), 2 * lost_fleet_rating -
                        monster_rating))  # includes mobile monsters
                if verbose:
                    print "enemy threat calc parts: enemy rating %.1f, lost fleet rating %.1f, monster_rating %.1f" % (
                        enemy_rating, lost_fleet_rating, monster_rating)
                sys_status['enemy_threat'] = int(
                    max(enemy_rating, 2 * lost_fleet_rating -
                        monster_rating))  # does NOT include mobile monsters
                sys_status['monsterThreat'] = monster_rating
                sys_status[
                    'totalThreat'] = CombatRatingsAI.combine_ratings_list([
                        enemy_rating, mob_rating, monster_rating,
                        pattack * phealth
                    ])
            sys_status['regional_fleet_threats'] = sys_status[
                'local_fleet_threats'].copy()
            sys_status['fleetThreat'] = max(sys_status['fleetThreat'],
                                            sys_status.get('nest_threat', 0))
            sys_status['totalThreat'] = max(sys_status['totalThreat'],
                                            sys_status.get('nest_threat', 0))

            if partial_vis_turn > 0 and sys_id not in supply_unobstructed_systems:  # has been seen with Partial Vis, but is currently supply-blocked
                sys_status['fleetThreat'] = max(
                    sys_status['fleetThreat'],
                    min_hidden_attack * min_hidden_health)
                sys_status['totalThreat'] = max(
                    sys_status['totalThreat'],
                    ((pattack + min_hidden_attack)**0.8) *
                    ((phealth + min_hidden_health)**0.6))
            if verbose and sys_status['fleetThreat'] > 0:
                print "%s intermediate status: %s" % (system, sys_status)

        enemy_supply, enemy_near_supply = self.assess_enemy_supply(
        )  # TODO: assess change in enemy supply over time
        # assess secondary threats (threats of surrounding systems) and update my fleet rating
        for sys_id in system_id_list:
            sys_status = self.systemStatus[sys_id]
            sys_status['enemies_supplied'] = enemy_supply.get(sys_id, [])
            sys_status['enemies_nearly_supplied'] = enemy_near_supply.get(
                sys_id, [])
            my_ratings_list = []
            my_ratings_against_planets_list = []
            for fid in sys_status['myfleets']:
                this_rating = self.get_rating(fid, True,
                                              self.get_standard_enemy())
                my_ratings_list.append(this_rating)
                my_ratings_against_planets_list.append(
                    self.get_rating(fid, against_planets=True))
            if sys_id != INVALID_ID:
                sys_status[
                    'myFleetRating'] = CombatRatingsAI.combine_ratings_list(
                        my_ratings_list)
                sys_status[
                    'myFleetRatingVsPlanets'] = CombatRatingsAI.combine_ratings_list(
                        my_ratings_against_planets_list)
                sys_status[
                    'all_local_defenses'] = CombatRatingsAI.combine_ratings(
                        sys_status['myFleetRating'],
                        sys_status['mydefenses']['overall'])
            sys_status['neighbors'] = set(
                dict_from_map(
                    universe.getSystemNeighborsMap(sys_id, self.empireID)))

        for sys_id in system_id_list:
            sys_status = self.systemStatus[sys_id]
            neighbors = sys_status.get('neighbors', set())
            this_system = fo.getUniverse().getSystem(sys_id)
            if verbose:
                print "Regional Assessment for %s with local fleet threat %.1f" % (
                    this_system, sys_status.get('fleetThreat', 0))
            jumps2 = set()
            jumps3 = set()
            jumps4 = set()
            for seta, setb in [(neighbors, jumps2), (jumps2, jumps3),
                               (jumps3, jumps4)]:
                for sys2id in seta:
                    setb.update(
                        self.systemStatus.get(sys2id,
                                              {}).get('neighbors', set()))
            jump2ring = jumps2 - neighbors - {sys_id}
            jump3ring = jumps3 - jumps2 - neighbors - {sys_id}
            jump4ring = jumps4 - jumps3 - jumps2 - neighbors - {sys_id}
            sys_status['2jump_ring'] = jump2ring
            sys_status['3jump_ring'] = jump3ring
            sys_status['4jump_ring'] = jump4ring
            threat, max_threat, myrating, j1_threats = self.area_ratings(
                neighbors, ref_sys_name="neighbors %s" %
                this_system) if verbose else self.area_ratings(neighbors)
            sys_status['neighborThreat'] = threat
            sys_status['max_neighbor_threat'] = max_threat
            sys_status['my_neighbor_rating'] = myrating
            threat, max_threat, myrating, j2_threats = self.area_ratings(
                jump2ring, ref_sys_name="jump2 %s" %
                this_system) if verbose else self.area_ratings(jump2ring)
            sys_status['jump2_threat'] = threat
            sys_status['my_jump2_rating'] = myrating
            threat, max_threat, myrating, j3_threats = self.area_ratings(
                jump3ring)
            sys_status['jump3_threat'] = threat
            sys_status['my_jump3_rating'] = myrating
            threat_keys = ['fleetThreat', 'neighborThreat', 'jump2_threat'
                           ]  # for local system includes both enemies and mobs
            sys_status[
                'regional_threat'] = CombatRatingsAI.combine_ratings_list(
                    map(lambda x: sys_status.get(x, 0), threat_keys))
            # TODO: investigate cases where regional_threat has been nonzero but no regional_threat_fleets
            # (probably due to attenuating history of past threats)
            sys_status.setdefault('regional_fleet_threats',
                                  set()).update(j1_threats, j2_threats)
Beispiel #49
0
def get_invasion_fleets():
    invasion_timer.start("gathering initial info")
    universe = fo.getUniverse()
    empire = fo.getEmpire()
    empire_id = empire.empireID

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    # export invasion targeted systems for other AI modules
    AIstate.invasionTargetedSystemIDs = list(all_invasion_targeted_system_ids)
    invasion_timer.stop(section_name="evaluating %d target planets" %
                        (len(evaluated_planet_ids)))
    invasion_timer.end()
Beispiel #50
0
def get_military_fleets(mil_fleets_ids=None, try_reset=True, thisround="Main"):
    """Get armed military fleets."""
    global _military_allocations

    universe = fo.getUniverse()
    empire_id = fo.empireID()
    home_system_id = PlanetUtilsAI.get_capital_sys_id()

    all_military_fleet_ids = (mil_fleets_ids if mil_fleets_ids is not None else
                              FleetUtilsAI.get_empire_fleet_ids_by_role(
                                  MissionType.MILITARY))

    if try_reset and (fo.currentTurn() +
                      empire_id) % 30 == 0 and thisround == "Main":
        try_again(all_military_fleet_ids,
                  try_reset=False,
                  thisround=thisround + " Reset")
        return

    mil_fleets_ids = list(
        FleetUtilsAI.extract_fleet_ids_without_mission_types(
            all_military_fleet_ids))
    mil_needing_repair_ids, mil_fleets_ids = avail_mil_needing_repair(
        mil_fleets_ids, split_ships=True)
    avail_mil_rating = sum(
        map(CombatRatingsAI.get_fleet_rating, mil_fleets_ids))

    if not mil_fleets_ids:
        if "Main" in thisround:
            _military_allocations = []
        return []

    # for each system, get total rating of fleets assigned to it
    already_assigned_rating = {}
    already_assigned_rating_vs_planets = {}
    systems_status = foAI.foAIstate.systemStatus
    enemy_sup_factor = {}  # enemy supply
    for sys_id in universe.systemIDs:
        already_assigned_rating[sys_id] = 0
        already_assigned_rating_vs_planets[sys_id] = 0
        enemy_sup_factor[sys_id] = min(
            2,
            len(
                systems_status.get(sys_id, {}).get('enemies_nearly_supplied',
                                                   [])))
    for fleet_id in [
            fid for fid in all_military_fleet_ids if fid not in mil_fleets_ids
    ]:
        ai_fleet_mission = foAI.foAIstate.get_fleet_mission(fleet_id)
        if not ai_fleet_mission.target:  # shouldn't really be possible
            continue
        last_sys = ai_fleet_mission.target.get_system(
        ).id  # will count this fleet as assigned to last system in target list  # TODO last_sys or target sys?
        this_rating = CombatRatingsAI.get_fleet_rating(fleet_id)
        this_rating_vs_planets = CombatRatingsAI.get_fleet_rating_against_planets(
            fleet_id)
        already_assigned_rating[last_sys] = CombatRatingsAI.combine_ratings(
            already_assigned_rating.get(last_sys, 0), this_rating)
        already_assigned_rating_vs_planets[
            last_sys] = CombatRatingsAI.combine_ratings(
                already_assigned_rating_vs_planets.get(last_sys, 0),
                this_rating_vs_planets)
    for sys_id in universe.systemIDs:
        my_defense_rating = systems_status.get(sys_id,
                                               {}).get('mydefenses',
                                                       {}).get('overall', 0)
        already_assigned_rating[sys_id] = CombatRatingsAI.combine_ratings(
            my_defense_rating, already_assigned_rating[sys_id])
        if _verbose_mil_reporting and already_assigned_rating[sys_id]:
            print "\t System %s already assigned rating %.1f" % (
                universe.getSystem(sys_id), already_assigned_rating[sys_id])

    # get systems to defend
    capital_id = PlanetUtilsAI.get_capital()
    if capital_id is not None:
        capital_planet = universe.getPlanet(capital_id)
    else:
        capital_planet = None
    # TODO: if no owned planets try to capture one!
    if capital_planet:
        capital_sys_id = capital_planet.systemID
    else:  # should be rare, but so as to not break code below, pick a randomish mil-centroid system
        capital_sys_id = None  # unless we can find one to use
        system_dict = {}
        for fleet_id in all_military_fleet_ids:
            status = foAI.foAIstate.fleetStatus.get(fleet_id, None)
            if status is not None:
                sys_id = status['sysID']
                if not list(universe.getSystem(sys_id).planetIDs):
                    continue
                system_dict[sys_id] = system_dict.get(sys_id, 0) + status.get(
                    'rating', 0)
        ranked_systems = sorted([(val, sys_id)
                                 for sys_id, val in system_dict.items()])
        if ranked_systems:
            capital_sys_id = ranked_systems[-1][-1]
        else:
            try:
                capital_sys_id = foAI.foAIstate.fleetStatus.items(
                )[0][1]['sysID']
            except:
                pass

    num_targets = max(10, PriorityAI.allotted_outpost_targets)
    top_target_planets = ([
        pid for pid, pscore, trp in AIstate.
        invasionTargets[:PriorityAI.allottedInvasionTargets] if pscore > 20
    ] + [
        pid
        for pid, (pscore, spec) in foAI.foAIstate.colonisableOutpostIDs.items(
        )[:num_targets] if pscore > 20
    ] + [
        pid
        for pid, (pscore, spec) in foAI.foAIstate.colonisablePlanetIDs.items()
        [:num_targets] if pscore > 20
    ])
    top_target_planets.extend(foAI.foAIstate.qualifyingTroopBaseTargets.keys())
    base_col_target_systems = PlanetUtilsAI.get_systems(top_target_planets)
    top_target_systems = []
    for sys_id in AIstate.invasionTargetedSystemIDs + base_col_target_systems:
        if sys_id not in top_target_systems:
            if foAI.foAIstate.systemStatus[sys_id][
                    'totalThreat'] > get_tot_mil_rating():
                continue
            top_target_systems.append(
                sys_id)  # doing this rather than set, to preserve order

    try:
        # capital defense
        allocation_helper = AllocationHelper(
            already_assigned_rating, already_assigned_rating_vs_planets,
            avail_mil_rating, try_reset)
        if capital_sys_id is not None:
            CapitalDefenseAllocator(capital_sys_id,
                                    allocation_helper).allocate()

        # defend other planets
        empire_planet_ids = PlanetUtilsAI.get_owned_planets_by_empire(
            universe.planetIDs)
        empire_occupied_system_ids = list(
            set(PlanetUtilsAI.get_systems(empire_planet_ids)) -
            {capital_sys_id})
        for sys_id in empire_occupied_system_ids:
            PlanetDefenseAllocator(sys_id, allocation_helper).allocate()

        # attack / protect high priority targets
        for sys_id in top_target_systems:
            TopTargetAllocator(sys_id, allocation_helper).allocate()

        # enemy planets
        other_targeted_system_ids = [
            sys_id for sys_id in set(
                PlanetUtilsAI.get_systems(AIstate.opponentPlanetIDs))
            if sys_id not in top_target_systems
        ]
        for sys_id in other_targeted_system_ids:
            TargetAllocator(sys_id, allocation_helper).allocate()

        # colony / outpost targets
        other_targeted_system_ids = [
            sys_id for sys_id in list(
                set(AIstate.colonyTargetedSystemIDs +
                    AIstate.outpostTargetedSystemIDs))
            if sys_id not in top_target_systems
        ]
        for sys_id in other_targeted_system_ids:
            OutpostTargetAllocator(sys_id, allocation_helper).allocate()

        # TODO blockade enemy systems

        # interior systems
        targetable_ids = set(state.get_systems_by_supply_tier(0))
        current_mil_systems = [
            sid for sid, _, _, _, _ in allocation_helper.allocations
        ]
        interior_targets1 = targetable_ids.difference(current_mil_systems)
        interior_targets = [
            sid for sid in interior_targets1
            if (allocation_helper.threat_bias +
                systems_status.get(sid, {}).get('totalThreat', 0) > 0.8 *
                allocation_helper.already_assigned_rating[sid])
        ]
        for sys_id in interior_targets:
            InteriorTargetsAllocator(sys_id, allocation_helper).allocate()

        # TODO Exploration targets

        # border protections
        visible_system_ids = foAI.foAIstate.visInteriorSystemIDs | foAI.foAIstate.visBorderSystemIDs
        accessible_system_ids = ([
            sys_id for sys_id in visible_system_ids
            if universe.systemsConnected(sys_id, home_system_id, empire_id)
        ] if home_system_id != INVALID_ID else [])
        current_mil_systems = [
            sid
            for sid, alloc, rvp, take_any, _ in allocation_helper.allocations
            if alloc > 0
        ]
        border_targets1 = [
            sid for sid in accessible_system_ids
            if sid not in current_mil_systems
        ]
        border_targets = [
            sid for sid in border_targets1
            if (allocation_helper.threat_bias +
                systems_status.get(sid, {}).get('fleetThreat', 0) +
                systems_status.get(sid, {}).get('planetThreat', 0) > 0.8 *
                allocation_helper.already_assigned_rating[sid])
        ]
        for sys_id in border_targets:
            BorderSecurityAllocator(sys_id, allocation_helper).allocate()
    except ReleaseMilitaryException:
        try_again(all_military_fleet_ids)
        return

    new_allocations = []
    remaining_mil_rating = avail_mil_rating
    # for top categories assign max_alloc right away as available
    for cat in ['capitol', 'occupied', 'topTargets']:
        for sid, alloc, rvp, take_any, max_alloc in allocation_helper.allocation_by_groups.get(
                cat, []):
            if remaining_mil_rating <= 0:
                break
            this_alloc = min(remaining_mil_rating, max_alloc)
            new_allocations.append((sid, this_alloc, alloc, rvp, take_any))
            remaining_mil_rating -= this_alloc

    base_allocs = set()
    # for lower priority categories, first assign base_alloc around to all, then top up as available
    for cat in ['otherTargets', 'accessibleTargets', 'exploreTargets']:
        for sid, alloc, rvp, take_any, max_alloc in allocation_helper.allocation_by_groups.get(
                cat, []):
            if remaining_mil_rating <= 0:
                break
            base_allocs.add(sid)
            remaining_mil_rating -= alloc
    for cat in ['otherTargets', 'accessibleTargets', 'exploreTargets']:
        for sid, alloc, rvp, take_any, max_alloc in allocation_helper.allocation_by_groups.get(
                cat, []):
            if sid not in base_allocs:
                break
            if remaining_mil_rating <= 0:
                new_allocations.append((sid, alloc, alloc, rvp, take_any))
            else:
                new_rating = min(remaining_mil_rating + alloc, max_alloc)
                new_allocations.append((sid, new_rating, alloc, rvp, take_any))
                remaining_mil_rating -= (new_rating - alloc)

    if "Main" in thisround:
        _military_allocations = new_allocations
    if _verbose_mil_reporting or "Main" in thisround:
        print "------------------------------\nFinal %s Round Military Allocations: %s \n-----------------------" % (
            thisround,
            dict([(sid, alloc) for sid, alloc, _, _, _ in new_allocations]))
        print "(Apparently) remaining military rating: %.1f" % remaining_mil_rating

    return new_allocations
Beispiel #51
0
 def score(self):
     if self.__last_score_update != fo.currentTurn():
         self.__update_score()
     return self.__score
Beispiel #52
0
def generate_fleet_orders_for_fleet_missions():
    """Generates fleet orders from targets."""
    print("Generating fleet orders")

    # The following fleet lists are based on *Roles* -- Secure type missions are done by fleets with Military Roles
    print "Fleets by Role\n"
    print "Exploration Fleets : %s" % get_empire_fleet_ids_by_role(
        AIFleetMissionType.FLEET_MISSION_EXPLORATION)
    print "Colonization Fleets:%s" % get_empire_fleet_ids_by_role(
        AIFleetMissionType.FLEET_MISSION_COLONISATION)
    print "Outpost Fleets :%s" % get_empire_fleet_ids_by_role(
        AIFleetMissionType.FLEET_MISSION_OUTPOST)
    print "Invasion Fleets :%s" % get_empire_fleet_ids_by_role(
        AIFleetMissionType.FLEET_MISSION_INVASION)
    print "Military Fleets :%s" % get_empire_fleet_ids_by_role(
        AIFleetMissionType.FLEET_MISSION_MILITARY)
    print "Orbital Defense Fleets :%s" % get_empire_fleet_ids_by_role(
        AIFleetMissionType.FLEET_MISSION_ORBITAL_DEFENSE)
    print "Outpost Base Fleets :%s" % get_empire_fleet_ids_by_role(
        AIFleetMissionType.FLEET_MISSION_ORBITAL_OUTPOST)
    print "Invasion Base Fleets :%s" % get_empire_fleet_ids_by_role(
        AIFleetMissionType.FLEET_MISSION_ORBITAL_INVASION)
    print "Securing Fleets :%s  (currently FLEET_MISSION_MILITARY should be used instead of this Role)" % get_empire_fleet_ids_by_role(
        AIFleetMissionType.FLEET_MISSION_SECURE)
    print "Unclassifiable Fleets :%s" % get_empire_fleet_ids_by_role(
        AIFleetMissionType.FLEET_MISSION_INVALID)

    if fo.currentTurn() < 50:
        print
        print "Explored systems :"
        print_systems(
            foAI.foAIstate.get_explorable_systems(
                AIExplorableSystemType.EXPLORABLE_SYSTEM_EXPLORED))
        print "Unexplored systems:"
        print_systems(
            foAI.foAIstate.get_explorable_systems(
                AIExplorableSystemType.EXPLORABLE_SYSTEM_UNEXPLORED))
        print

    exploration_fleet_missions = foAI.foAIstate.get_fleet_missions_with_any_mission_types(
        [AIFleetMissionType.FLEET_MISSION_EXPLORATION])
    if exploration_fleet_missions:
        print "Exploration targets: "
    else:
        print "Exploration targets: None"
    for explorationAIFleetMission in exploration_fleet_missions:
        print "    %s" % explorationAIFleetMission

    colonisation_fleet_missions = foAI.foAIstate.get_fleet_missions_with_any_mission_types(
        [AIFleetMissionType.FLEET_MISSION_COLONISATION])
    if colonisation_fleet_missions:
        print "Colonization targets: "
    else:
        print "Colonization targets: None"
    for colonisation_fleet_mission in colonisation_fleet_missions:
        print "    %s" % colonisation_fleet_mission

    outpost_fleet_missions = foAI.foAIstate.get_fleet_missions_with_any_mission_types(
        [AIFleetMissionType.FLEET_MISSION_OUTPOST])
    if outpost_fleet_missions:
        print "Outpost targets: "
    else:
        print "Outpost targets: None"
    for outpost_fleet_mission in outpost_fleet_missions:
        print "    %s" % outpost_fleet_mission

    outpost_base_fleet_missions = foAI.foAIstate.get_fleet_missions_with_any_mission_types(
        [AIFleetMissionType.FLEET_MISSION_ORBITAL_OUTPOST])
    if outpost_base_fleet_missions:
        print "Outpost Base targets (must have been interrupted by combat): "
    else:
        print "Outpost targets: None (as expected, due to expected timing of order submission and execution)"
    for outpost_fleet_mission in outpost_base_fleet_missions:
        print "    %s" % outpost_fleet_mission

    invasion_fleet_missions = foAI.foAIstate.get_fleet_missions_with_any_mission_types(
        [AIFleetMissionType.FLEET_MISSION_INVASION])
    if invasion_fleet_missions:
        print "Invasion targets: "
    else:
        print "Invasion targets: None"
    for invasion_fleet_mission in invasion_fleet_missions:
        print "    %s" % invasion_fleet_mission

    troop_base_fleet_missions = foAI.foAIstate.get_fleet_missions_with_any_mission_types(
        [AIFleetMissionType.FLEET_MISSION_ORBITAL_INVASION])
    if troop_base_fleet_missions:
        print "Invasion Base targets (must have been interrupted by combat): "
    else:
        print "Invasion Base targets: None (as expected, due to expected timing of order submission and execution)"
    for invasion_fleet_mission in troop_base_fleet_missions:
        print "    %s" % invasion_fleet_mission

    military_fleet_missions = foAI.foAIstate.get_fleet_missions_with_any_mission_types(
        [AIFleetMissionType.FLEET_MISSION_MILITARY])
    if military_fleet_missions:
        print "General Military targets: "
    else:
        print "General Military targets: None"
    for military_fleet_mission in military_fleet_missions:
        print "    %s" % military_fleet_mission

    secure_fleet_missions = foAI.foAIstate.get_fleet_missions_with_any_mission_types(
        [AIFleetMissionType.FLEET_MISSION_SECURE])
    if secure_fleet_missions:
        print "Secure targets: "
    else:
        print "Secure targets: None"
    for secure_fleet_mission in secure_fleet_missions:
        print "    %s" % secure_fleet_mission

    orb_defense_fleet_missions = foAI.foAIstate.get_fleet_missions_with_any_mission_types(
        [AIFleetMissionType.FLEET_MISSION_ORBITAL_DEFENSE])
    if orb_defense_fleet_missions:
        print "Orbital Defense targets: "
    else:
        print "Orbital Defense targets: None"
    for orb_defence_fleet_mission in orb_defense_fleet_missions:
        print "    %s" % orb_defence_fleet_mission

    fleet_missions = foAI.foAIstate.get_all_fleet_missions()

    for mission in fleet_missions:
        mission.generate_fleet_orders()
Beispiel #53
0
def __print_candidate_table(candidates, mission, show_detail=False):
    universe = fo.getUniverse()
    if mission == "Colonization":
        first_column = Text("Score/Species")

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

    elif mission == "Outposts":
        first_column = Number("Score")
        get_first_column_value = itemgetter(0)
    else:
        warning("__print_candidate_table(%s, %s): Invalid mission type" % (candidates, mission))
        return
    columns = [first_column, Text("Planet"), Text("System"), Sequence("Specials")]
    if show_detail:
        columns.append(Sequence("Detail"))
    candidate_table = Table(*columns, table_name="Potential Targets for %s in Turn %d" % (mission, fo.currentTurn()))
    for planet_id, score_tuple in candidates:
        if score_tuple[0] > 0.5:
            planet = universe.getPlanet(planet_id)
            entries = [
                get_first_column_value(score_tuple),
                planet,
                universe.getSystem(planet.systemID),
                planet.specials,
            ]
            if show_detail:
                entries.append(score_tuple[-1])
            candidate_table.add_row(*entries)
    candidate_table.print_table(info)
Beispiel #54
0
    def refresh(self):
        """Turn start AIstate cleanup/refresh."""
        universe = fo.getUniverse()
        # checks exploration border & clears roles/missions of missing fleets & updates fleet locs & threats
        fleetsLostBySystem.clear()
        invasionTargets[:] = []
        exploration_center = PlanetUtilsAI.get_capital_sys_id()
        if exploration_center == INVALID_ID:  # a bad state probably from an old savegame, or else empire has lost (or almost has)
            exploration_center = self.__origin_home_system_id

        # check if planets in cache is still present. Remove destroyed.
        for system_id, info in sorted(self.systemStatus.items()):
            self.systemStatus[system_id][
                'enemy_ship_count'] = 0  # clear now in prep for update_system_status()
            planet_dict = info.get('planets', {})
            cache_planet_set = set(planet_dict)
            system_planet_set = set(
                *(sys.planetIDs for sys in [universe.getSystem(system_id)]
                  if sys))
            diff = cache_planet_set - system_planet_set
            if diff:
                print "Removing destroyed planets from systemStatus for system %s: planets to be removed: %s" % (
                    system_id, sorted(diff))
                for key in diff:
                    del planet_dict[key]

        ExplorationAI.graphFlags.clear()
        if fo.currentTurn() < 50:
            print "-------------------------------------------------"
            print "Border Exploration Update (relative to %s)" % (
                PlanetUtilsAI.sys_name_ids([exploration_center, INVALID_ID
                                            ])[0])
            print "-------------------------------------------------"
        if self.visBorderSystemIDs.keys() == [INVALID_ID]:
            self.visBorderSystemIDs.clear()
            self.visBorderSystemIDs[exploration_center] = 1
        for sys_id in self.visBorderSystemIDs.keys(
        ):  # This dict modified during iteration.
            if fo.currentTurn() < 50:
                print "Considering border system %s" % (
                    PlanetUtilsAI.sys_name_ids([sys_id, INVALID_ID])[0])
            ExplorationAI.follow_vis_system_connections(
                sys_id, exploration_center)
        newly_explored = ExplorationAI.update_explored_systems()
        nametags = []
        for sys_id in newly_explored:
            newsys = universe.getSystem(sys_id)
            nametags.append(
                "ID:%4d -- %-20s" %
                (sys_id, (newsys and newsys.name) or "name unknown")
            )  # an explored system *should* always be able to be gotten
        if newly_explored:
            print "-------------------------------------------------"
            print "Newly explored systems:\n%s" % "\n".join(nametags)
            print "-------------------------------------------------"
        # cleanup fleet roles
        # self.update_fleet_locs()
        self.__clean_fleet_roles()
        self.__clean_fleet_missions(FleetUtilsAI.get_empire_fleet_ids())
        print "Fleets lost by system: %s" % fleetsLostBySystem
        self.update_system_status()
Beispiel #55
0
def survey_universe():
    colonization_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]
            ship_facilities = set(AIDependencies.SHIP_FACILITIES).intersection(buildings_here)
            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, ship_facilities, pid, sys_id)

                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()

    _print_empire_species_roster()

    rating_list = sorted(get_pilot_ratings().values(), reverse=True)
    summarize_pilot_ratings(rating_list)
    colonization_timer.stop()
Beispiel #56
0
def allotted_invasion_targets():
    return min(1 + int(fo.currentTurn() // 50), 3)
Beispiel #57
0
def allotted_invasion_targets():
    return 1 + int(fo.currentTurn() // 25)
Beispiel #58
0
def _calculate_colonisation_priority():
    """Calculates the demand for colony ships by colonisable planets."""
    global allottedColonyTargets
    aistate = get_aistate()
    enemies_sighted = aistate.misc.get('enemies_sighted', {})
    galaxy_is_sparse = ColonisationAI.galaxy_is_sparse()
    total_pp = fo.getEmpire().productionPoints
    num_colonies = get_number_of_colonies()
    colony_growth_barrier = aistate.character.max_number_colonies()
    if num_colonies > colony_growth_barrier:
        return 0.0
    colony_cost, turns_to_build = (ColonisationAI.colony_pod_cost_turns())

    mil_prio = aistate.get_priority(PriorityType.PRODUCTION_MILITARY)
    allotted_portion = ([[[0.6, 0.8], [0.3, 0.4]],
                         [[0.8, 0.9],
                          [0.4, 0.6]]][galaxy_is_sparse][any(enemies_sighted)])
    allotted_portion = aistate.character.preferred_colonization_portion(
        allotted_portion)
    # if ( get_aistate().get_priority(AIPriorityType.PRIORITY_PRODUCTION_COLONISATION)
    # > 2 * get_aistate().get_priority(AIPriorityType.PRIORITY_PRODUCTION_MILITARY)):
    # allotted_portion *= 1.5
    if mil_prio < 100:
        allotted_portion *= 2
    elif mil_prio < 200:
        allotted_portion *= 1.5
    elif fo.currentTurn() > 100:
        allotted_portion *= 0.75**(num_colonies / 10.0)
    # allottedColonyTargets = 1+ int(fo.currentTurn()/50)
    allottedColonyTargets = 1 + int(
        total_pp * turns_to_build * allotted_portion / colony_cost)
    outpost_prio = aistate.get_priority(PriorityType.PRODUCTION_OUTPOST)

    # if have no SP_SLY, and have any outposts to build, don't build colony ships TODO: make more complex assessment
    colonizers = list(ColonisationAI.empire_colonizers)
    if "SP_SLY" not in colonizers and outpost_prio > 0:
        return 0.0
    min_score = ColonisationAI.MINIMUM_COLONY_SCORE
    minimal_top = min_score + 2  # one more than the conditional floor set by ColonisationAI.revise_threat_factor()
    minimal_opportunities = [
        species_name
        for (_, (score, species_name)) in aistate.colonisablePlanetIDs.items()
        if min_score < score <= minimal_top
    ]
    decent_opportunities = [
        species_name
        for (_, (score, species_name)) in aistate.colonisablePlanetIDs.items()
        if score > minimal_top
    ]
    minimal_planet_factor = 0.2  # count them for something, but not much
    num_colonisable_planet_ids = len(
        decent_opportunities
    ) + minimal_planet_factor * len(minimal_opportunities)
    if num_colonisable_planet_ids == 0:
        return 1

    colony_ship_ids = FleetUtilsAI.get_empire_fleet_ids_by_role(
        MissionType.COLONISATION)
    num_colony_ships = len(
        FleetUtilsAI.extract_fleet_ids_without_mission_types(colony_ship_ids))
    colonisation_priority = 60 * (1.0 + num_colonisable_planet_ids -
                                  num_colony_ships) / (
                                      num_colonisable_planet_ids + 1)

    if colonizers == ["SP_SLY"]:
        colonisation_priority *= 2
    elif "SP_SLY" in colonizers:
        colony_opportunities = minimal_opportunities + decent_opportunities
        colonisation_priority *= (1.0 + colony_opportunities.count("SP_SLY")
                                  ) / len(colony_opportunities)

    # print
    # print "Number of Colony Ships : " + str(num_colony_ships)
    # print "Number of Colonisable planets : " + str(num_colonisable_planet_ids)
    # print "Priority for colony ships : " + str(colonisation_priority)

    if colonisation_priority < 1:
        return 0
    return colonisation_priority
Beispiel #59
0
 def target_number_of_orbitals(self):
     aggression_index = max(1, self.aggression)
     return min(
         int(((fo.currentTurn() + 4) / (8.0 * aggression_index**1.5))**0.8),
         fo.aggression.maniacal - aggression_index)
Beispiel #60
0
def generate_fleet_orders_for_fleet_missions():
    """Generates fleet orders from targets."""
    print("Generating fleet orders")

    # The following fleet lists are based on *Roles* -- Secure type missions are done by fleets with Military Roles
    debug("Fleets by Role\n")
    debug("Exploration Fleets: %s" %
          get_empire_fleet_ids_by_role(MissionType.EXPLORATION))
    debug("Colonization Fleets: %s" %
          get_empire_fleet_ids_by_role(MissionType.COLONISATION))
    debug("Outpost Fleets: %s" %
          get_empire_fleet_ids_by_role(MissionType.OUTPOST))
    debug("Invasion Fleets: %s" %
          get_empire_fleet_ids_by_role(MissionType.INVASION))
    debug("Military Fleets: %s" %
          get_empire_fleet_ids_by_role(MissionType.MILITARY))
    debug("Orbital Defense Fleets: %s" %
          get_empire_fleet_ids_by_role(MissionType.ORBITAL_DEFENSE))
    debug("Outpost Base Fleets: %s" %
          get_empire_fleet_ids_by_role(MissionType.ORBITAL_OUTPOST))
    debug("Invasion Base Fleets: %s" %
          get_empire_fleet_ids_by_role(MissionType.ORBITAL_INVASION))
    debug(
        "Securing Fleets: %s  (currently FLEET_MISSION_MILITARY should be used instead of this Role)"
        % (get_empire_fleet_ids_by_role(MissionType.SECURE)))

    aistate = get_aistate()
    if fo.currentTurn() < 50:
        debug('')
        debug("Explored systems:")
        _print_systems_and_supply(aistate.get_explored_system_ids())
        debug("Unexplored systems:")
        _print_systems_and_supply(aistate.get_unexplored_system_ids())
        debug('')

    exploration_fleet_missions = aistate.get_fleet_missions_with_any_mission_types(
        [MissionType.EXPLORATION])
    if exploration_fleet_missions:
        debug("Exploration targets:")
        for explorationAIFleetMission in exploration_fleet_missions:
            debug(" - %s" % explorationAIFleetMission)
    else:
        debug("Exploration targets: None")

    colonisation_fleet_missions = aistate.get_fleet_missions_with_any_mission_types(
        [MissionType.COLONISATION])
    if colonisation_fleet_missions:
        debug("Colonization targets: ")
    else:
        debug("Colonization targets: None")
    for colonisation_fleet_mission in colonisation_fleet_missions:
        debug("    %s" % colonisation_fleet_mission)

    outpost_fleet_missions = aistate.get_fleet_missions_with_any_mission_types(
        [MissionType.OUTPOST])
    if outpost_fleet_missions:
        debug("Outpost targets: ")
    else:
        debug("Outpost targets: None")
    for outpost_fleet_mission in outpost_fleet_missions:
        debug("    %s" % outpost_fleet_mission)

    outpost_base_fleet_missions = aistate.get_fleet_missions_with_any_mission_types(
        [MissionType.ORBITAL_OUTPOST])
    if outpost_base_fleet_missions:
        debug("Outpost Base targets (must have been interrupted by combat): ")
    else:
        debug(
            "Outpost Base targets: None (as expected, due to expected timing of order submission and execution)"
        )
    for outpost_fleet_mission in outpost_base_fleet_missions:
        debug("    %s" % outpost_fleet_mission)

    invasion_fleet_missions = aistate.get_fleet_missions_with_any_mission_types(
        [MissionType.INVASION])
    if invasion_fleet_missions:
        debug("Invasion targets: ")
    else:
        debug("Invasion targets: None")
    for invasion_fleet_mission in invasion_fleet_missions:
        debug("    %s" % invasion_fleet_mission)

    troop_base_fleet_missions = aistate.get_fleet_missions_with_any_mission_types(
        [MissionType.ORBITAL_INVASION])
    if troop_base_fleet_missions:
        debug("Invasion Base targets (must have been interrupted by combat): ")
    else:
        debug(
            "Invasion Base targets: None (as expected, due to expected timing of order submission and execution)"
        )
    for invasion_fleet_mission in troop_base_fleet_missions:
        debug("    %s" % invasion_fleet_mission)

    military_fleet_missions = aistate.get_fleet_missions_with_any_mission_types(
        [MissionType.MILITARY])
    if military_fleet_missions:
        debug("General Military targets: ")
    else:
        debug("General Military targets: None")
    for military_fleet_mission in military_fleet_missions:
        debug("    %s" % military_fleet_mission)

    secure_fleet_missions = aistate.get_fleet_missions_with_any_mission_types(
        [MissionType.SECURE])
    if secure_fleet_missions:
        debug("Secure targets: ")
    else:
        debug("Secure targets: None")
    for secure_fleet_mission in secure_fleet_missions:
        debug("    %s" % secure_fleet_mission)

    orb_defense_fleet_missions = aistate.get_fleet_missions_with_any_mission_types(
        [MissionType.ORBITAL_DEFENSE])
    if orb_defense_fleet_missions:
        debug("Orbital Defense targets: ")
    else:
        debug("Orbital Defense targets: None")
    for orb_defence_fleet_mission in orb_defense_fleet_missions:
        debug("    %s" % orb_defence_fleet_mission)

    fleet_missions = aistate.get_all_fleet_missions()
    destroyed_objects = fo.getUniverse().destroyedObjectIDs(fo.empireID())

    # merge fleets where appropriate before generating fleet orders.
    # This allows us to consider the full fleet strength when determining
    # e.g. whether to engage or avoid an enemy.
    for mission in fleet_missions:
        fleet_id = mission.fleet.id
        fleet = mission.fleet.get_object()
        if not fleet or not fleet.shipIDs or fleet_id in destroyed_objects:
            continue
        mission.check_mergers()
    # get new set of fleet missions without fleets that are empty after merge
    fleet_missions = aistate.get_all_fleet_missions()
    for mission in fleet_missions:
        mission.generate_fleet_orders()