Complete.Org: Mailing Lists: Archives: freeciv-ai: October 2004:
[freeciv-ai] Re: (PR#8992) Patch: Building ferries
Home

[freeciv-ai] Re: (PR#8992) Patch: Building ferries

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
To: Gregory.Berkolaiko@xxxxxxxxxxxxx
Subject: [freeciv-ai] Re: (PR#8992) Patch: Building ferries
From: "Benedict Adamson" <badamson@xxxxxxxxxxx>
Date: Wed, 6 Oct 2004 16:24:03 -0700
Reply-to: rt@xxxxxxxxxxx

<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.

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

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