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: fleet_mission = aistate.get_fleet_mission(fleet_id) start = fleet_mission.get_location_target() 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)
def get_fleets_for_mission(target_stats, min_stats, cur_stats, starting_system, fleet_pool_set, fleet_list, species="", ensure_return=False): """Get fleets for a mission. Implements breadth-first search through systems starting at the **starting_sytem**. In each system, local fleets are checked if they are in the allowed **fleet_pool_set** and suitable for the mission. If so, they are added to the **fleet_list** and **cur_stats** is updated with the currently selected fleet summary. The search continues until the requirements defined in **target_stats** are met or there are no more systems/fleets. In that case, if the **min_stats** are covered, the **fleet_list** is returned anyway. Otherwise, an empty list is returned by the function, in which case the caller can make an evaluation of an emergency use of the found fleets in fleet_list; if not to be used they should be added back to the main pool. :param target_stats: stats the fleet should ideally meet :type target_stats: dict :param min_stats: minimum stats the final fleet must meet to be accepted :type min_stats: dict :param cur_stats: (**mutated**) stat summary of selected fleets :type cur_stats: dict :param starting_system: system_id where breadth-first-search is centered :type starting_system: int :param fleet_pool_set: (**mutated**) fleets allowed to be selected. Split fleed_ids are added, used ones removed. :type: fleet_pool_set: set[int] :param fleet_list: (**mutated**) fleets that are selected for the mission. Gets filled during the call. :type fleet_list: list[int] :param species: species for colonization mission :type species: str :param bool ensure_return: If true, fleet must have sufficient fuel to return into supply after mission :return: List of selected fleet_ids or empty list if couldn't meet minimum requirements. :rtype: list[int] """ universe = fo.getUniverse() colonization_roles = (ShipRoleType.CIVILIAN_COLONISATION, ShipRoleType.BASE_COLONISATION) systems_enqueued = [starting_system] systems_visited = [] # loop over systems in a breadth-first-search trying to find nearby suitable ships in fleet_pool_set aistate = get_aistate() while systems_enqueued and fleet_pool_set: this_system_id = systems_enqueued.pop(0) this_system_obj = TargetSystem(this_system_id) systems_visited.append(this_system_id) accessible_fleets = aistate.systemStatus.get(this_system_id, {}).get( 'myFleetsAccessible', []) fleets_here = [ fid for fid in accessible_fleets if fid in fleet_pool_set ] # loop over all fleets in the system, split them if possible and select suitable ships while fleets_here: fleet_id = fleets_here.pop(0) fleet = universe.getFleet(fleet_id) if not fleet: # TODO should be checked before passed to the function fleet_pool_set.remove(fleet_id) continue # try splitting fleet if fleet.numShips > 1: debug("Splitting candidate fleet to get ships for mission.") new_fleets = split_fleet(fleet_id) fleet_pool_set.update(new_fleets) fleets_here.extend(new_fleets) if ('target_system' in target_stats and not MoveUtilsAI.can_travel_to_system( fleet_id, this_system_obj, target_stats['target_system'], ensure_return=ensure_return)): continue # check species for colonization missions if species: for ship_id in fleet.shipIDs: ship = universe.getShip(ship_id) if (ship and aistate.get_ship_role( ship.design.id) in colonization_roles and species == ship.speciesName): break else: # no suitable species found continue # check troop capacity for invasion missions troop_capacity = 0 if 'troopCapacity' in target_stats: troop_capacity = count_troops_in_fleet(fleet_id) if troop_capacity <= 0: continue # check if we need additional rating vs planets this_rating_vs_planets = 0 if 'ratingVsPlanets' in target_stats: this_rating_vs_planets = aistate.get_rating( fleet_id, against_planets=True) if this_rating_vs_planets <= 0 and cur_stats.get( 'rating', 0) >= target_stats.get('rating', 0): # we already have enough general rating, so do not add any more warships useless against planets continue # all checks passed, add ship to selected fleets and update the stats try: fleet_pool_set.remove(fleet_id) except KeyError: error( "After having split a fleet, the original fleet apparently no longer exists.", exc_info=True) continue fleet_list.append(fleet_id) this_rating = aistate.get_rating(fleet_id) cur_stats['rating'] = CombatRatingsAI.combine_ratings( cur_stats.get('rating', 0), this_rating) if 'ratingVsPlanets' in target_stats: cur_stats['ratingVsPlanets'] = CombatRatingsAI.combine_ratings( cur_stats.get('ratingVsPlanets', 0), this_rating_vs_planets) if 'troopCapacity' in target_stats: cur_stats['troopCapacity'] = cur_stats.get('troopCapacity', 0) + troop_capacity # if we already meet the requirements, we can stop looking for more ships if (sum(len(universe.getFleet(fid).shipIDs) for fid in fleet_list) >= 1) \ and stats_meet_reqs(cur_stats, target_stats): return fleet_list # finished system without meeting requirements. Add neighboring systems to search queue. for neighbor_id in universe.getImmediateNeighbors( this_system_id, fo.empireID()): if all((neighbor_id not in systems_visited, neighbor_id not in systems_enqueued, neighbor_id in aistate.exploredSystemIDs)): systems_enqueued.append(neighbor_id) # we ran out of systems or fleets to check but did not meet requirements yet. if stats_meet_reqs(cur_stats, min_stats) and any( universe.getFleet(fid).shipIDs for fid in fleet_list): return fleet_list else: return []
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( fleet_id, fleet_mission.get_location_target(), target, ensure_return=True): 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 """
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: fleet_mission = aistate.get_fleet_mission(fleet_id) start = fleet_mission.get_location_target() 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)
def get_fleets_for_mission(target_stats, min_stats, cur_stats, starting_system, fleet_pool_set, fleet_list, species=""): """Get fleets for a mission. Implements breadth-first search through systems starting at the **starting_sytem**. In each system, local fleets are checked if they are in the allowed **fleet_pool_set** and suitable for the mission. If so, they are added to the **fleet_list** and **cur_stats** is updated with the currently selected fleet summary. The search continues until the requirements defined in **target_stats** are met or there are no more systems/fleets. In that case, if the **min_stats** are covered, the **fleet_list** is returned anyway. Otherwise, an empty list is returned by the function, in which case the caller can make an evaluation of an emergency use of the found fleets in fleet_list; if not to be used they should be added back to the main pool. :param target_stats: stats the fleet should ideally meet :type target_stats: dict :param min_stats: minimum stats the final fleet must meet to be accepted :type min_stats: dict :param cur_stats: (**mutated**) stat summary of selected fleets :type cur_stats: dict :param starting_system: system_id where breadth-first-search is centered :type starting_system: int :param fleet_pool_set: (**mutated**) fleets allowed to be selected. Split fleed_ids are added, used ones removed. :type: fleet_pool_set: set[int] :param fleet_list: (**mutated**) fleets that are selected for the mission. Gets filled during the call. :type fleet_list: list[int] :param species: species for colonization mission :type species: str :return: List of selected fleet_ids or empty list if couldn't meet minimum requirements. :rtype: list[int] """ universe = fo.getUniverse() colonization_roles = (ShipRoleType.CIVILIAN_COLONISATION, ShipRoleType.BASE_COLONISATION) systems_enqueued = [starting_system] systems_visited = [] # loop over systems in a breadth-first-search trying to find nearby suitable ships in fleet_pool_set aistate = get_aistate() while systems_enqueued and fleet_pool_set: this_system_id = systems_enqueued.pop(0) this_system_obj = universe_object.System(this_system_id) systems_visited.append(this_system_id) accessible_fleets = aistate.systemStatus.get(this_system_id, {}).get('myFleetsAccessible', []) fleets_here = [fid for fid in accessible_fleets if fid in fleet_pool_set] # loop over all fleets in the system, split them if possible and select suitable ships while fleets_here: fleet_id = fleets_here.pop(0) fleet = universe.getFleet(fleet_id) if not fleet: # TODO should be checked before passed to the function fleet_pool_set.remove(fleet_id) continue # try splitting fleet if len(list(fleet.shipIDs)) > 1: new_fleets = split_fleet(fleet_id) fleet_pool_set.update(new_fleets) fleets_here.extend(new_fleets) # check species for colonization missions if species: for ship_id in fleet.shipIDs: ship = universe.getShip(ship_id) if (ship and aistate.get_ship_role(ship.design.id) in colonization_roles and species == ship.speciesName): break else: # no suitable species found continue # check troop capacity for invasion missions troop_capacity = 0 if 'troopCapacity' in target_stats: troop_capacity = count_troops_in_fleet(fleet_id) if troop_capacity <= 0: continue if 'target_system' in target_stats: if not MoveUtilsAI.can_travel_to_system(fleet_id, this_system_obj, target_stats['target_system']): continue # check if we need additional rating vs planets this_rating_vs_planets = 0 if 'ratingVsPlanets' in target_stats: this_rating_vs_planets = aistate.get_rating(fleet_id, against_planets=True) if this_rating_vs_planets <= 0 and cur_stats.get('rating', 0) >= target_stats.get('rating', 0): # we already have enough general rating, so do not add any more warships useless against planets continue # all checks passed, add ship to selected fleets and update the stats try: fleet_pool_set.remove(fleet_id) except KeyError: error("After having split a fleet, the original fleet apparently no longer exists.", exc_info=True) continue fleet_list.append(fleet_id) this_rating = aistate.get_rating(fleet_id) cur_stats['rating'] = CombatRatingsAI.combine_ratings(cur_stats.get('rating', 0), this_rating) if 'ratingVsPlanets' in target_stats: cur_stats['ratingVsPlanets'] = CombatRatingsAI.combine_ratings(cur_stats.get('ratingVsPlanets', 0), this_rating_vs_planets) if 'troopCapacity' in target_stats: cur_stats['troopCapacity'] = cur_stats.get('troopCapacity', 0) + troop_capacity # if we already meet the requirements, we can stop looking for more ships if (sum(len(universe.getFleet(fid).shipIDs) for fid in fleet_list) >= 1) \ and stats_meet_reqs(cur_stats, target_stats): return fleet_list # finished system without meeting requirements. Add neighboring systems to search queue. for neighbor_id in universe.getImmediateNeighbors(this_system_id, fo.empireID()): if all(( neighbor_id not in systems_visited, neighbor_id not in systems_enqueued, neighbor_id in aistate.exploredSystemIDs )): systems_enqueued.append(neighbor_id) # we ran out of systems or fleets to check but did not meet requirements yet. if stats_meet_reqs(cur_stats, min_stats) and any(universe.getFleet(fid).shipIDs for fid in fleet_list): return fleet_list else: return []
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(fleet_id, fleet_mission.get_location_target(), target, ensure_return=True): 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 """