[Freeciv-Dev] (PR#10694) AI Builds Doomed Ferries and Passengers

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

Here is a patch that implements a possible fix. This is applicable to 
the 2004-1103 CVS development version. Note that this patch is only 
lightly tested; I'm posting it to get feedback rather than to provide a 
final fix.

The uses an estimate of the ferry sinking probability to adjust the cost 
estimate for a proposed ferried attacker. That tends to punish long 
ferry routes through dangerous waters. It computes the sinking 
probability from the danger values already computed in the assess_danger 
function. The computation has one WAG constant (FERRY_DANGER_FACTOR).

Any comments?
PR10694,993,2004-11-03.patch (text/x-patch, 6.8 KB)
diff -ru -Xfreeciv.PR10694/diff_ignore vendor.freeciv.current/ai/advmilitary.c freeciv.PR10694/ai/advmilitary.c
--- vendor.freeciv.current/ai/advmilitary.c	2004-11-03 19:46:36.000000000 +0000
+++ freeciv.PR10694/ai/advmilitary.c	2004-11-08 00:14:46.000000000 +0000
@@ -580,6 +580,10 @@
   }
 
   pcity->ai.danger = danger[0];
+  /* TO DO: sea_danger should ignore the effects of coast defences and
+   * should include a contribution from warships that can not make
+   * land attacks */
+  pcity->ai.sea_danger = danger[2];
   pcity->ai.urgency = urgency;
 
   return urgency;
@@ -756,6 +760,47 @@
   return;
 }
 
+/* A WAG for ferry_turn_survival_probabilty */
+#define FERRY_DANGER_FACTOR 800
+/************************************************************************** 
+  Estimate the probability of a loaded ferry evading sinking by enemy warships
+  for one turn in the waters around one of our cities.
+**************************************************************************/
+static int ferry_turn_survival_probabilty(const struct city *pcity)
+{
+  const int danger = MAX(1, pcity->ai.sea_danger);
+  int p = 100;
+
+  p = 100 - MIN(100, danger/FERRY_DANGER_FACTOR);
+  assert(0 <= p && p <= 100);
+  return p;
+}
+
+/************************************************************************** 
+  Estimate the probability of a loaded ferry evading sinking by enemy warships.
+  The ferry starts in our city, pcity. move_time gives the length of the
+  *passenger's* journey; some of that journey will be on land.
+  The probability is a percentage.
+**************************************************************************/
+static int ferry_survival_probabilty(const struct city *pcity,
+				     const int move_time)
+{
+  const int turn_survival = ferry_turn_survival_probabilty(pcity);
+  int sea_time = MAX(1, move_time - 1); /*assume 1 turn on land*/
+  int p = 100;
+
+  assert(0 <= move_time);
+
+  while (sea_time) {
+    p = p * turn_survival / 100;
+    sea_time--;
+  }
+
+  p = MAX(1, p); /*prevent divide-by-zero */
+  assert(0 < p && p <= 100);
+  return p;
+}
+
 /************************************************************************** 
   This function decides, what unit would be best for erasing enemy. It is 
   called, when we just want to kill something, we've found it but we don't 
@@ -785,17 +830,15 @@
   bool shore = is_ocean_near_tile(pcity->tile);
   int orig_move_type = unit_types[best_choice->choice].move_type;
   int victim_count = 1;
-  int needferry = 0;
+  int ferry_cost = 0;
   bool unhap = ai_assess_military_unhappiness(pcity,
                                               get_gov_pplayer(pplayer));
+  bool will_use_ferry = (orig_move_type == LAND_MOVING
+			 && (boat || boattype < U_LAST));
+  bool will_build_ferry = will_use_ferry && !boat;
 
   assert(orig_move_type == SEA_MOVING || orig_move_type == LAND_MOVING);
 
-  if (orig_move_type == LAND_MOVING && !boat && boattype < U_LAST) {
-    /* cost of ferry */
-    needferry = unit_build_shield_cost(boattype);
-  }
-  
   if (!is_stack_vulnerable(ptile)) {
     /* If it is a city, a fortress or an air base,
      * we may have to whack it many times */
@@ -899,6 +942,22 @@
           }
         }
       }
+
+      /* Using ferries introduces costs of ferry building,
+       * if we use a new ferry, and the danger that we will be sunk en route,
+       * when we are helpless */
+      if (will_use_ferry) {
+	int ferry_build_cost = unit_build_shield_cost(boattype);
+	int p = ferry_survival_probabilty(pcity, move_time);
+	if (will_build_ferry) {
+	  ferry_cost = ferry_build_cost * 100 / p;
+	} else {
+	  ferry_cost = ferry_build_cost * (100 - p) / p;
+	}
+	bcost_balanced = bcost_balanced * 100 / p;
+      } else {
+	ferry_cost = 0;
+      }
       
       desire -= tech_cost * SHIELD_WEIGHTING;
       /* We can be possibly making some people of our homecity unhappy - then
@@ -908,7 +967,7 @@
                              : SHIELD_WEIGHTING);
 
       want = military_amortize(pplayer, pcity, desire, MAX(1, move_time),
-                               bcost_balanced + needferry);
+                               bcost_balanced + ferry_cost);
       
       if (want > 0) {
         if (tech_dist > 0) {
diff -ru -Xfreeciv.PR10694/diff_ignore vendor.freeciv.current/ai/ailog.c freeciv.PR10694/ai/ailog.c
--- vendor.freeciv.current/ai/ailog.c	2004-10-22 23:16:37.000000000 +0100
+++ freeciv.PR10694/ai/ailog.c	2004-11-08 00:14:46.000000000 +0000
@@ -78,7 +78,7 @@
 
 /**************************************************************************
   Log city messages, they will appear like this
-    2: c's Romenna(5,35) [s1 d106 u11 g1] must have Archers ...
+    2: c's Romenna(5,35) [s1 d106 s90 u11 g1] must have Archers ...
 **************************************************************************/
 void CITY_LOG(int level, struct city *pcity, const char *msg, ...)
 {
@@ -93,10 +93,10 @@
     return;
   }
 
-  my_snprintf(buffer, sizeof(buffer), "%s's %s(%d,%d) [s%d d%d u%d g%d] ",
+  my_snprintf(buffer, sizeof(buffer), "%s's %s(%d,%d) [s%d d%d s%d u%d g%d] ",
               city_owner(pcity)->name, pcity->name,
               pcity->tile->x, pcity->tile->y, pcity->size,
-              pcity->ai.danger, pcity->ai.urgency,
+              pcity->ai.danger, pcity->ai.sea_danger, pcity->ai.urgency,
               pcity->ai.grave_danger);
 
   va_start(ap, msg);
diff -ru -Xfreeciv.PR10694/diff_ignore vendor.freeciv.current/common/city.c freeciv.PR10694/common/city.c
--- vendor.freeciv.current/common/city.c	2004-10-22 23:16:36.000000000 +0100
+++ freeciv.PR10694/common/city.c	2004-11-08 00:14:45.000000000 +0000
@@ -2457,6 +2457,7 @@
   pcity->ai.trade_want = 1; /* we always want some */
   memset(pcity->ai.building_want, 0, sizeof(pcity->ai.building_want));
   pcity->ai.danger = 0;
+  pcity->ai.sea_danger = 0;
   pcity->ai.urgency = 0;
   pcity->ai.grave_danger = 0;
   pcity->ai.wallvalue = 0;
diff -ru -Xfreeciv.PR10694/diff_ignore vendor.freeciv.current/common/city.h freeciv.PR10694/common/city.h
--- vendor.freeciv.current/common/city.h	2004-10-22 23:16:36.000000000 +0100
+++ freeciv.PR10694/common/city.h	2004-11-08 00:14:45.000000000 +0000
@@ -174,6 +174,7 @@
   int building_want[B_LAST];    /* not sure these will always be < 256 */
 
   unsigned int danger;          /* danger to be compared to assess_defense */
+  unsigned int sea_danger;      /* due to warships */
   bool diplomat_threat;         /* enemy diplomat or spy is near the city */
   bool has_diplomat;            /* this city has diplomat or spy defender */
   unsigned int urgency;         /* how close the danger is; if zero, 
diff -ru -Xfreeciv.PR10694/diff_ignore vendor.freeciv.current/diff_ignore freeciv.PR10694/diff_ignore
--- vendor.freeciv.current/diff_ignore	2004-10-22 23:16:37.000000000 +0100
+++ freeciv.PR10694/diff_ignore	2004-11-08 00:18:21.000000000 +0000
@@ -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.