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

    This is an experimental patch.  It replaces "real map distance"
(RMD) with pathfinder (PF) distance in the calculation of "waste /
corruption by distance from the capital".

    The idea is that you can reduce the losses due to waste and
corruption by building roads to your non-capital cities.  Instead
of the "one tile per turn" movement that "real map distance" equates
to, tiles with roads provide for up to "three tiles per turn"
movement.  In effect, your cities are up to 3 times closer to your
capital if they are linked to it by roads.

    Zones of control (ZOC) exerted by foreign units also affect the
PF distance to the capital.  Essentially, the PF path must go around
the ZOCs of such units.

    No attempt is made to account for air or sea travel.  Distances
for such cities (i.e. those on different continents from the
capital) fall back to the "real map distance".

    This version is intended merely as a "proof of concept".  Its
methods should evaluated for appropriateness and efficiency and
then improvements should be made where necessary.

    This code was extracted from source files and assembled into
the form of a diff file.  This patch is *untested* in this form.
But the code worked in the system where it was extracted from.  So
if this form doesn't work, then maybe I missed a piece somewhere.
Let me know and I'll try to figure out what went wrong in the
extraction process.

    Note that the code is misleading in that it uses the "pos.turn"
field from PF output instead of the "cc" (combined cost) field.  I
had intended to use the cc field but that wasn't working the way
that I had expected it to.  I don't know why.

    However, since PF's "pos.turn" field *did* work, I just plugged
its data into the field intended for the cc data.  I didn't go back
and fix the field names because I had intended to eventually get the
"cc" field problem figured out; but I never did.

    Perhaps the biggest question I still have about this code is
about the form of the PF search.  AIUI the method used here is an
outward search of surrounding tiles that looks for cities.  But
since the locations of cities are *known*, wouldn't a PF search for
a path (between two known points) be more efficient?  I never
explored that question (but I am curious about the answer).

    Finally, the radius of the PF search is arbitrarily set to 7.
If that method of PF search ends up being used, then that value
should be examined for appropriateness.  At a minumum, it should
probably be set to citymindist + something.

-Eddie


Index: common/city.c
==================================================================
--- common/city.c  (revision 11656)
+++ common/city.c  (working copy)       
@@ -2182,6 +2210,7 @@
 **************************************************************************/
 int city_waste(const struct city *pcity, Output_type_id otype, int total)
 {
+  int rmd, pfd = 0;
   int penalty = 0;
   int waste_level = get_city_output_bonus(pcity, get_output_type(otype),
                                           EFT_OUTPUT_WASTE);
@@ -2215,8 +2244,19 @@
     if (!capital) {
       return total; /* no capital - no income */
     } else {
+
+      /* debugging code */
+      rmd = real_map_distance(capital->tile, pcity->tile);
+      pfd = pcity->ai.pf_cc_distance_to_capital;
+      if (rmd > pfd && pfd > 0) {
+        freelog(LOG_DEBUG,"year= %d, city= %s, rmd = %d, pfd = %d", 
+               game.info.year, pcity->name, rmd, pfd);
+      } 
+
       waste_level += waste_by_dist 
-                     * real_map_distance(capital->tile, pcity->tile);
+                     * pcity->ai.pf_cc_distance_to_capital;
     }
   }
 

Index: common/city.h
==================================================================
--- common/city.h  (revision 11656)
+++ common/city.h  (working copy)
@@ -193,6 +193,12 @@
                                    wonders wisely */
   int distance_to_wonder_city;  /* wondercity will set this for us, 
                                    avoiding paradox */
+  int pf_mc_distance_to_capital;/* these next 3 pf_* variables are filled */
+  int pf_ec_distance_to_capital;/* with values determined by the */ 
+  int pf_cc_distance_to_capital;/* pathfinder routines.  mc is for "move 
+                                 * cost" (i.e. travel time).  ec is for 
+                                * "extra cost" (i.e. danger, zoc, etc.).
+                                * cc is for combined cost */
   bool celebrate;               /* try to celebrate in this city */
 
   /* Used for caching change in value from a worker performing

Index: ai/aicity.c
==================================================================
--- ai/aicity.c  (revision 11656)
+++ ai/aicity.c  (working copy)
@@ -1551,8 +1551,9 @@
     punittype = get_role_unit(F_HELP_WONDER, 0); /* simulate future unit */
   }
   ghost = create_unit_virtual(pplayer, NULL, punittype, 0);
-  range = unit_move_rate(ghost) * 4;
-
+  range = unit_move_rate(ghost) * (game.info.citymindist + 2); 
+  /* the second factor must be >= citymindist if it is to be effective */ 
+  
   city_list_iterate(pplayer->cities, pcity) {
     struct pf_parameter parameter;
     struct pf_map *map;
@@ -1795,7 +1796,7 @@
     }
   }
   calculate_wonder_helpers(pplayer, ai);
-
+  
   /* First find current worth of cities and cache this. */
   city_list_iterate(pplayer->cities, acity) {
     acity->ai.worth = city_want(pplayer, acity, ai, B_LAST);

Index: ai/aidata.h
==================================================================
--- ai/aidata.h  (revision 11656)
+++ ai/aidata.h  (working copy)
@@ -168,6 +168,7 @@
 
 void ai_data_init(struct player *pplayer);
 void ai_data_analyze_rulesets(struct player *pplayer);
+void calc_pf_dist_of_cities_to_capital(struct player *pplayer);
 
 struct ai_data *ai_data_get(struct player *pplayer);
 const struct ai_dip_intel *ai_diplomacy_get(const struct player *pplayer,

Index: ai/aidata.c
==================================================================
--- ai/aidata.c  (revision 11656)
+++ ai/aidata.c  (working copy)
@@ -215,6 +215,90 @@
 }
 
 /**************************************************************************
+  Calculate walking distances to capital from each of our cities.
+  TODO: remove maxrange limit; add code for ferry and air transport 
+**************************************************************************/
+void calc_pf_dist_of_cities_to_capital(struct player *pplayer)
+{
+  struct unit_type *punittype;
+  struct pf_map *map;
+  struct pf_parameter parameter;
+  struct unit *ghost;
+  int maxrange;
+  struct city *capital = find_palace(pplayer);
+
+  /* initialize with real map distance */
+  city_list_iterate(pplayer->cities, acity) {
+    /* if there is no capital, then set the cc distance value to 100 */
+    if (capital == NULL) {
+      acity->ai.pf_cc_distance_to_capital = 100;
+      acity->ai.pf_ec_distance_to_capital = 50;
+      acity->ai.pf_mc_distance_to_capital = 50;
+    } else {
+      /* otherwise set cc to real map distance; set mc and ec to 1/2 cc */
+      acity->ai.pf_cc_distance_to_capital 
+      = real_map_distance(capital->tile, acity->tile);
+      acity->ai.pf_ec_distance_to_capital 
+      = acity->ai.pf_cc_distance_to_capital / 2;
+      acity->ai.pf_mc_distance_to_capital
+      = acity->ai.pf_cc_distance_to_capital / 2;
+    }
+  } city_list_iterate_end;
+
+  /* If there's no capital, then there is nothing else that we can 
+   * calculate.  Because if there's no capital, then the virtual unit 
+   * has no starting point on the map (and so, can't be created). */  
+  if (capital == NULL) {
+    return;
+  }
+  
+  /* Use a virtual unit that is like a caravan to walk the path to the 
+   * capital.  If a caravan type isn't available, then use a settler (i.e. 
+   * worker) like unit.  If neither type is available, then keep the real 
+   * map distance values that were loaded earlier. */
+  punittype = best_role_unit_for_player(pplayer, F_HELP_WONDER);
+  if (!punittype) {
+     punittype = best_role_unit_for_player(pplayer, F_SETTLERS);
+     if (!punittype) {
+       return;
+     }
+  }
+
+  ghost = create_unit_virtual(pplayer, capital, punittype, 0);
+  maxrange = unit_move_rate(ghost) * 7;
+
+  pft_fill_unit_parameter(&parameter, ghost);
+  /* fractional movement points always succeed in moving to next tile */
+  /*parameter->turn_mode = TM_BEST_TIME; doesn't work */
+  /* doesn't work "invalid type argument of `->' */
+  map = pf_create_map(&parameter);
+
+  pf_iterator(map, pos) {
+    struct city *acity = tile_get_city(pos.tile);
+
+    if (pos.turn > maxrange) {
+      break;
+    }
+    if (!acity) {
+      continue;
+    }
+    if (city_owner(acity) == pplayer) {
+      if ((acity->ai.pf_cc_distance_to_capital > pos.turn)
+           && (pos.turn > 0)) {
+        acity->ai.pf_cc_distance_to_capital = pos.turn;
+      }
+      if ((acity->ai.pf_ec_distance_to_capital > pos.total_EC)
+           && (pos.total_EC > 0)) {
+        acity->ai.pf_ec_distance_to_capital = pos.total_EC;
+      }
+    }
+  } pf_iterator_end;
+
+  pf_destroy_map(map);
+  destroy_unit_virtual(ghost);
+}
+
+/**************************************************************************
   Make and cache lots of calculations needed for other functions.
 
   Note: We use map.num_continents here rather than pplayer->num_continents

Index: server/settlers.c
==================================================================
--- server/settlers.c  (revision 11656)
+++ server/settlers.c  (working copy)
@@ -1157,6 +1157,7 @@
 **************************************************************************/
 void initialize_infrastructure_cache(struct player *pplayer)
 {
+  calc_pf_dist_of_cities_to_capital(pplayer);
   city_list_iterate(pplayer->cities, pcity) {
     Want best = best_worker_tile_value(pcity);
 
Index: server/srv_main.c
==================================================================
--- server/srv_main.c  (revision 11656)
+++ server/srv_main.c  (working copy)
@@ -609,6 +609,7 @@
            pplayer->player_no, pplayer->name);
     /* human players also need this for building advice */
     ai_data_phase_init(pplayer, is_new_phase);
+    calc_pf_dist_of_cities_to_capital(pplayer);
     if (!pplayer->ai.control) {
       ai_manage_buildings(pplayer); /* building advisor */
     }
_______________________________________________
Freeciv-dev mailing list
Freeciv-dev@gna.org
https://mail.gna.org/listinfo/freeciv-dev

Reply via email to