Complete.Org: Mailing Lists: Archives: freeciv-dev: March 2005:
[Freeciv-Dev] (PR#12538) Speed up AI unit handling
Home

[Freeciv-Dev] (PR#12538) Speed up AI unit handling

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
Subject: [Freeciv-Dev] (PR#12538) Speed up AI unit handling
From: "Per I. Mathisen" <per@xxxxxxxxxxx>
Date: Fri, 18 Mar 2005 05:43:23 -0800
Reply-to: bugs@xxxxxxxxxxx

<URL: http://bugs.freeciv.org/Ticket/Display.html?id=12538 >

This patch makes the AI try harder to avoid managing units twice in a
turn. For the most part (2/3 to 3/4 of the time), it will succeed, and the
unit will only be managed once. Speed increase should be considerable
within this part of the code, but unit handling is not the biggest CPU
hog.

  - Per

Index: ai/aiferry.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/aiferry.c,v
retrieving revision 1.15
diff -u -r1.15 aiferry.c
--- ai/aiferry.c        14 Mar 2005 20:26:24 -0000      1.15
+++ ai/aiferry.c        18 Mar 2005 13:38:15 -0000
@@ -731,6 +731,7 @@
       && (pcity = map_get_city(punit->tile))) {
     UNIT_LOG(LOGLEVEL_FERRY, punit, "waiting in %s to recover hitpoints", 
              pcity->name);
+    punit->ai.done = TRUE;
     return;
   }
 
@@ -826,6 +827,7 @@
   if (IS_ATTACKER(punit) && punit->moves_left > 0) {
      /* AI used to build frigates to attack and then use them as ferries 
       * -- Syela */
+     ai_unit_new_role(punit, AIUNIT_ATTACK, NULL);
      UNIT_LOG(LOGLEVEL_FERRY, punit, "passing ferry over to attack code");
      ai_manage_military(pplayer, punit);
      return;
@@ -842,7 +844,7 @@
   if (aiferry_findcargo(punit)) {
     UNIT_LOG(LOGLEVEL_FERRY, punit, "picking up cargo (moves left: %d)",
             punit->moves_left);
-    ai_unit_goto(punit, punit->goto_tile);
+    (void) ai_unit_goto(punit, punit->goto_tile);
     return;
   }
 
@@ -850,22 +852,30 @@
   if (aiferry_find_interested_city(punit)) {
     if (same_pos(punit->tile, punit->goto_tile)) {
       UNIT_LOG(LOGLEVEL_FERRY, punit, "staying in city that needs us");
+      punit->ai.done = TRUE;
       return;
     } else {
       UNIT_LOG(LOGLEVEL_FERRY, punit, "going to city that needs us");
-      (void) ai_unit_goto(punit, punit->goto_tile);
+      if (ai_unit_goto(punit, punit->goto_tile)
+          && same_pos(punit->tile, punit->goto_tile)) {
+        punit->ai.done = TRUE; /* save some CPU */
+      }
       return;
     }
   }
 
   UNIT_LOG(LOGLEVEL_FERRY, punit, "Passing control of ferry to explorer code");
-  (void) ai_manage_explorer(punit);
+  if (!ai_manage_explorer(punit)) {
+    punit->ai.done = TRUE;
+  }
 
   if (find_unit_by_id(sanity) && punit->moves_left > 0) {
     struct city *pcity = find_nearest_safe_city(punit);
     if (pcity) {
       punit->goto_tile = pcity->tile;
       UNIT_LOG(LOGLEVEL_FERRY, punit, "No work, going home");
+      punit->ai.done = TRUE;
+      ai_unit_new_role(punit, AIUNIT_NONE, NULL);
       (void) ai_unit_goto(punit, pcity->tile);
     }
   }
Index: ai/aitools.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/aitools.c,v
retrieving revision 1.139
diff -u -r1.139 aitools.c
--- ai/aitools.c        14 Mar 2005 20:26:24 -0000      1.139
+++ ai/aitools.c        18 Mar 2005 13:38:15 -0000
@@ -57,6 +57,41 @@
 #include "aitools.h"
 
 /**************************************************************************
+  Return a string describing a unit's AI role.
+**************************************************************************/
+const char *get_ai_role_str(enum ai_unit_task task)
+{
+  switch(task) {
+   case AIUNIT_NONE:
+     return "None";
+   case AIUNIT_AUTO_SETTLER:
+     return "Auto settler";
+   case AIUNIT_BUILD_CITY:
+     return "Build city";
+   case AIUNIT_DEFEND_HOME:
+     return "Defend home";
+   case AIUNIT_ATTACK:
+     return "Attack";
+   case AIUNIT_FORTIFY:
+     return "Fortify";
+   case AIUNIT_RUNAWAY:
+     return "Run away";
+   case AIUNIT_ESCORT:
+     return "Escort";
+   case AIUNIT_EXPLORE:
+     return "Explore";
+   case AIUNIT_PILLAGE:
+     return "Pillage";
+   case AIUNIT_RECOVER:
+     return "Recover";
+   case AIUNIT_HUNTER:
+     return "Hunter";
+  }
+  assert(FALSE);
+  return NULL;
+}
+
+/**************************************************************************
   Amortize a want modified by the shields (build_cost) we risk losing.
   We add the build time of the unit(s) we risk to amortize delay.  The
   build time is claculated as the build cost divided by the production
Index: ai/aitools.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/aitools.h,v
retrieving revision 1.50
diff -u -r1.50 aitools.h
--- ai/aitools.h        3 Feb 2005 09:48:53 -0000       1.50
+++ ai/aitools.h        18 Mar 2005 13:38:15 -0000
@@ -37,6 +37,8 @@
   BODYGUARD_NONE
 };
 
+const char *get_ai_role_str(enum ai_unit_task task);
+
 int military_amortize(struct player *pplayer, struct city *pcity, 
                       int value, int delay, int build_cost);
 int stack_cost(struct unit *pdef);
Index: ai/aiunit.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/aiunit.c,v
retrieving revision 1.346
diff -u -r1.346 aiunit.c
--- ai/aiunit.c 14 Mar 2005 20:26:24 -0000      1.346
+++ ai/aiunit.c 18 Mar 2005 13:38:15 -0000
@@ -817,8 +817,11 @@
   /* I had these guys set to just fortify, which is so dumb. -- Syela
    * Instead we can attack adjacent units and maybe even pick up some free 
    * cities! */
-  (void) ai_military_rampage(punit, BODYGUARD_RAMPAGE_THRESHOLD,
-                             RAMPAGE_FREE_CITY_OR_BETTER);
+  if (ai_military_rampage(punit, BODYGUARD_RAMPAGE_THRESHOLD,
+                          RAMPAGE_FREE_CITY_OR_BETTER)
+      && same_pos(punit->tile, ptile)) {
+    punit->ai.done = TRUE; /* Stay with charge */
+  }
 }
 
 /*************************************************************************
@@ -1172,6 +1175,7 @@
     if (same_pos(punit->tile, pcity->tile)) {
       UNIT_LOG(LOG_DEBUG, punit, "go home successful; role AI_NONE");
       ai_unit_new_role(punit, AIUNIT_NONE, NULL);
+      punit->ai.done = TRUE;
 
       /* aggro defense goes here -- Syela */
       /* Attack anything that won't kill us */
@@ -1784,6 +1788,7 @@
       /* This city needs defending, don't go outside! */
       UNIT_LOG(LOG_DEBUG, punit, "stayed to defend %s", 
                map_get_city(punit->tile)->name);
+      punit->ai.done = TRUE;
       return;
     }
 
@@ -1872,6 +1877,7 @@
     struct city *pcity = map_get_city(punit->tile);
 
     if (pcity) {
+      punit->ai.done = TRUE;
       ai_unit_new_role(punit, AIUNIT_DEFEND_HOME, pcity->tile);
       /* FIXME: Send unit to nearest city needing more defence */
       UNIT_LOG(LOG_DEBUG, punit, "could not find work, sitting duck");
@@ -2007,6 +2013,8 @@
     UNIT_LOG(LOGLEVEL_RECOVERY, punit, "ready to kick ass again!");
     ai_unit_new_role(punit, AIUNIT_NONE, NULL);  
     return;
+  } else {
+    punit->ai.done = TRUE; /* sit tight */
   }
 }
 
@@ -2021,7 +2029,8 @@
   CHECK_UNIT(punit);
 
   /* "Escorting" aircraft should not do anything. They are activated
-   * by their transport or charge. */
+   * by their transport or charge.  We do _NOT_ set them to 'done'
+   * since they may need be activated once our charge moves. */
   if (punit->ai.ai_role == AIUNIT_ESCORT && is_air_unit(punit)) {
     return;
   }
@@ -2031,6 +2040,7 @@
       && ai_handicap(pplayer, H_AWAY)) {
     /* Don't move sentried or fortified units controlled by a player
      * in away mode. */
+    punit->ai.done = TRUE;
     return;
   }
 
@@ -2043,7 +2053,7 @@
   switch (punit->ai.ai_role) {
   case AIUNIT_AUTO_SETTLER:
   case AIUNIT_BUILD_CITY:
-    ai_unit_new_role(punit, AIUNIT_NONE, NULL);
+    assert(FALSE); /* This is not the place for this role */
     break;
   case AIUNIT_DEFEND_HOME:
     ai_military_gohome(pplayer, punit);
@@ -2055,6 +2065,7 @@
     ai_military_gohome(pplayer, punit);
     break;
   case AIUNIT_RUNAWAY: 
+    /* ??? */
     break;
   case AIUNIT_ESCORT: 
     ai_military_bodyguard(pplayer, punit);
@@ -2063,7 +2074,7 @@
     handle_unit_activity_request(punit, ACTIVITY_PILLAGE);
     return; /* when you pillage, you have moves left, avoid later fortify */
   case AIUNIT_EXPLORE:
-    (void) ai_manage_explorer(punit);
+    punit->ai.done = !(ai_manage_explorer(punit) && punit->moves_left > 0);
     break;
   case AIUNIT_RECOVER:
     ai_manage_hitpoint_recovery(punit);
@@ -2128,6 +2139,7 @@
   /* Don't manage the unit if it is under human orders. */
   if (unit_has_orders(punit)) {
     punit->ai.ai_role = AIUNIT_NONE;
+    punit->ai.done = TRUE;
     return;
   }
 
@@ -2135,15 +2147,10 @@
      function */
   if( is_barbarian(pplayer) ) {
     /* Todo: should be configurable */
-    if( unit_can_be_retired(punit) && myrand(100) > 90 ) {
+    if (unit_can_be_retired(punit) && myrand(100) > 90) {
       wipe_unit(punit);
       return;
     }
-    if( !is_military_unit(punit)
-       && !unit_has_role(punit->type, L_BARBARIAN_LEADER)) {
-      freelog(LOG_VERBOSE, "Barbarians picked up non-military unit.");
-      return;
-    }
   }
 
   /* Check if we have lost our bodyguard. If we never had one, all
@@ -2155,6 +2162,7 @@
 
   if (punit->moves_left <= 0) {
     /* Can do nothing */
+    punit->ai.done = TRUE;
     return;
   }
 
@@ -2185,6 +2193,7 @@
   } else if (is_heli_unit(punit)) {
     /* TODO: We can try using air-unit code for helicopters, just
      * pretend they have fuel = HP / 3 or something. */
+    punit->ai.done = TRUE; /* we did our best, which was ... nothing */
     return;
   } else if (is_military_unit(punit)) {
     ai_manage_military(pplayer,punit); 
@@ -2203,17 +2212,30 @@
 
 /**************************************************************************
   Master manage unit function.
+
+  A manage function should set the unit to 'done' when it should no
+  longer be touched by this code, and its role should be reset to IDLE
+  when its role has accomplished its mission or the manage function
+  fails to have or no longer has any use for the unit.
 **************************************************************************/
 void ai_manage_units(struct player *pplayer) 
 {
   ai_airlift(pplayer);
+
+  unit_list_iterate(pplayer->units, punit) {
+    punit->ai.done = FALSE;
+  } unit_list_iterate_end;
+
   unit_list_iterate_safe(pplayer->units, punit) {
     ai_manage_unit(pplayer, punit);
   } unit_list_iterate_safe_end;
+
   /* Sometimes units wait for other units to move so we crudely
    * solve it by moving everything again */ 
   unit_list_iterate_safe(pplayer->units, punit) {
-    ai_manage_unit(pplayer, punit);
+    if (punit->moves_left > 0 && !punit->ai.done) {
+      ai_manage_unit(pplayer, punit);
+    }
   } unit_list_iterate_safe_end;
 }
 
Index: common/unit.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/unit.c,v
retrieving revision 1.230
diff -u -r1.230 unit.c
--- common/unit.c       14 Mar 2005 20:26:25 -0000      1.230
+++ common/unit.c       18 Mar 2005 13:38:16 -0000
@@ -1468,6 +1468,7 @@
   if (is_barbarian(pplayer)) {
     punit->fuel = BARBARIAN_LIFE;
   }
+  punit->ai.done = FALSE;
   punit->ai.cur_pos = NULL;
   punit->ai.prev_pos = NULL;
   punit->ai.target = 0;
Index: common/unit.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/unit.h,v
retrieving revision 1.137
diff -u -r1.137 unit.h
--- common/unit.h       14 Mar 2005 20:26:25 -0000      1.137
+++ common/unit.h       18 Mar 2005 13:38:16 -0000
@@ -119,6 +119,7 @@
 
   int target; /* target we hunt */
   int hunted; /* if a player is hunting us, set by that player */
+  bool done;  /* we are done controlling this unit this turn */
 };
 
 struct unit {
Index: server/settlers.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/settlers.c,v
retrieving revision 1.222
diff -u -r1.222 settlers.c
--- server/settlers.c   14 Mar 2005 20:26:26 -0000      1.222
+++ server/settlers.c   18 Mar 2005 13:38:16 -0000
@@ -147,6 +147,7 @@
 void ai_manage_settler(struct player *pplayer, struct unit *punit)
 {
   punit->ai.control = TRUE;
+  punit->ai.done = TRUE; /* we will manage this unit later... ugh */
   /* if BUILD_CITY must remain BUILD_CITY, otherwise turn into autosettler */
   if (punit->ai.ai_role == AIUNIT_NONE) {
     ai_unit_new_role(punit, AIUNIT_AUTO_SETTLER, NULL);

[Prev in Thread] Current Thread [Next in Thread]
  • [Freeciv-Dev] (PR#12538) Speed up AI unit handling, Per I. Mathisen <=