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

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

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
To: undisclosed-recipients: ;
Subject: [freeciv-ai] (PR#8992) Building ferries
From: "Gregory Berkolaiko" <Gregory.Berkolaiko@xxxxxxxxxxxxx>
Date: Fri, 25 Jun 2004 12:35:48 -0700
Reply-to: rt@xxxxxxxxxxx

<URL: http://rt.freeciv.org/Ticket/Display.html?id=8992 >

Here is some code which actually fits to the title of the ticket.

It's a very rough version of a centralized ferry-building.  There is a
function which, for each "ocean" counts how many boats are there, how
many cities want boats and how many units are waiting for boats and
forces some cities (1 at the moment) to build boats if necessary.

Note that individual cities no longer build boats.  If they want a unit
which wants a boat, they just set the need_ferry field in the ai_choice
struct and wait for the centralized system to pick up.

It compiles and works, but that's about it for now.

G.

? ai/aisettler.c
? ai/aisettler.h
? data/flags/Makefile
? data/flags/Makefile.in
Index: ai/advdomestic.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/advdomestic.c,v
retrieving revision 1.110
diff -u -r1.110 advdomestic.c
--- ai/advdomestic.c    16 Jun 2004 12:54:36 -0000      1.110
+++ ai/advdomestic.c    25 Jun 2004 19:28:30 -0000
@@ -1006,7 +1006,7 @@
       choice->type = CT_NONMIL;
       choice->choice = unit_type; /* default */
       choice->need_boat = TRUE;
-      ai_choose_role_unit(pplayer, pcity, choice, L_FERRYBOAT, -want);
+      // ai_choose_role_unit(pplayer, pcity, choice, L_FERRYBOAT, -want);
     }
   }
 
Index: ai/advmilitary.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/advmilitary.c,v
retrieving revision 1.168
diff -u -r1.168 advmilitary.c
--- ai/advmilitary.c    24 May 2004 02:09:27 -0000      1.168
+++ ai/advmilitary.c    25 Jun 2004 19:28:30 -0000
@@ -1075,11 +1075,14 @@
   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)" : ""));
   } 
 }
 
Index: ai/aicity.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/aicity.c,v
retrieving revision 1.155
diff -u -r1.155 aicity.c
--- ai/aicity.c 27 May 2004 22:14:17 -0000      1.155
+++ ai/aicity.c 25 Jun 2004 19:28:30 -0000
@@ -595,6 +595,8 @@
     ai_city_choose_build(pplayer, pcity);
   } city_list_iterate_end;
 
+  aiferry_choose_build_global(pplayer);
+
   ai_spend_gold(pplayer);
 }
 
Index: ai/aiferry.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/aiferry.c,v
retrieving revision 1.2
diff -u -r1.2 aiferry.c
--- ai/aiferry.c        20 Jun 2004 18:23:38 -0000      1.2
+++ ai/aiferry.c        25 Jun 2004 19:28:30 -0000
@@ -72,7 +72,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++;
@@ -850,3 +850,176 @@
  
   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(int x, int y, enum direction8 dir,
+                           int x1, int y1, struct pf_parameter *param)
+{
+  if (is_ocean(map_get_terrain(x, y))) {
+    return SINGLE_MOVE;
+  } else if (is_allied_city_tile(map_get_tile(x, y), param->owner)
+            && is_ocean(map_get_terrain(x1, y1))) {
+    return SINGLE_MOVE;
+  }
+
+  return PF_IMPOSSIBLE_MC;
+}
+
+
+/****************************************************************************
+  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_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->x, acity->y)) {
+       pcity = acity;
+       break;
+      }
+    } city_list_iterate_end;
+
+    if (!pcity) {
+      break;
+    }
+
+    /* Part 1: estimate the demand for the boats */
+
+    parameter.start_x = pcity->x;
+    parameter.start_y = pcity->y;
+    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.x, pos.y);
+
+      if (acity && acity->owner == pplayer->player_no) {
+       assert(acity->ai.founder_want == 0);
+       acity->ai.founder_want = 1;
+
+       if (acity->ai.choice.need_boat) {
+         future_psngrs++;
+       }
+      }
+
+      unit_list_iterate(map_get_tile(pos.x, pos.y)->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++;
+         }
+       } 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),"
+           " %d units waiting for boats and %d cities needing boats",
+           pcity->name, boats, avail_boats, psngrs, 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 + (future_psngrs + 1) / 2;
+    boats = boats + avail_boats;
+    boats_to_be_built = (psngrs > boats ? 1 : 0);
+
+    freelog(LOG_NORMAL, "%d boats will be built", 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->x, pcity->y));
+         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);
+
+}
Index: ai/aiferry.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/aiferry.h,v
retrieving revision 1.1
diff -u -r1.1 aiferry.h
--- ai/aiferry.h        20 Jun 2004 07:41:14 -0000      1.1
+++ ai/aiferry.h        25 Jun 2004 19:28:30 -0000
@@ -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 */

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