Complete.Org: Mailing Lists: Archives: freeciv-ai: November 2004:
[freeciv-ai] (PR#9908) Make AI understand channels
Home

[freeciv-ai] (PR#9908) Make AI understand channels

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
Subject: [freeciv-ai] (PR#9908) Make AI understand channels
From: "Gregory Berkolaiko" <Gregory.Berkolaiko@xxxxxxxxxxxxx>
Date: Wed, 10 Nov 2004 22:11:58 -0800
Reply-to: rt@xxxxxxxxxxx

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

> It seems that the transitivity is not taken into account (i.e. A->B  and
>  B->C  =>  A->C).

Fixed.

> Also you can make it a single array by associating to each ocean the
> smallest of the ocean numbers which are connected to it.  But I am not
> sure if it's worth the trouble.

Couldn't do in any reasonable way.

Also fixed: 
* in is_goto_sane if we are a boat and happen to be in a city, we still
understand that it is ok to go to an ocean
* in ai_channel we receive the result of map_get_continent which is
negative if it's an ocean, so we treat it correspondingly.  if it isn't
negative, we return FALSE.
Index: ai/aidata.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/aidata.c,v
retrieving revision 1.46
diff -u -r1.46 aidata.c
--- ai/aidata.c 23 Oct 2004 19:01:01 -0000      1.46
+++ ai/aidata.c 11 Nov 2004 06:09:46 -0000
@@ -134,7 +134,8 @@
 void ai_data_turn_init(struct player *pplayer) 
 {
   struct ai_data *ai = &aidata[pplayer->player_no];
-  int i, nuke_units = num_role_units(F_NUCLEAR);
+  int i, j, k;
+  int nuke_units = num_role_units(F_NUCLEAR);
   bool danger_of_nukes = FALSE;
   int ally_strength = -1;
   struct player *ally_strongest = NULL;
@@ -225,6 +226,52 @@
   /* Increase from fear to terror if opponent actually has nukes */
   if (danger_of_nukes) ai->threats.nuclear++; /* sum of both fears */
 
+  /*** Channels ***/
+
+  /* Ways to cross from one ocean to another through a city. */
+  ai->channels = fc_calloc((ai->num_oceans + 1) * (ai->num_oceans + 1), 
sizeof(int));
+  players_iterate(aplayer) {
+    if (pplayers_allied(pplayer, aplayer)) {
+      city_list_iterate(aplayer->cities, pcity) {
+        adjc_iterate(pcity->tile, tile1) {
+          if (is_ocean(tile1->terrain)) {
+            adjc_iterate(pcity->tile, tile2) {
+              if (is_ocean(tile2->terrain) 
+                  && map_get_continent(tile1) != map_get_continent(tile2)) {
+                ai->channels[(-tile1->continent) * ai->num_oceans
+                             + (-tile2->continent)] = TRUE;
+                ai->channels[(-tile2->continent) * ai->num_oceans
+                             + (-tile1->continent)] = TRUE;
+              }
+            } adjc_iterate_end;
+          }
+        } adjc_iterate_end;
+      } city_list_iterate_end;
+    }
+  } players_iterate_end;
+
+  /* If we can go i -> j and j -> k, we can also go i -> k. */
+  for(i = 1; i <= ai->num_oceans; i++) {
+    for(j = 1; j <= ai->num_oceans; j++) {
+      if (ai->channels[i * ai->num_oceans + j]) {
+        for(k = 1; k <= ai->num_oceans; k++) {
+          ai->channels[i * ai->num_oceans + k] |= 
+            ai->channels[j * ai->num_oceans + k];
+        }
+      }
+    }
+  }
+#if 0
+  freelog(LOG_NORMAL, "Player %s:", pplayer->name);
+  for(i = 1; i <= ai->num_oceans; i++) {
+    for(j = 1; j <= ai->num_oceans; j++) {
+      if (ai->channels[i * ai->num_oceans + j]) {
+        freelog(LOG_NORMAL, "oceans %d and %d are connected", i, j);
+      }
+    }
+  }
+#endif
+
   /*** Exploration ***/
 
   ai->explore.land_done = TRUE;
@@ -426,6 +473,9 @@
 
   free(ai->stats.cities);
   ai->stats.cities = NULL;
+
+  free(ai->channels);
+  ai->channels = NULL;
 }
 
 /**************************************************************************
@@ -458,7 +508,7 @@
                                    * sizeof(*ai->government_want)));
   memset(ai->government_want, 0,
         (game.government_count + 1) * sizeof(*ai->government_want));
-
+  ai->channels = NULL;
   ai->diplomacy.target = NULL;
   ai->diplomacy.strategy = WIN_OPEN;
   ai->diplomacy.timer = 0;
@@ -481,3 +531,17 @@
     ai->diplomacy.player_intel[i].warned_about_space = 0;
   }
 }
+
+/**************************************************************************
+  Is there a channel going from ocean c1 to ocean c2?
+  Returns FALSE if either is not an ocean.
+**************************************************************************/
+bool ai_channel(struct player *pplayer, Continent_id c1, Continent_id c2)
+{
+  struct ai_data *ai = ai_data_get(pplayer);
+
+  if (c1 >= 0 || c2 >= 0) {
+    return FALSE;
+  }
+  return (c1 == c2 || ai->channels[(-c1) * ai->num_oceans + (-c2)]);
+}
Index: ai/aidata.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/aidata.h,v
retrieving revision 1.19
diff -u -r1.19 aidata.h
--- ai/aidata.h 23 Oct 2004 19:01:01 -0000      1.19
+++ ai/aidata.h 11 Nov 2004 06:09:46 -0000
@@ -97,6 +97,9 @@
     bool sea_done;    /* nothing more to explore at sea */
   } explore;
 
+  /* Keep track of available ocean channels */
+  bool *channels;
+
   /* This struct is used for statistical unit building, eg to ensure
    * that we don't build too few or too many units of a given type. */
   struct {
@@ -149,4 +152,6 @@
 
 struct ai_data *ai_data_get(struct player *pplayer);
 
+bool ai_channel(struct player *pplayer, Continent_id c1, Continent_id c2);
+
 #endif
Index: server/gotohand.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/gotohand.c,v
retrieving revision 1.187
diff -u -r1.187 gotohand.c
--- server/gotohand.c   31 Oct 2004 22:32:33 -0000      1.187
+++ server/gotohand.c   11 Nov 2004 06:09:46 -0000
@@ -33,6 +33,7 @@
 #include "unithand.h"
 #include "unittools.h"
 
+#include "aidata.h"
 #include "aitools.h"
 
 #include "gotohand.h"
@@ -1217,6 +1218,9 @@
 bool goto_is_sane(struct unit *punit, struct tile *ptile, bool omni)
 {  
   struct player *pplayer = unit_owner(punit);
+  struct city *pcity = map_get_city(ptile);
+  Continent_id my_cont = map_get_continent(punit->tile);
+  Continent_id target_cont = map_get_continent(ptile);
 
   if (same_pos(punit->tile, ptile)) {
     return TRUE;
@@ -1235,36 +1239,57 @@
        * and with a boat */
       if (ground_unit_transporter_capacity(ptile, pplayer) > 0) {
         adjc_iterate(ptile, tmp_tile) {
-          if (map_get_continent(tmp_tile) == map_get_continent(punit->tile))
+          if (map_get_continent(tmp_tile) == my_cont) {
             /* The target is adjacent to our continent! */
             return TRUE;
+          }
         } adjc_iterate_end;
       }
     } else {
       /* Going to a land tile: better be our continent */
-      if (map_get_continent(punit->tile) == map_get_continent(ptile)) {
+      if (my_cont == target_cont) {
         return TRUE;
       } else {
         /* Well, it's not our continent, but maybe we are on a boat
          * adjacent to the target continent? */
        adjc_iterate(punit->tile, tmp_tile) {
-         if (map_get_continent(tmp_tile) == map_get_continent(ptile)) {
+         if (map_get_continent(tmp_tile) == target_cont) {
            return TRUE;
           }
        } adjc_iterate_end;
       }
-    }
-      
+    }      
     return FALSE;
 
   case SEA_MOVING:
-    if (is_ocean(map_get_terrain(ptile))
-        || is_ocean_near_tile(ptile)) {
-      /* The target is sea or is accessible from sea 
-       * (allow for bombardment and visiting ports) */
-      return TRUE;
+    if (!is_ocean(map_get_terrain(punit->tile))) {
+      /* Oops, we are not in the open waters.  What ocean do we have 
+       * access to?  We can assume we are in a city and any oceans adjacent
+       * are connected. */
+      adjc_iterate(punit->tile, tmp_tile) {
+        if (is_ocean(map_get_terrain(tmp_tile))) {
+          my_cont = map_get_continent(tmp_tile);
+          break;
+        }
+      } adjc_iterate_end;
     }
-    return FALSE;
+
+    if (is_ocean(map_get_terrain(ptile))) {
+      if (ai_channel(pplayer, target_cont, my_cont)) {
+        return TRUE; /* Ocean -> Ocean travel ok. */
+      }
+    } else if ((pcity && pplayers_allied(city_owner(pcity), pplayer))
+               || !unit_flag(punit, F_NO_LAND_ATTACK)) {
+      /* Not ocean, but allied city or can bombard, checking if there is 
+       * good ocean adjacent */
+      adjc_iterate(ptile, tmp_tile) {
+        if (is_ocean(map_get_terrain(tmp_tile)) 
+            && ai_channel(pplayer, my_cont, map_get_continent(tmp_tile))) {
+          return TRUE;
+        }
+      } adjc_iterate_end;
+    }
+    return FALSE; /* Not ok. */
 
   default:
     return TRUE;

[Prev in Thread] Current Thread [Next in Thread]
  • [freeciv-ai] (PR#9908) Make AI understand channels, Gregory Berkolaiko <=