Complete.Org: Mailing Lists: Archives: freeciv-ai: June 2004:
[freeciv-ai] (PR#8827) bad use of ferries by AI
Home

[freeciv-ai] (PR#8827) bad use of ferries by AI

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
To: jdorje@xxxxxxxxxxxxxxxxxxxxx
Subject: [freeciv-ai] (PR#8827) bad use of ferries by AI
From: "Gregory Berkolaiko" <Gregory.Berkolaiko@xxxxxxxxxxxxx>
Date: Tue, 1 Jun 2004 07:44:26 -0700
Reply-to: rt@xxxxxxxxxxx

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

Attached patch fixes some bugs and reorders things slightly in ai_gothere.

Before, the unit would ifnd_ferry whenever it wanted ferry, but then if
the ferry is not nearby, the result would not be used constructively.
Now the unit will use find_ferry only if it's totally lost (inland),
then it'd walk towards the coast.  If unit is on the coast it will wait
for a ferry to come within one step.

Bugs were:
1. Ferry not made available when released.
2. Ferry not using omniscience when looking for psngrs.
3. Units reserving a ferry alhtough it does them no good and it hurts
other things.
4. Units reserving other players ferries.

G.
? aaa.gz
? ttt.gz
? ai/aisettler.c
? ai/aisettler.h
? data/flags/Makefile
? data/flags/Makefile.in
Index: ai/aidata.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/aidata.c,v
retrieving revision 1.26
diff -u -r1.26 aidata.c
--- ai/aidata.c 25 May 2004 15:35:32 -0000      1.26
+++ ai/aidata.c 1 Jun 2004 14:40:38 -0000
@@ -401,15 +401,16 @@
 **************************************************************************/
 void ai_set_ferry(struct unit *punit, struct unit *ferry)
 {
-  if (!ferry && punit->ai.ferryboat != FERRY_WANTED) {
+  /* First delete unit from the list of passengers and release its ferry */
+  ai_clear_ferry(punit);
+
+  if (!ferry) {
     struct ai_data *ai = ai_data_get(unit_owner(punit));
 
-    UNIT_LOG(LOG_DEBUG, punit, "want a boat.");
+    UNIT_LOG(LOG_DEBUG, punit, "requests a boat.");
     ai->stats.passengers++;
     punit->ai.ferryboat = FERRY_WANTED;
-  } else if (ferry) {
-    /* Make sure we delete punit from the list of potential passengers */
-    ai_clear_ferry(punit);
+  } else {
     punit->ai.ferryboat = ferry->id;
   }
 }
@@ -428,8 +429,11 @@
     struct unit *ferry = find_unit_by_id(punit->ai.ferryboat);
     
     if (ferry && ferry->ai.passenger == punit->id) {
+      struct ai_data *ai = ai_data_get(unit_owner(punit));
+
       /* punit doesn't want us anymore */
-      ferry->ai.passenger = FERRY_NONE;
+      ferry->ai.passenger = FERRY_AVAILABLE;
+      ai->stats.available_boats++;
     }
   }
 
Index: ai/aitools.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/aitools.c,v
retrieving revision 1.107
diff -u -r1.107 aitools.c
--- ai/aitools.c        25 May 2004 15:47:09 -0000      1.107
+++ ai/aitools.c        1 Jun 2004 14:40:38 -0000
@@ -305,6 +305,7 @@
       
       unit_list_iterate(ptile->units, aunit) {
         if (is_ground_units_transport(aunit)
+            && aunit->owner == punit->owner
             && (aunit->ai.passenger == FERRY_AVAILABLE
                 || aunit->ai.passenger == punit->id)) {
           /* Turns for the unit to get to rendezvous pnt */
@@ -334,6 +335,29 @@
   return best_id;
 }
 
+/****************************************************************************
+  Find a boat within one move from us (i.e. a one we can board).
+
+  FIXME: Actually check the capacity.
+****************************************************************************/
+static int find_ferry_nearby(struct unit *punit, int cap)
+{
+  UNIT_LOG(LOGLEVEL_FINDFERRY, punit, "asked find_ferry_nearby for a boat");
+
+  square_iterate(punit->x, punit->y, 1, x, y) {
+    unit_list_iterate(map_get_tile(x, y)->units, aunit) {
+      if (is_ground_units_transport(aunit)
+         && aunit->owner == punit->owner
+          && (aunit->ai.passenger == FERRY_AVAILABLE
+              || aunit->ai.passenger == punit->id)) {
+         return aunit->id;
+       }
+    } unit_list_iterate_end;
+  } square_iterate_end;
+
+  return 0;
+}
+
 #define LOGLEVEL_GOTHERE LOG_DEBUG
 /****************************************************************************
   This is ferry-enabled goto.  Should not normally be used for non-ferried 
@@ -351,7 +375,6 @@
                 int dest_x, int dest_y)
 {
   struct unit *bodyguard = find_unit_by_id(punit->ai.bodyguard);
-  struct pf_path *path_to_ferry = NULL;
 
   CHECK_UNIT(punit);
 
@@ -364,42 +387,28 @@
   /* FIXME: If bodyguard is _really_ necessary, don't go anywhere */
   ai_gothere_bodyguard(punit, dest_x, dest_y);
 
-  /* If we can, we will walk, take boat only if necessary */
-  if (punit->transported_by > 0 
-      || !goto_is_sane(punit, dest_x, dest_y, TRUE)) {
-    int boatid = punit->transported_by;
+  if (punit->transported_by <= 0 
+      && !goto_is_sane(punit, dest_x, dest_y, TRUE)) {
+    /* We are not on a boat and we cannot walk */
+    int boatid;
     struct unit *ferryboat = NULL;
 
     UNIT_LOG(LOGLEVEL_GOTHERE, punit, "will have to go to (%d,%d) by boat",
              dest_x, dest_y);
 
-    if (boatid <= 0) {
+    if (!is_ocean_near_tile(punit->x, punit->y)) {
+      struct pf_path *path_to_ferry = NULL;
+      
       boatid = find_ferry(punit, 2, &path_to_ferry);
-    } 
-    ferryboat = find_unit_by_id(boatid);
-
-    if (!ferryboat) {
-      UNIT_LOG(LOGLEVEL_GOTHERE, punit, "No boat found.");
-      if (is_ocean_near_tile(punit->x, punit->y)) {
-        ai_set_ferry(punit, NULL);
+      if (boatid <= 0) {
+        UNIT_LOG(LOGLEVEL_GOTHERE, punit, 
+                "in ai_gothere cannot find any boats.");
+        return FALSE;
       }
-      return FALSE;
-    } else {
-      UNIT_LOG(LOGLEVEL_GOTHERE, punit, "Found boat at (%d,%d)",
-               ferryboat->x, ferryboat->y);
-    }
 
-    ai_set_ferry(punit, ferryboat);
-    ai_set_passenger(ferryboat, punit);
-
-    if (!is_tiles_adjacent(punit->x, punit->y, ferryboat->x, ferryboat->y)
-       && !same_pos(punit->x, punit->y, ferryboat->x, ferryboat->y)
-       && !is_ocean_near_tile(punit->x, punit->y)) {
-      /* Go to the boat only if it cannot reach us or it's parked 
-       * next to us.  Otherwise just wait (boats are normally faster) */
-      /* TODO: agree on a rendez-vous point */
-      UNIT_LOG(LOGLEVEL_GOTHERE, punit, "going to boat[%d](%d,%d).", boatid,
-               ferryboat->x, ferryboat->y);
+      ferryboat = find_unit_by_id(boatid);
+      UNIT_LOG(LOGLEVEL_GOTHERE, punit, "found boat[%d](%d,%d), going there", 
+              boatid, ferryboat->x, ferryboat->y);
       /* The path can be amphibious so we will stop at the coast.  
        * It might not lead _onto_ the boat. */
       if (!ai_unit_execute_path(punit, path_to_ferry)) { 
@@ -407,32 +416,59 @@
        pf_destroy_path(path_to_ferry);
         return FALSE;
       }
+      pf_destroy_path(path_to_ferry);
     }
-    pf_destroy_path(path_to_ferry);
+
+    if (!is_ocean_near_tile(punit->x, punit->y)) {
+      /* Still haven't reached the coast */
+      return FALSE;
+    }
+
+    /* We are on the coast, look around for a boat */
+    boatid = find_ferry_nearby(punit, 2);
+    if (boatid <= 0) {
+      UNIT_LOG(LOGLEVEL_GOTHERE, punit, "requesting a boat.");
+      ai_set_ferry(punit, NULL);
+      return FALSE;
+    }
+
+    /* Ok, a boat found, try boarding it */
+    ferryboat = find_unit_by_id(boatid);
+    UNIT_LOG(LOGLEVEL_GOTHERE, punit, "found a nearby boat[%d](%d,%d)",
+            ferryboat->id, ferryboat->x, ferryboat->y);
+    /* Setting ferry now in hope it won't run away even 
+     * if we can't board it right now */
+    ai_set_ferry(punit, ferryboat);
+    ai_set_passenger(ferryboat, punit);
 
     if (is_tiles_adjacent(punit->x, punit->y, ferryboat->x, ferryboat->y)) {
       (void) ai_unit_move(punit, ferryboat->x, ferryboat->y);
     }
-    
+
     if (!same_pos(punit->x, punit->y, ferryboat->x, ferryboat->y)) {
-      /* Didn't get to the boat */
-      if (is_ocean_near_tile(punit->x, punit->y)) {
-        /* At least got to the coast, wave to the boats! */
-        UNIT_LOG(LOGLEVEL_GOTHERE, punit, "asking a boat to come nearer");
-        ai_set_ferry(punit, NULL);
-      }
+      /* Something prevented us from boarding */
+      UNIT_LOG(LOGLEVEL_GOTHERE, punit, "couldn't board boat[%d](%d,%d)",
+              ferryboat->id, ferryboat->x, ferryboat->y);
       return FALSE;
     }
 
+    handle_unit_load(pplayer, punit->id, ferryboat->id);
+    assert(punit->transported_by > 0);
+  }
+
+  if (punit->transported_by > 0) {
+    /* We are on a boat, ride it! */
+    struct unit *ferryboat = find_unit_by_id(punit->transported_by);
+
     /* Check if we are the passenger-in-charge */
     if (ferryboat->ai.passenger <= 0
         || ferryboat->ai.passenger == punit->id) {
       int beach_x, beach_y;     /* Destination for the boat */
       struct tile *dest_tile = map_get_tile(dest_x, dest_y);
 
-      UNIT_LOG(LOGLEVEL_GOTHERE, punit, "got boat[%d], going (%d,%d)",
-               ferryboat->id, dest_x, dest_y);
-      handle_unit_load(pplayer, punit->id, ferryboat->id);
+      UNIT_LOG(LOGLEVEL_GOTHERE, punit, 
+              "got boat[%d](moves left: %d), going (%d,%d)",
+               ferryboat->id, ferryboat->moves_left, dest_x, dest_y);
       ai_set_passenger(ferryboat, punit);
 
       /* If the location is not accessible directly from sea
@@ -453,7 +489,6 @@
         beach_y = dest_y;
       }
 
-      UNIT_LOG(LOGLEVEL_GOTHERE, punit, "All aboard!");
       set_goto_dest(ferryboat, beach_x, beach_y);
       set_goto_dest(punit, dest_x, dest_y);
       /* Grab bodyguard */
Index: ai/aiunit.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/aiunit.c,v
retrieving revision 1.316
diff -u -r1.316 aiunit.c
--- ai/aiunit.c 23 May 2004 02:05:37 -0000      1.316
+++ ai/aiunit.c 1 Jun 2004 14:40:38 -0000
@@ -2273,9 +2273,9 @@
   UNIT_LOG(LOGLEVEL_FERRY, punit, "Ferryboat is looking for cargo.");
 
   pft_fill_unit_overlap_param(&parameter, punit);
-  /* We are looking for our units, no need to look into the unknown */
-  parameter.get_TB = no_fights_or_unknown;
-  parameter.omniscience = FALSE;
+  /* If we have omniscience, we use it, since paths to some places
+   * might be "blocked" by unknown.  We don't want to fight though */
+  parameter.get_TB = no_fights;
   
   map = pf_create_map(&parameter);
   while (pf_next(map)) {
@@ -2285,7 +2285,8 @@
     
     unit_list_iterate(map_get_tile(pos.x, pos.y)->units, aunit) {
       if (punit->owner == aunit->owner 
-         && aunit->ai.ferryboat == FERRY_WANTED) {
+         && (aunit->ai.ferryboat == FERRY_WANTED
+             || aunit->ai.ferryboat == punit->id)) {
         UNIT_LOG(LOGLEVEL_FERRY, punit, 
                  "Found a potential cargo %s[%d](%d,%d), going there",
                  unit_type(aunit)->name, aunit->id, aunit->x, aunit->y);
@@ -2446,7 +2447,7 @@
       if (!psngr 
          || real_map_distance(punit->x, punit->y, psngr->x, psngr->y) > 1) {
        UNIT_LOG(LOGLEVEL_FERRY, punit, 
-                "lost passenger-in-charge[%d], resetting",
+                "recorded passenger[%d] is not on board, checking for others",
                 punit->ai.passenger);
        punit->ai.passenger = 0;
       }
Index: common/aicore/pf_tools.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/aicore/pf_tools.c,v
retrieving revision 1.14
diff -u -r1.14 pf_tools.c
--- common/aicore/pf_tools.c    19 May 2004 00:49:31 -0000      1.14
+++ common/aicore/pf_tools.c    1 Jun 2004 14:40:39 -0000
@@ -379,6 +379,22 @@
   return TB_NORMAL;
 }
 
+/********************************************************************** 
+  PF callback to prohibit attacking anyone.
+***********************************************************************/
+enum tile_behavior no_fights(int x, int y, enum known_type known,
+                            struct pf_parameter *param)
+{
+  struct tile *ptile = map_get_tile(x, y);
+
+  if (is_non_allied_unit_tile(ptile, param->owner)
+      || is_non_allied_city_tile(ptile, param->owner)) {
+    /* Can't attack */
+    return TB_IGNORE;
+  }
+  return TB_NORMAL;
+}
+
 
 /* =====================  Postion Dangerous Callbacks ================ */
 
@@ -538,8 +554,6 @@
   parameter->unit_flags = unit_type(punit)->flags;
 
   parameter->omniscience = !ai_handicap(unit_owner(punit), H_MAP);
-
-
 }
 
 /**********************************************************************
Index: common/aicore/pf_tools.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/aicore/pf_tools.h,v
retrieving revision 1.6
diff -u -r1.6 pf_tools.h
--- common/aicore/pf_tools.h    28 Jan 2004 21:36:48 -0000      1.6
+++ common/aicore/pf_tools.h    1 Jun 2004 14:40:39 -0000
@@ -26,6 +26,8 @@
 enum tile_behavior no_fights_or_unknown(int x, int y, 
                                         enum known_type known,
                                         struct pf_parameter *param);
+enum tile_behavior no_fights(int x, int y, enum known_type known,
+                            struct pf_parameter *param);
 
 #define pf_iterator(map, position) {                       \
   struct pf_position position;                             \
Index: doc/README.AI
===================================================================
RCS file: /home/freeciv/CVS/freeciv/doc/README.AI,v
retrieving revision 1.11
diff -u -r1.11 README.AI
--- doc/README.AI       19 May 2004 14:06:24 -0000      1.11
+++ doc/README.AI       1 Jun 2004 14:40:39 -0000
@@ -12,6 +12,7 @@
 Amortize
 Estimation of profit from a military operation
 Selecting military units
+Ferry system
 Diplomacy
 Difficulty levels
 Things that needs to be fixed
@@ -220,6 +221,15 @@
 do any calculations, instead one of the passengers is given full
 control and it is the passenger who drives the boat.
 
+Here are the main data fields used by the system.
+Value of ai.ferry in the passenger unit is:
+  FERRY_NONE : means that the unit has no need of a ferry
+  FERRY_WANTED : means that the unit wants a ferry
+  >0 : id of it's ferry
+Value of ai.passenger in the ferry unit can be either of:
+  FERRY_AVAILABLE : means that the unit is a ferry and is available
+  >0 : id of it's passenger
+
 When boat-building code stabilizes, it can be seen how many free boats
 there are, on average, per PP.  If there are more boats than PPs, it
 makes sense that only PPs should look for boats.  If boats are few,

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