User:The Silent One/colonisation code

From FreeOrionWiki
Jump to: navigation, search
import freeOrionAIInterface as fo
import pickle

# known issue: several colonyships can be sent to the same planet
# AI must keep track of planets to which it has sent colony ships just like with exploration (change RemoveUnsuitablePlanets accordingly)
# moving fleets with colony ship are intercepted and send to colonize

# currently only uses size and hospitality score
# later: specials, exploration, distance

# minimal value a planet must have to be colonised
minimal_colonise_value = 5


class planet_value(object):
  def __init__(self, ID=0, value=0):
    self.ID = ID
    self.value = value



def GenerateColonisationOrders():

    fo.LogOutput("Generating Colonisation Orders")

    

    empire = fo.GetEmpire()

    empire_id = fo.EmpireID()

    universe = fo.GetUniverse()

    # Look for stationary colonyships

    colonyship_ids = GetColonyshipIDs(empire_id, universe)
    if len(colonyship_ids) == 0: return
    fo.LogOutput("Available colony ships: " + str(colonyship_ids))

    # Colonize Target Planets (if colonyship has arrived)
    ColoniseTargetPlanets(colonyship_ids, universe)

    # Search for suitable planets
    system_ids = GetExploredSystemIDs(empire, universe)
    planet_ids = GetPlanetsInSystemsIDs(system_ids, universe)
    fo.LogOutput("All planets in range: " + str(planet_ids))

    RemoveUnsuitablePlanetIDs(planet_ids, universe)
    fo.LogOutput("Uncolonized planets without colony ship en route: " + str(planet_ids))

    # Judge Planet Colonisation Values, remove bad planets
    evaluated_planets = AssignColonisationValue(planet_ids, universe)

    RemoveBadPlanets(evaluated_planets)
    evaluated_planets.sort(key=value)   # correct sorting?
    if len(evaluated_planets) == 0: return
    fo.LogOutput("Attractive planets: " + str(evaluated_planets[0:-1].ID) + " Value: " + str(evaluated_planets[0:-1].value))

    # Send Colony Ships
    SendColonyShips(colonyship_ids, evaluated_planets)




# Helper functions, NOT to be called externally since globals will not be initialized

def GetColonyshipIDs(empireID, universe):
    fo.LogOutput("GetEmpireStationaryColonyFleetIDs")

            

    ship_ids = []
    object_ids = universe.ObjectIDs()



    for obj_id in object_ids:


        ship = universe.GetShip(obj_id)


        if (ship == None): continue                                     # it's not a ship

        if (not ship.whollyOwnedBy(empire_id)): continue                # it's not owned by the AI
        if (not ship.design.name = 'Colony Ship'): continue             # it's no colony ship       



        ship_ids.append(obj_id)



    return ship_ids


def ColoniseTargetPlanets(colonyship_ids, universe):   # probably needs change in C++ code, see below
    fo.LogOutput("Colonise Planets")

    for colonyship_id in colonyship_ids:

      colonyship = universe.GetShip(colonyship_id) 
      if (colonyship == None): continue

      if colonyship.systemID == colonyship.destinationID: # colonyship.destinationID?

        print "colonizing " + colonyship.destinationID
        fo.issueColonizeOrder(colonyship_id, colonyship.destinationID)


def GetExploredSystemIDs(empire, universe):

    fo.LogOutput("GetExploredSystemIDs")

     

    system_ids = []
    object_ids = universe.ObjectIDs()



    for obj_id in object_ids:        

      system = universe.GetSystem(obj_id)

      if (system == None): continue

      fo.LogOutput("...is a system")



      if (empire.HasExploredSystem(obj_id)):
        system_ids.append(obj_id)
        fo.LogOutput("...is explored")

    

    return system_ids


def GetPlanetsInSystemsIDs(system_ids, universe):   # may need change in C++ code or is an appropriate function available?
    fo.LogOutput("GetPlanetsInSystemsIDs")

    planet_ids = []

    for system_id in system_ids:

      system = universe.GetSystem(system_id)
      if (system == None): continue

      planet_ids.extend(system.orbits)   # System.Orbits??

    return planet_ids


def RemoveUnsuitablePlanetIDs(planet_ids, universe):
    fo.LogOutput("RemovePlanetIDs (Occupied, ToBeColonized)")

    for planet_id in planet_ids:

      planet = universe.GetPlanet(planet_id)

      if (planet == None): continue
      if not (planet.unowned): planet_ids.remove(planet_id)
     #if not (planet.NoColonyShipEnRoute): planet_ids_list = planet_ids_list - [planet_id]

    return planet_ids


def AssignColonisationValue(planet_ids, universe):
    fo.LogOutput("AssignColonisationValue")

    # assign colonisation values to ids
    planet_values = []

    for planet_id in planet_ids:
      value = planet_value(planet_id, EvaluatePlanet(planet_id, universe))
      planet_values.append(value)

    return planet_values


def EvaluatePlanet(planet_id, universe):
    fo.LogOutput("Evaluating planets")
    
    return GetPlanetHospitality(planet_id, universe) * planet.size # planet.size?


def GetPlanetHospitality(planet_id, universe):

    planet = universe.GetPlanet(planet_id)
    if planet = None: return 0

    # should be reworked with races
    if planet.type == fo.planetType.gaia: return 3
    if planet.type == fo.planetType.terran: return 2
    if planet.type == fo.planetType.ocean: return 1
    if planet.type == fo.planetType.desert: return 1
    if planet.type == fo.planetType.tundra: return 0.5
    if planet.type == fo.planetType.swamp: return 0.5

    return 0
    

def RemoveBadPlanets(evaluated_planets)

    for p_value in evaluated_planets:
      if p_value.value < minimal_colonise_value:
        evaluated_planets.remove(p_value)


def SendColonyShips(colonyship_ids, evaluated_planets, universe)

    for i in range(0, colonyship_ids.len):
      if i > len(evaluated_planets): return # quit if there are more ships than planets
      colonyship = universe.GetShip(colonyship_ids[i])
      IssueFleetMoveOrder(colonyship.fleetID, evaluated_planets[i].ID) # colonyship.fleetID?
      # set colonyship.destination