Re: (PR#8992) Patch: Building ferries

"Benedict Adamson" <[email protected]>
Newsgroups gmane.games.freeciv.ai
Message-ID <[email protected]>
<URL: http://rt.freeciv.org/Ticket/Display.html?id=8992 >

Gregory Berkolaiko wrote:
...
> I am forwarding the last patch I made in this series.  It is pretty old
> (8 Aug)
...
> It
> contains some code that should be deleted rather than commented out.  It
> is not likely to apply to CVS.
...

Attached is a version of the patch, updated to the 2004-10-03 CVS 
snapshot. I've deleted the commented out code. I ran some auto games and 
examined one game, so it hardly counts as tested.
PR8992,848,2004-10-03.patch (text/x-patch, 10.2 KB)
diff -Nur -Xfreeciv.PR8992/diff_ignore vendor.freeciv.current/ai/advdomestic.c freeciv.PR8992/ai/advdomestic.c
--- vendor.freeciv.current/ai/advdomestic.c	2004-10-03 11:40:07.000000000 +0100
+++ freeciv.PR8992/ai/advdomestic.c	2004-10-07 00:23:00.000000000 +0100
@@ -200,7 +200,6 @@
       choice->type = CT_NONMIL;
       choice->choice = unit_type; /* default */
       choice->need_boat = TRUE;
-      ai_choose_role_unit(pplayer, pcity, choice, L_FERRYBOAT, -want);
     }
   }
 
diff -Nur -Xfreeciv.PR8992/diff_ignore vendor.freeciv.current/ai/advmilitary.c freeciv.PR8992/ai/advmilitary.c
--- vendor.freeciv.current/ai/advmilitary.c	2004-10-03 11:40:07.000000000 +0100
+++ freeciv.PR8992/ai/advmilitary.c	2004-10-07 00:23:00.000000000 +0100
@@ -1118,11 +1118,9 @@
   if (best_choice.want > choice->want) {
     /* We want attacker more that what we have selected before */
     copy_if_better_choice(&best_choice, choice);
-    if (go_by_boat && !ferryboat) {
-      ai_choose_role_unit(pplayer, pcity, choice, L_FERRYBOAT, choice->want);
-    }
-    freelog(LOG_DEBUG, "%s has chosen attacker, %s, want=%d",
-            pcity->name, unit_types[choice->choice].name, choice->want);
+    CITY_LOG(LOG_DEBUG, pcity, "has chosen attacker, %s, want=%d%s",
+	     unit_types[choice->choice].name, choice->want, 
+	     (best_choice.need_boat ? "(need boat)" : ""));
   } 
 }
 
diff -Nur -Xfreeciv.PR8992/diff_ignore vendor.freeciv.current/ai/aicity.c freeciv.PR8992/ai/aicity.c
--- vendor.freeciv.current/ai/aicity.c	2004-10-03 11:40:07.000000000 +0100
+++ freeciv.PR8992/ai/aicity.c	2004-10-07 00:23:00.000000000 +0100
@@ -46,6 +46,7 @@
 #include "advdomestic.h"
 #include "advmilitary.h"
 #include "aidata.h"
+#include "aiferry.h"
 #include "aihand.h"
 #include "ailog.h"
 #include "aitools.h"
@@ -980,6 +981,8 @@
     ai_city_choose_build(pplayer, pcity);
   } city_list_iterate_end;
 
+  aiferry_choose_build_global(pplayer);
+
   ai_spend_gold(pplayer);
 }
 
diff -Nur -Xfreeciv.PR8992/diff_ignore vendor.freeciv.current/ai/aiferry.c freeciv.PR8992/ai/aiferry.c
--- vendor.freeciv.current/ai/aiferry.c	2004-10-03 11:40:07.000000000 +0100
+++ freeciv.PR8992/ai/aiferry.c	2004-10-07 00:23:00.000000000 +0100
@@ -27,6 +27,7 @@
 
 #include "aidata.h"
 #include "aiexplorer.h"
+#include "aihand.h"
 #include "ailog.h"
 #include "aitools.h"
 #include "aiunit.h"
@@ -44,7 +45,7 @@
  * The below is used only by passengers in ai.ferryboat field 
  */ 
 #define FERRY_WANTED      -1      /* Needs a boat */
-#define FERRY_NONE         0      /* Has no boa and doesn't need one */
+#define FERRY_NONE         0      /* Has no boat and doesn't need one */
 
 
 /* =================== group log levels, debug options ================= */
@@ -58,7 +59,6 @@
 /* Extra consistency checks */
 #define DEBUG_FERRY_STATS 0
 
-
 /* ========= managing statistics and boat/passanger assignments ======== */
 
 /**************************************************************************
@@ -73,7 +73,7 @@
   ai->stats.available_boats = 0;
  
   unit_list_iterate(pplayer->units, punit) {
-    if (is_sailing_unit(punit) && is_ground_units_transport(punit)) {
+    if (unit_has_role(punit->type, L_FERRYBOAT)) {
       ai->stats.boats++;
       if (punit->ai.passenger == FERRY_AVAILABLE) {
 	ai->stats.available_boats++;
@@ -95,8 +95,8 @@
   struct ai_data *ai = ai_data_get(pplayer);
   int n = 1;
 
-  freelog(LOG_NORMAL, "Boat stats for %s[%d]", 
-	  pplayer->name, pplayer->player_no);
+  freelog(LOG_NORMAL, "Boat stats for %s[%d] in turn %d", 
+	  pplayer->name, pplayer->player_no, game.turn);
   freelog(LOG_NORMAL, "Registered: %d free out of total %d",
 	  ai->stats.available_boats, ai->stats.boats);
   unit_list_iterate(pplayer->units, punit) {
@@ -855,3 +855,189 @@
  
   return;
 }
+
+/**************************************************************************
+  A cost function for a sea unit which allows going one step into the land.
+  
+  Things to remember: we should prevent going from land to anywhere, unless 
+  we are leaving a city, in which case we can move into the ocean but not 
+  into the land.
+**************************************************************************/
+static int overlap_move(const struct tile *ptile, enum direction8 dir,
+                        const struct tile *ptile1, struct pf_parameter *param)
+{
+  if (is_ocean(map_get_terrain(ptile))) {
+    return SINGLE_MOVE;
+  } else if (is_allied_city_tile(ptile, param->owner)
+	     && is_ocean(map_get_terrain(ptile1))) {
+    return SINGLE_MOVE;
+  }
+
+  return PF_IMPOSSIBLE_MC;
+}
+
+/* Least Common Denominator of 2,3,..,8 (a very divisible number) */
+#define DENOM 840
+/****************************************************************************
+  A global ferry build selector.  Estimates our want for the boats and finds
+  cities who will build them.
+
+  FIXME: Gross hack, uses pcity->ai.founder_want field for its local 
+  calculations.
+****************************************************************************/
+void aiferry_choose_build_global(struct player *pplayer)
+{
+  struct city *pcity;
+  int inf_loop_guard = city_list_size(&pplayer->cities);
+  /* Path-finding stuff */
+  struct pf_map *pfmap;
+  struct pf_parameter parameter;
+
+  /* Initialize */
+  city_list_iterate(pplayer->cities, acity) {
+    acity->ai.founder_want = 0;
+  } city_list_iterate_end;
+  parameter.turn_mode = TM_NONE;
+  parameter.get_MC = overlap_move;
+  parameter.get_TB = NULL;
+  parameter.get_EC = NULL;
+  parameter.get_costs = NULL;
+  parameter.get_zoc = NULL;
+  parameter.is_pos_dangerous = NULL;
+  BV_CLR_ALL(parameter.unit_flags);
+  parameter.owner = pplayer;
+  parameter.omniscience = !ai_handicap(pplayer, H_MAP);
+  /* These don't matter */
+  parameter.moves_left_initially = 0;
+  parameter.move_rate = 3;
+
+  do {
+    int future_psngrs = 0, psngrs = 0;
+    int boats = 0, avail_boats = 0;
+    int boats_to_be_built;
+
+    /* Find unprocessed city */
+    pcity = NULL;
+    city_list_iterate(pplayer->cities, acity) {
+      if (acity->ai.founder_want == 0 
+	  && is_ocean_near_tile(acity->tile)) {
+	pcity = acity;
+	break;
+      }
+    } city_list_iterate_end;
+
+    if (!pcity) {
+      break;
+    }
+
+    /* Part 1: estimate the demand for the boats */
+
+    parameter.start_tile = pcity->tile;
+    pfmap = pf_create_map(&parameter);
+
+    /* We want to consider the place we are currently in too, hence the 
+     * do-while loop */
+    do {
+      struct pf_position pos;
+      struct city *acity;
+
+      pf_next_get_position(pfmap, &pos);
+      acity = map_get_city(pos.tile);
+
+      if (acity && acity->owner == pplayer->player_no) {
+	assert(acity->ai.founder_want == 0);
+	acity->ai.founder_want = 1;
+
+	if (acity->ai.choice.need_boat) {
+	  int turns_to_build = 
+	    city_turns_to_build(acity, acity->ai.choice.choice, 
+				is_unit_choice_type(acity->ai.choice.type),
+				TRUE);
+
+	  future_psngrs += DENOM / turns_to_build;
+	}
+      }
+
+      unit_list_iterate(pos.tile->units, aunit) {
+	if (aunit->owner != pplayer->player_no) {
+	  continue;
+	}
+	if (unit_has_role(aunit->type, L_FERRYBOAT)) {
+	  boats++;
+	  if (aunit->ai.passenger == FERRY_AVAILABLE) {
+	    avail_boats++;
+	  }
+	  if (aunit->ai.passenger == 0) {
+	    freelog(LOG_ERROR, "Passenger field set to 0");
+	    avail_boats++;
+	  }
+	} else if (aunit->ai.ferryboat == FERRY_WANTED) {
+	  psngrs++;
+	}
+      } unit_list_iterate_end;      
+    } while (pf_next(pfmap));
+
+    pf_destroy_map(pfmap);
+
+    freelog(LOG_NORMAL, "Sea area accessible from %s has %d boats (%d free)"
+	    " and %d units waiting for boats",
+	    pcity->name, boats, avail_boats, psngrs);
+    freelog(LOG_NORMAL, "Future passenger score is %d.", future_psngrs);
+
+    /* Part 2: Decide on how many boats we want built */
+
+    /* WAG rules: idle boats count twice, future passangers 
+     * count as half */ 
+    psngrs = psngrs * DENOM + MAX(0, future_psngrs - boats * DENOM);
+    boats = (boats + avail_boats) * DENOM;
+    boats_to_be_built = (psngrs > boats ? 1 : 0);
+
+    freelog(LOG_NORMAL, "Boat-want is %d, so %d boats will be built", 
+	    psngrs - boats, boats_to_be_built);
+
+    /* Part 3: Decide where to build it */
+    
+    while (boats_to_be_built > 0) {
+      Unit_Type_id boattype = best_role_unit_for_player(pplayer, L_FERRYBOAT);
+      int best = FC_INFINITY;
+      struct city *bestcity = NULL;
+
+      if (boattype == U_LAST) {
+	/* Stimulate tech A LOT!!! */
+	break;
+      }
+
+      city_list_iterate(pplayer->cities, acity) {
+	if (acity->ai.founder_want == 1 
+	    && acity->ai.choice.need_boat
+	    && city_turns_to_build(acity, boattype, TRUE, TRUE) < best) {
+	  assert(is_ocean_near_tile(pcity->tile));
+	  best = city_turns_to_build(acity, boattype, TRUE, TRUE);
+	  bestcity = acity;
+	}
+      } city_list_iterate_end;
+
+      if (!bestcity) {
+	break;
+      }
+
+      /* FIXME: separate a function ai_set_build from 
+       * aicity.c:ai_city_choose_build and use it here */
+      CITY_LOG(LOG_NORMAL, bestcity, "will build a boat");
+      bestcity->currently_building = boattype;
+      pcity->is_building_unit = TRUE;
+      boats_to_be_built--;
+    }
+
+    /* Part 4: Cleanup */
+    city_list_iterate(pplayer->cities, acity) {
+      if (acity->ai.founder_want == 1) { 
+	  acity->ai.founder_want = 2;
+      }
+    } city_list_iterate_end;
+
+    inf_loop_guard--;
+  } while(inf_loop_guard > 0);
+}
+
+#undef DENOM
diff -Nur -Xfreeciv.PR8992/diff_ignore vendor.freeciv.current/ai/aiferry.h freeciv.PR8992/ai/aiferry.h
--- vendor.freeciv.current/ai/aiferry.h	2004-10-03 11:40:07.000000000 +0100
+++ freeciv.PR8992/ai/aiferry.h	2004-10-07 00:23:00.000000000 +0100
@@ -48,4 +48,10 @@
  */
 void ai_manage_ferryboat(struct player *pplayer, struct unit *punit);
 
+/* 
+ * A function for a centralized (i.e. per-civilization rather than per-city
+ * estimation of need to build more ferries and where to build them
+ */
+void aiferry_choose_build_global(struct player *pplayer);
+
 #endif /* FC__AIFERRY_H */
diff -Nur -Xfreeciv.PR8992/diff_ignore vendor.freeciv.current/diff_ignore freeciv.PR8992/diff_ignore
--- vendor.freeciv.current/diff_ignore	2004-09-05 21:01:58.000000000 +0100
+++ freeciv.PR8992/diff_ignore	2004-10-07 00:23:00.000000000 +0100
@@ -17,6 +17,7 @@
 *~
 .#*
 .deps
+.svn
 CVS
 Freeciv.h
 Makefile
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.