Complete.Org: Mailing Lists: Archives: freeciv-dev: April 2005:
[Freeciv-Dev] Re: (PR#12840) delay in pollution patrol (possible causes)
Home

[Freeciv-Dev] Re: (PR#12840) delay in pollution patrol (possible causes)

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
Subject: [Freeciv-Dev] Re: (PR#12840) delay in pollution patrol (possible causes)
From: "Brian Dunstan" <bdunstan149@xxxxxxxxx>
Date: Fri, 29 Apr 2005 15:12:02 -0700
Reply-to: bugs@xxxxxxxxxxx

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

OK, here is the patch with that change made.


--- Jason Short <jdorje@xxxxxxxxxxxxxxxxxxxxx> wrote:
> 
> <URL:
> http://bugs.freeciv.org/Ticket/Display.html?id=12840
> >
> 
> unit_list_find is super-slow, O(n).  You should be
> using
> player_find_unit_by_id instead.  This does a hash
> lookup and is about O(1).
> 
> -jason
> 
> 

__________________________________________________
Do You Yahoo!?
Tired of spam?  Yahoo! Mail has the best spam protection around 
http://mail.yahoo.com 
diff -Nur -Xfreeciv/diff_ignore freeciv/server/settlers.c 
freeciv_nopollute/server/settlers.c
--- freeciv/server/settlers.c   2005-04-26 11:12:40.000000000 -0400
+++ freeciv_nopollute/server/settlers.c 2005-04-27 22:24:35.495276424 -0400
@@ -835,10 +835,21 @@
   this return value is >0, then (gx,gy) indicates the tile chosen and bestact
   indicates the activity it wants to do.  If 0 is returned then there are no
   worthwhile activities available.
+
+  completion_time is the time that would be taken by punit to travel to
+  and complete work at best_tile
+
+  tile_inbound is, for each tile, the unit id of the worker en route
+  tile_inbound_time is the eta of this worker (if any).  This information
+  is used to possibly displace this previously assigned worker.
+  if these two arrays are NULL, workers are never displaced.
 ****************************************************************************/
 static int evaluate_improvements(struct unit *punit,
                                 enum unit_activity *best_act,
-                                struct tile **best_tile)
+                                struct tile **best_tile,
+                                int *completion_time,
+                                int *tile_inbound,
+                                int *tile_inbound_time)
 {
   struct city *mycity = tile_get_city(punit->tile);
   struct player *pplayer = unit_owner(punit);
@@ -858,6 +869,9 @@
   int best_newv = 0;
   enemy_mask my_enemies = enemies[pplayer->player_no]; /* optimalization */
 
+  struct unit *inbound = NULL; /* closest worker, if any, headed towards 
+                                 target tile */
+
   generate_warmap(mycity, punit);
 
   city_list_iterate(pplayer->cities, pcity) {
@@ -869,65 +883,85 @@
        continue;
       }
       in_use = (get_worker_city(pcity, i, j) == C_TILE_WORKER);
+      if(tile_inbound) {
+       inbound = player_find_unit_by_id(pplayer, tile_inbound[ptile->index]);
+      }
       if (tile_get_continent(ptile) == ucont
          && WARMAP_COST(ptile) <= THRESHOLD * mv_rate
          && !BV_CHECK_MASK(TERRITORY(ptile), my_enemies)
-         /* pretty good, hope it's enough! -- Syela */
-         && !is_already_assigned(punit, pplayer, ptile)) {
-       /* calling is_already_assigned once instead of four times
-          for obvious reasons;  structure is much the same as it once
-          was but subroutines are not -- Syela */
+         && (!(is_already_assigned(punit, pplayer, ptile)
+               || (inbound 
+                   && inbound->owner == pplayer->player_no)))) {
+       
+       int eta=FC_INFINITY, inbound_distance=FC_INFINITY;
        int time;
+       if(inbound) {
+         eta = tile_inbound_time[ptile->index];
+         inbound_distance = real_map_distance(ptile, inbound->tile);
+       }
        mv_turns = (WARMAP_COST(ptile)) / mv_rate;
        oldv = city_tile_value(pcity, i, j, 0, 0);
 
-       /* now, consider various activities... */
-
-       activity_type_iterate(act) {
+       /* only consider this tile if we are closer in time and space to it than
+          our other worker (if any) travelling to the site */
+       if(mv_turns < eta ||
+          (mv_turns == eta &&
+           real_map_distance(ptile, punit->tile) < inbound_distance)) {
+         
+         /* now, consider various activities... */
+         
+         activity_type_iterate(act) {
+           
+           if(pcity->ai.act_value[act][i][j] >= 0 &&
+              can_unit_do_activity_targeted_at(punit, act, 
+                                               S_NO_SPECIAL, ptile)) {
+             int extra = 0;
+             int base_value = pcity->ai.act_value[act][i][j];
+             int old_best_value = best_newv;
+             time = mv_turns + get_turns_for_activity_at(punit, act, ptile);
+             if(act == ACTIVITY_ROAD) {
+               extra = road_bonus(ptile, S_ROAD) * 5;
+               if (can_rr) {
+                 /* if we can make railroads eventually, consider making
+                  * road here, and set extras and time to to consider
+                  * railroads in main consider_settler_action call */
+                 consider_settler_action(pplayer, ACTIVITY_ROAD,
+                                         extra,
+                                         
pcity->ai.act_value[ACTIVITY_ROAD][i][j], 
+                                         oldv, in_use, time,
+                                         &best_newv, &best_oldv, 
+                                         best_act, best_tile,
+                                         ptile);
+                 
+                 base_value = pcity->ai.act_value[ACTIVITY_RAILROAD][i][j];
+                 
+                 /* Count road time plus rail time. */
+                 time += get_turns_for_activity_at(punit, ACTIVITY_RAILROAD, 
+                                                   ptile);
+               }
+             } else if (act == ACTIVITY_RAILROAD) {
+               extra = road_bonus(ptile, S_RAILROAD) * 3;
+             } else if (act == ACTIVITY_FALLOUT) {
+               extra = pplayer->ai.frost;
+             } else if (act == ACTIVITY_POLLUTION) {
+               extra = pplayer->ai.warmth;
+             }    
+             
+             consider_settler_action(pplayer, act,
+                                     extra, 
+                                     base_value, oldv, 
+                                     in_use, time,
+                                     &best_newv, &best_oldv,
+                                     best_act, best_tile,
+                                     ptile);
 
-         if(pcity->ai.act_value[act][i][j] >= 0 &&
-            can_unit_do_activity_targeted_at(punit, act, 
-                                             S_NO_SPECIAL, ptile)) {
-           int extra = 0;
-           int base_value = pcity->ai.act_value[act][i][j];
-           time = mv_turns + get_turns_for_activity_at(punit, act, ptile);
-           if(act == ACTIVITY_ROAD) {
-             extra = road_bonus(ptile, S_ROAD) * 5;
-             if (can_rr) {
-               /* if we can make railroads eventually, consider making
-                * road here, and set extras and time to to consider
-                * railroads in main consider_settler_action call */
-               consider_settler_action(pplayer, ACTIVITY_ROAD,
-                                       extra,
-                                       
pcity->ai.act_value[ACTIVITY_ROAD][i][j], 
-                                       oldv, in_use, time,
-                                       &best_newv, &best_oldv, 
-                                       best_act, best_tile,
-                                       ptile);
-
-               base_value = pcity->ai.act_value[ACTIVITY_RAILROAD][i][j];
-
-               /* Count road time plus rail time. */
-               time += get_turns_for_activity_at(punit, ACTIVITY_RAILROAD, 
-                                                 ptile);
+             if(best_newv > old_best_value) {
+               *completion_time = time;
              }
-           } else if (act == ACTIVITY_RAILROAD) {
-             extra = road_bonus(ptile, S_RAILROAD) * 3;
-           } else if (act == ACTIVITY_FALLOUT) {
-             extra = pplayer->ai.frost;
-           } else if (act == ACTIVITY_POLLUTION) {
-             extra = pplayer->ai.warmth;
-           }    
-
-           consider_settler_action(pplayer, act,
-                                   extra, 
-                                   base_value, oldv, 
-                                   in_use, time,
-                                   &best_newv, &best_oldv,
-                                   best_act, best_tile,
-                                   ptile);
-         } /* endif: can the worker perform this action */
-       } activity_type_iterate_end;
+
+           } /* endif: can the worker perform this action */
+         } activity_type_iterate_end;
+       } /* endif: are we closer than the currenly assigned worker, if any? */
       } /* endif: are we travelling to a legal destination? */
     } city_map_checked_iterate_end;
   } city_list_iterate_end;
@@ -955,13 +989,18 @@
   Find some work for our settlers and/or workers.
 **************************************************************************/
 #define LOG_SETTLER LOG_DEBUG
-static void auto_settler_findwork(struct player *pplayer, struct unit *punit)
+static void auto_settler_findwork(struct player *pplayer, 
+                                 struct unit *punit,
+                                 int *tile_inbound,
+                                 int *tile_inbound_time)
 {
   struct cityresult result;
   int best_impr = 0;            /* best terrain improvement we can do */
   enum unit_activity best_act;
   struct tile *best_tile = NULL;
   struct ai_data *ai = ai_data_get(pplayer);
+  int completion_time = 0; /* time it will take worker to complete 
+                             its given task */
 
   CHECK_UNIT(punit);
 
@@ -1014,7 +1053,9 @@
 
   if (unit_flag(punit, F_SETTLERS)) {
     TIMING_LOG(AIT_WORKERS, TIMER_START);
-    best_impr = evaluate_improvements(punit, &best_act, &best_tile);
+    best_impr = evaluate_improvements(punit, &best_act, &best_tile, 
+                                     &completion_time, tile_inbound,
+                                     tile_inbound_time);
     TIMING_LOG(AIT_WORKERS, TIMER_STOP);
   }
 
@@ -1064,7 +1105,18 @@
   if (punit->ai.ai_role == AIUNIT_AUTO_SETTLER) {
     /* Mark the square as taken. */
     if (best_tile) {
+      struct unit *displaced = 
+       unit_list_find(pplayer->units, tile_inbound[best_tile->index]);
+      tile_inbound[best_tile->index] = punit->id;
+      tile_inbound_time[best_tile->index] = completion_time;
+      
       best_tile->assigned = best_tile->assigned | 1 << pplayer->player_no;
+
+      if(displaced) {
+       displaced->goto_tile = displaced->tile;
+       auto_settler_findwork(pplayer, displaced, 
+                             tile_inbound, tile_inbound_time);
+      }
     } else {
       UNIT_LOG(LOG_DEBUG, punit, "giving up trying to improve terrain");
       return; /* We cannot do anything */
@@ -1085,7 +1137,8 @@
 
   if (punit->ai.ai_role == AIUNIT_BUILD_CITY
       && punit->moves_left > 0) {
-    auto_settler_findwork(pplayer, punit);
+    auto_settler_findwork(pplayer, punit,
+                         tile_inbound, tile_inbound_time);
   }
 }
 #undef LOG_SETTLER
@@ -1169,6 +1222,9 @@
 {
   static struct timer *t = NULL;      /* alloc once, never free */
 
+  int tile_inbound[MAP_INDEX_SIZE];
+  int tile_inbound_time[MAP_INDEX_SIZE];
+  
   t = renew_timer_start(t, TIMER_CPU, TIMER_DEBUG);
 
   if (pplayer->ai.control) {
@@ -1176,6 +1232,11 @@
     citymap_turn_init(pplayer);
   }
 
+  whole_map_iterate(ptile) {
+    tile_inbound[ptile->index] = -1;
+    tile_inbound_time[ptile->index] = FC_INFINITY;
+  } whole_map_iterate_end;
+
   /* Initialize the infrastructure cache, which is used shortly. */
   initialize_infrastructure_cache(pplayer);
 
@@ -1214,7 +1275,8 @@
         handle_unit_activity_request(punit, ACTIVITY_IDLE);
       }
       if (punit->activity == ACTIVITY_IDLE) {
-        auto_settler_findwork(pplayer, punit);
+        auto_settler_findwork(pplayer, punit,
+                             tile_inbound, tile_inbound_time);
       }
     }
   }
@@ -1416,6 +1478,7 @@
   struct tile *ptile = pcity->tile;
   struct ai_data *ai = ai_data_get(pplayer);
   Unit_Type_id unit_type = best_role_unit(pcity, F_SETTLERS);
+  int completion_time;
 
   if (unit_type == U_LAST) {
     freelog(LOG_DEBUG, "No F_SETTLERS role unit available");
@@ -1425,7 +1488,9 @@
   /* Create a localized "virtual" unit to do operations with. */
   virtualunit = create_unit_virtual(pplayer, pcity, unit_type, 0);
   virtualunit->tile = pcity->tile;
-  want = evaluate_improvements(virtualunit, &best_act, &best_tile);
+  want = evaluate_improvements(virtualunit, &best_act,
+                              &best_tile, &completion_time,
+                              NULL, NULL);
   free(virtualunit);
 
   /* Massage our desire based on available statistics to prevent

[Prev in Thread] Current Thread [Next in Thread]