parameters: ()
docstring: Generate research orders.
docstring_summary: Generate research orders.
docstring_tokens: Generate research orders .
function: def generate_research_orders():
      """Generate research orders."""
  
      if use_classic_research_approach():
          debug("Classical research approach is used")
          generate_classic_research_orders()
          return
      else:
          debug("New research approach is used")
  
      # initializing priority functions here within generate_research_orders() to avoid import race
      if not priority_funcs:
          init()
  
      empire = fo.getEmpire()
      empire_id = empire.empireID
      completed_techs = get_completed_techs()
      debug("Research Queue Management on turn %d:", fo.currentTurn())
      debug("ColonisationAI survey:")
      debug("  have asteroids: %s", have_asteroids())
      debug("  have gas giant: %s", have_gas_giant())
      debug("  have ruins: %s", have_ruins())
  
      resource_production = empire.resourceProduction(fo.resourceType.research)
      debug("\nTotal Current Research Points: %.2f\n", resource_production)
      debug("Techs researched and available for use:")
      print_in_columns(sorted(completed_techs))
  
      #
      # report techs currently at head of research queue
      #
      research_queue = empire.researchQueue
      research_queue_list = get_research_queue_techs()
      tech_turns_left = {}
      if research_queue_list:
          debug("Techs currently at head of Research Queue:")
          for element in list(research_queue)[:10]:
              tech_turns_left[element.tech] = element.turnsLeft
              this_tech = fo.getTech(element.tech)
              if not this_tech:
                  warning("Can't retrieve tech ", element.tech)
                  continue
              missing_prereqs = [
                  preReq for preReq in this_tech.recursivePrerequisites(empire_id) if preReq not in completed_techs
              ]
              # unlocked_items = [(uli.name, uli.type) for uli in this_tech.unlocked_items]
              unlocked_items = [uli.name for uli in this_tech.unlockedItems]
              if not missing_prereqs:
                  debug(
                      "  %25s allocated %6.2f RP -- unlockable items: %s",
                      element.tech,
                      element.allocation,
                      unlocked_items,
                  )
              else:
                  debug(
                      "  %25s allocated %6.2f RP -- missing preReqs: %s -- unlockable items: %s",
                      element.tech,
                      element.allocation,
                      missing_prereqs,
                      unlocked_items,
                  )
          debug("")
  
      #
      # calculate all research priorities, as in get_priority(tech) / total cost of tech (including prereqs)
      #
      calculate_research_requirements()
      total_rp = empire.resourceProduction(fo.resourceType.research)
  
      if total_rp <= 0:  # No RP available - no research.
          return
  
      base_priorities = {}
      priorities = {}
      on_path_to = {}
      for tech_name in fo.techs():
          this_tech = fo.getTech(tech_name)
          if not this_tech or tech_is_complete(tech_name):
              continue
          base_priorities[tech_name] = priorities[tech_name] = get_priority(tech_name)
  
      # inherited priorities are modestly attenuated by total time
      timescale_period = 30.0
      for tech_name, priority in base_priorities.items():
          if priority >= 0:
              turns_needed = max(
                  research_reqs[tech_name][REQS_TIME_IDX],
                  math.ceil(float(research_reqs[tech_name][REQS_COST_IDX]) / total_rp),
              )
              time_attenuation = 2 ** (-max(0.0, turns_needed - 5) / timescale_period)
              attenuated_priority = priority * time_attenuation
              for prereq in research_reqs.get(tech_name, ([], 0, 0, 0))[REQS_PREREQS_IDX]:
                  if (
                      prereq in priorities and attenuated_priority > priorities[prereq]
                  ):  # checking like this to keep finished techs out of priorities
                      priorities[prereq] = attenuated_priority
                      on_path_to[prereq] = tech_name
  
      # final priorities are scaled by a combination of relative per-turn cost and relative total cost
      for tech_name, priority in priorities.items():
          if priority >= 0:
              relative_turn_cost = max(research_reqs[tech_name][REQS_PER_TURN_COST_IDX], 0.1) / total_rp
              relative_total_cost = max(research_reqs[tech_name][REQS_COST_IDX], 0.1) / total_rp
              cost_factor = 2.0 / (relative_turn_cost + relative_total_cost)
              adjusted_priority = float(priority) * cost_factor
              # if priority > 1:
              #    print "tech %s has raw priority %.1f and adjusted priority %.1f, with %.1f total remaining cost, %.1f min turns needed and %.1f projected turns needed" % (tech_name, priority, adjusted_priority, research_reqs[tech_name][REQS_COST_IDX], research_reqs[tech_name][REQS_TIME_IDX], turns_needed)
              priorities[tech_name] = adjusted_priority
  
      #
      # put in highest priority techs until all RP spent, with  time then cost as minor sorting keys
      #
      possible = sorted(priorities.keys(), key=tech_cost_sort_key)
      possible.sort(key=tech_time_sort_key)
      possible.sort(key=priorities.__getitem__, reverse=True)
  
      missing_prereq_list = []
      debug("Research priorities")
      debug("  %-25s %8s %8s %8s %-25s %s", "Name", "Priority", "Cost", "Time", "As Prereq To", "Missing Prerequisties")
      for idx, tech_name in enumerate(possible[:20]):
          tech_info = research_reqs[tech_name]
          debug(
              "  %-25s %8.4f %8.2f %8.2f %-25s %s",
              tech_name,
              priorities[tech_name],
              tech_info[1],
              tech_info[2],
              on_path_to.get(tech_name, ""),
              tech_info[0],
          )
          missing_prereq_list.extend(
              [prereq for prereq in tech_info[0] if prereq not in possible[:idx] and not tech_is_complete(prereq)]
          )
      debug("")
  
      if missing_prereq_list:
          debug("Prerequirements seeming out of order:")
          debug(
              "  %-25s %8s %8s %8s %8s %-25s %s",
              "Name",
              "Priority",
              "Base Prio",
              "Cost",
              "Time",
              "As Prereq To",
              "Missing Prerequisties",
          )
          for tech_name in missing_prereq_list:
              tech_info = research_reqs[tech_name]
              debug(
                  "  %-25s %8.4f %8.4f %8.2f %8.2f %-25s %s",
                  tech_name,
                  priorities[tech_name],
                  base_priorities[tech_name],
                  tech_info[1],
                  tech_info[2],
                  on_path_to.get(tech_name, ""),
                  tech_info[0],
              )
  
      debug("Enqueuing techs, already spent %.2f RP of %.2f RP", fo.getEmpire().researchQueue.totalSpent, total_rp)
      possible = [x for x in possible if x not in set(get_research_queue_techs())]
      # some floating point issues can cause AI to enqueue every tech......
      while empire.resourceProduction(fo.resourceType.research) - empire.researchQueue.totalSpent > 0.001 and possible:
          to_research = possible.pop(0)  # get tech with highest priority
          fo.issueEnqueueTechOrder(to_research, -1)
          fo.updateResearchQueue()
          debug(
              "  %-25s %6.2f RP/turn %6.2f RP",
              to_research,
              fo.getTech(to_research).perTurnCost(empire.empireID),
              fo.getTech(to_research).researchCost(empire.empireID),
          )
  
      debug(
          "Finish research orders, spent %.2f RP of %.2f RP\n",
          fo.getEmpire().researchQueue.totalSpent,
          empire.resourceProduction(fo.resourceType.research),
      )
function_tokens: def generate_research_orders ( ) : if use_classic_research_approach ( ) : debug ( "Classical research approach is used" ) generate_classic_research_orders ( ) return else : debug ( "New research approach is used" ) # initializing priority functions here within generate_research_orders() to avoid import race if not priority_funcs : init ( ) empire = fo . getEmpire ( ) empire_id = empire . empireID completed_techs = get_completed_techs ( ) debug ( "Research Queue Management on turn %d:" , fo . currentTurn ( ) ) debug ( "ColonisationAI survey:" ) debug ( "  have asteroids: %s" , have_asteroids ( ) ) debug ( "  have gas giant: %s" , have_gas_giant ( ) ) debug ( "  have ruins: %s" , have_ruins ( ) ) resource_production = empire . resourceProduction ( fo . resourceType . research ) debug ( "\nTotal Current Research Points: %.2f\n" , resource_production ) debug ( "Techs researched and available for use:" ) print_in_columns ( sorted ( completed_techs ) ) # # report techs currently at head of research queue # research_queue = empire . researchQueue research_queue_list = get_research_queue_techs ( ) tech_turns_left = { } if research_queue_list : debug ( "Techs currently at head of Research Queue:" ) for element in list ( research_queue ) [ : 10 ] : tech_turns_left [ element . tech ] = element . turnsLeft this_tech = fo . getTech ( element . tech ) if not this_tech : warning ( "Can't retrieve tech " , element . tech ) continue missing_prereqs = [ preReq for preReq in this_tech . recursivePrerequisites ( empire_id ) if preReq not in completed_techs ] # unlocked_items = [(uli.name, uli.type) for uli in this_tech.unlocked_items] unlocked_items = [ uli . name for uli in this_tech . unlockedItems ] if not missing_prereqs : debug ( "  %25s allocated %6.2f RP -- unlockable items: %s" , element . tech , element . allocation , unlocked_items , ) else : debug ( "  %25s allocated %6.2f RP -- missing preReqs: %s -- unlockable items: %s" , element . tech , element . allocation , missing_prereqs , unlocked_items , ) debug ( "" ) # # calculate all research priorities, as in get_priority(tech) / total cost of tech (including prereqs) # calculate_research_requirements ( ) total_rp = empire . resourceProduction ( fo . resourceType . research ) if total_rp <= 0 : # No RP available - no research. return base_priorities = { } priorities = { } on_path_to = { } for tech_name in fo . techs ( ) : this_tech = fo . getTech ( tech_name ) if not this_tech or tech_is_complete ( tech_name ) : continue base_priorities [ tech_name ] = priorities [ tech_name ] = get_priority ( tech_name ) # inherited priorities are modestly attenuated by total time timescale_period = 30.0 for tech_name , priority in base_priorities . items ( ) : if priority >= 0 : turns_needed = max ( research_reqs [ tech_name ] [ REQS_TIME_IDX ] , math . ceil ( float ( research_reqs [ tech_name ] [ REQS_COST_IDX ] ) / total_rp ) , ) time_attenuation = 2 ** ( - max ( 0.0 , turns_needed - 5 ) / timescale_period ) attenuated_priority = priority * time_attenuation for prereq in research_reqs . get ( tech_name , ( [ ] , 0 , 0 , 0 ) ) [ REQS_PREREQS_IDX ] : if ( prereq in priorities and attenuated_priority > priorities [ prereq ] ) : # checking like this to keep finished techs out of priorities priorities [ prereq ] = attenuated_priority on_path_to [ prereq ] = tech_name # final priorities are scaled by a combination of relative per-turn cost and relative total cost for tech_name , priority in priorities . items ( ) : if priority >= 0 : relative_turn_cost = max ( research_reqs [ tech_name ] [ REQS_PER_TURN_COST_IDX ] , 0.1 ) / total_rp relative_total_cost = max ( research_reqs [ tech_name ] [ REQS_COST_IDX ] , 0.1 ) / total_rp cost_factor = 2.0 / ( relative_turn_cost + relative_total_cost ) adjusted_priority = float ( priority ) * cost_factor # if priority > 1: #    print "tech %s has raw priority %.1f and adjusted priority %.1f, with %.1f total remaining cost, %.1f min turns needed and %.1f projected turns needed" % (tech_name, priority, adjusted_priority, research_reqs[tech_name][REQS_COST_IDX], research_reqs[tech_name][REQS_TIME_IDX], turns_needed) priorities [ tech_name ] = adjusted_priority # # put in highest priority techs until all RP spent, with  time then cost as minor sorting keys # possible = sorted ( priorities . keys ( ) , key = tech_cost_sort_key ) possible . sort ( key = tech_time_sort_key ) possible . sort ( key = priorities . __getitem__ , reverse = True ) missing_prereq_list = [ ] debug ( "Research priorities" ) debug ( "  %-25s %8s %8s %8s %-25s %s" , "Name" , "Priority" , "Cost" , "Time" , "As Prereq To" , "Missing Prerequisties" ) for idx , tech_name in enumerate ( possible [ : 20 ] ) : tech_info = research_reqs [ tech_name ] debug ( "  %-25s %8.4f %8.2f %8.2f %-25s %s" , tech_name , priorities [ tech_name ] , tech_info [ 1 ] , tech_info [ 2 ] , on_path_to . get ( tech_name , "" ) , tech_info [ 0 ] , ) missing_prereq_list . extend ( [ prereq for prereq in tech_info [ 0 ] if prereq not in possible [ : idx ] and not tech_is_complete ( prereq ) ] ) debug ( "" ) if missing_prereq_list : debug ( "Prerequirements seeming out of order:" ) debug ( "  %-25s %8s %8s %8s %8s %-25s %s" , "Name" , "Priority" , "Base Prio" , "Cost" , "Time" , "As Prereq To" , "Missing Prerequisties" , ) for tech_name in missing_prereq_list : tech_info = research_reqs [ tech_name ] debug ( "  %-25s %8.4f %8.4f %8.2f %8.2f %-25s %s" , tech_name , priorities [ tech_name ] , base_priorities [ tech_name ] , tech_info [ 1 ] , tech_info [ 2 ] , on_path_to . get ( tech_name , "" ) , tech_info [ 0 ] , ) debug ( "Enqueuing techs, already spent %.2f RP of %.2f RP" , fo . getEmpire ( ) . researchQueue . totalSpent , total_rp ) possible = [ x for x in possible if x not in set ( get_research_queue_techs ( ) ) ] # some floating point issues can cause AI to enqueue every tech...... while empire . resourceProduction ( fo . resourceType . research ) - empire . researchQueue . totalSpent > 0.001 and possible : to_research = possible . pop ( 0 ) # get tech with highest priority fo . issueEnqueueTechOrder ( to_research , - 1 ) fo . updateResearchQueue ( ) debug ( "  %-25s %6.2f RP/turn %6.2f RP" , to_research , fo . getTech ( to_research ) . perTurnCost ( empire . empireID ) , fo . getTech ( to_research ) . researchCost ( empire . empireID ) , ) debug ( "Finish research orders, spent %.2f RP of %.2f RP\n" , fo . getEmpire ( ) . researchQueue . totalSpent , empire . resourceProduction ( fo . resourceType . research ) , )