Complete.Org: Mailing Lists: Archives: freeciv-dev: September 2003:
[Freeciv-Dev] (PR#6131) bunch of changes to AI wall, coastal & SAM code
Home

[Freeciv-Dev] (PR#6131) bunch of changes to AI wall, coastal & SAM code

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
To: undisclosed-recipients: ;
Subject: [Freeciv-Dev] (PR#6131) bunch of changes to AI wall, coastal & SAM code
From: "Per I. Mathisen" <per@xxxxxxxxxxx>
Date: Wed, 10 Sep 2003 15:12:07 -0700
Reply-to: rt@xxxxxxxxxxxxxx

I looked hard at a savegame pille sent me this evening, trying to figure
out why the AI wasn't building SAMs to counter pille's massive air fleets,
which he used to successfully beat 15 teamed hard AIs (!!). Turned out
there was more than one reason. A lot more.


worstenemy: This is based on an idea from pille. We look at all a player's
active units, where active is defined as moved in last turn, and figure
out if he is going for land, sea or air primarily. Then we adjust want for
coastal and SAM accordingly. (We don't touch walls here.)

rewritewall: This is a first attempt to rewrite the final instance
wall/sam/coastal deciding code, which was hideous. I made the logic a bit
simpler, and also made sure that we build coastal or SAM instead of wall
when there are wanted higher (previously we would build wall first no
matter what...).

no_overwrite_defense: In assess_danger(), we might overwrite the want for
wall, coastal and SAM by a _smaller_ value than given to them by the
threat code. Bad!

funitbug: This is a really awful bug. Basically we create an empty virtual
unit, and then do a lot of checks on it, when we really should be checking
the real unit (punit). No wonder SAM never worked!

adjustattackers: Sometimes units start pouring out attacking units, but
don't find any place to send them afterwards. This can be for various
reasons, I guess. In any case, if we support loads of units that just sit
there, desire more of them less.

consider_defense: Another bug, I think. In the general buildings code, we
massage away any buildings requiring upkeep that have low want. This way
we massage wall, coastal and SAM down to zero want, and later cause
assess_danger() to skip considering these, since it checks if previous
code wanted them at least 1 point of want!


Overall result: We now build lots of more SAM when the enemy has lots of
air units. We also build less attackers in typical "caught in
build-attackers-loop" cities.

Possible problems: I've changed rather critical code that has worked so-so
for some time now. Some more playtesting is needed. Please help out.

  - Per

Index: ai/advdomestic.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/advdomestic.c,v
retrieving revision 1.103
diff -u -r1.103 advdomestic.c
--- ai/advdomestic.c    29 Apr 2003 08:40:11 -0000      1.103
+++ ai/advdomestic.c    10 Sep 2003 21:45:30 -0000
@@ -79,14 +80,18 @@
 static int ai_eval_threat_sea(struct player *pplayer, struct city *pcity)
 {
   struct ai_data *ai = ai_data_get(pplayer);
+  int want = 1;
 
   /* make easy AI stay dumb */
   if (ai_handicap(pplayer, H_DEFENSIVE)) {
-    return 40;
+    want = 40;
+  } else if (ai->threats.sea) {
+    want = TRADE_WEIGHTING + 3;
+    if (ai->threats.worst_move_type == SEA_MOVING) {
+      want += 80;
+    }
   }
-
-  /* trump coinage, and wall, and sam */
-  return ai->threats.sea ? TRADE_WEIGHTING + 3 : 1;
+  return want;
 }
 
 /**************************************************************************
@@ -95,21 +100,20 @@
 static int ai_eval_threat_air(struct player *pplayer, struct city *pcity)
 {
   struct ai_data *ai = ai_data_get(pplayer);
-  int continent;
-  bool vulnerable;
+  int continent = map_get_continent(pcity->x, pcity->y);
+  int want = 1;
 
-  /* make easy AI dumber */
+  /* make easy AI stay dumb */
   if (ai_handicap(pplayer, H_DEFENSIVE)) {
-    return 50;
+    want = 50;
+  } else if (ai->threats.air) {
+    want = TRADE_WEIGHTING + 1;
+    want += (ai->threats.continent[continent]
+             || is_water_adjacent_to_tile(pcity->x, pcity->y) 
+             || city_got_building(pcity, B_PALACE)) ? TRADE_WEIGHTING : 0;
+    want += (ai->threats.worst_move_type == AIR_MOVING) ? 60 : 0;
   }
-
-  continent = map_get_continent(pcity->x, pcity->y);
-  vulnerable = ai->threats.air
-               && (ai->threats.continent[continent]
-                   || is_water_adjacent_to_tile(pcity->x, pcity->y) 
-                   || city_got_building(pcity, B_PALACE));
-
-  return vulnerable ? TRADE_WEIGHTING + 1 : 1; /* trump coinage */
+  return want;
 }
 
 /**************************************************************************
Index: ai/aidata.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/aidata.c,v
retrieving revision 1.20
diff -u -r1.20 aidata.c
--- ai/aidata.c 8 Aug 2003 22:11:41 -0000       1.20
+++ ai/aidata.c 10 Sep 2003 21:45:31 -0000
@@ -66,9 +66,15 @@
   bool can_build_antimissile = can_player_build_improvement(pplayer, B_SDI);
   int ally_strength = -1;
   struct player *ally_strongest = NULL;
+  int active_units[AIR_MOVING], worst_move_type_num = 0;
 
   /*** Threats ***/
 
+  for (i = LAND_MOVING; i <= AIR_MOVING; i++) {
+    active_units[i] = 0;
+  }
+  ai->threats.worst_move_type = LAND_MOVING;
+
   ai->num_continents = map.num_continents;
   ai->threats.continent = fc_calloc(ai->num_continents + 1, sizeof(bool));
   ai->threats.invasions = FALSE;
@@ -91,6 +97,10 @@
     } city_list_iterate_end;
 
     unit_list_iterate(aplayer->units, punit) {
+      if (punit->moves_left < unit_move_rate(punit)) {
+        active_units[unit_type(punit)->move_type]++;
+      }
+
       if (is_sailing_unit(punit)) {
         /* If the enemy has not started sailing yet, or we have total
          * control over the seas, don't worry, keep attacking. */
@@ -107,8 +117,8 @@
 
       /* The next idea is that if our enemies don't have any offensive
        * airborne units, we don't have to worry. Go on the offensive! */
-      if (can_build_antiair && (is_air_unit(punit) || is_heli_unit(punit))
-           && unit_type(punit)->attack_strength > 1) {
+      if (can_build_antiair && is_air_unit(punit)
+          && unit_type(punit)->attack_strength > 1) {
         ai->threats.air = TRUE;
       }
 
@@ -141,8 +151,17 @@
         ai->threats.nuclear = 1;
       }
     }
+
   } players_iterate_end;
 
+  /* Calculate worst problem */
+  for (i = LAND_MOVING; i <= AIR_MOVING; i++) {
+    if (active_units[i] > worst_move_type_num) {
+      worst_move_type_num = active_units[i];
+      ai->threats.worst_move_type = i;
+    }
+  }
+
   /* Increase from fear to terror if opponent actually has nukes */
   if (danger_of_nukes) ai->threats.nuclear++; /* sum of both fears */
 
@@ -342,6 +361,7 @@
   ai->diplomacy.req_love_for_alliance = 8;
   ai->diplomacy.req_love_for_ceasefire = 0;
   ai->diplomacy.alliance_leader = pplayer;
+  ai->threats.worst_move_type = LAND_MOVING;
 
   for (i = 0; i < MAX_NUM_PLAYERS; i++) {
     ai->diplomacy.player_intel[i].spam = i; /* pseudorandom */
Index: ai/aidata.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/aidata.h,v
retrieving revision 1.10
diff -u -r1.10 aidata.h
--- ai/aidata.h 8 Aug 2003 22:11:41 -0000       1.10
+++ ai/aidata.h 10 Sep 2003 21:45:31 -0000
@@ -16,6 +16,7 @@
 /* max size of a short */
 #define MAX_NUM_ID 32767
 
+#include "unittype.h"          /* enum unit_move_type */
 #include "shared.h"            /* bool type */
 
 struct player;
@@ -71,6 +72,7 @@
 
   /* Long-term threats, not to be confused with short-term danger */
   struct {
+    enum unit_move_type worst_move_type;
     bool invasions;   /* check if we need to consider invasions */
     bool *continent;  /* non-allied cities on continent? */
     bool sea;         /* check if exists non-allied offensive ships */
Index: ai/advmilitary.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/advmilitary.c,v
retrieving revision 1.150
diff -u -r1.150 advmilitary.c
--- ai/advmilitary.c    10 Sep 2003 17:51:03 -0000      1.150
+++ ai/advmilitary.c    10 Sep 2003 21:45:30 -0000
@@ -1186,7 +1212,7 @@
                                   struct ai_choice *choice)
 {
   Unit_Type_id unit_type;
-  int our_def, danger, urgency;
+  int our_def, urgency;
   struct tile *ptile = map_get_tile(pcity->x, pcity->y);
   struct unit *virtualunit;
 
@@ -1204,90 +1230,47 @@
   ai_choose_diplomat_defensive(pplayer, pcity, choice, our_def);
 
   /* Otherwise no need to defend yet */
-  if (pcity->ai.danger != 0) { 
+  if (pcity->ai.danger > our_def) {
     int num_defenders = unit_list_size(&ptile->units);
 
-    /* First determine the danger.  It is measured in percents of our 
-     * defensive strength, capped at 200 + urgency */
-    if (pcity->ai.danger >= our_def) {
-      if (urgency == 0) {
-        /* don't waste money */
-        danger = 100;
-      } else if (our_def == 0) {
-        danger = 200 + urgency;
-      } else {
-        danger = MIN(200, 100 * pcity->ai.danger / our_def) + urgency;
-      }
-    } else { 
-      danger = 100 * pcity->ai.danger / our_def;
-    }
-    if (pcity->shield_surplus <= 0 && our_def != 0) {
-      /* Won't be able to support anything */
-      danger = 0;
-    }
-
-    /* FIXME: 1. Will tend to build walls beofre coastal irrespectfully what
-     * type of danger we are facing
-     * 2. (80 - pcity->shield_stock) * 2 below is hardcoded price of walls */
-    /* We will build walls if we can and want and (have "enough" defenders or
-     * can just buy the walls straight away) */
-    if (pcity->ai.building_want[B_CITY] != 0 && our_def != 0 
-        && can_build_improvement(pcity, B_CITY)
-        && (danger < 101 || num_defenders > 1
-            || (pcity->ai.grave_danger == 0 
-                && pplayer->economic.gold > (80 - pcity->shield_stock) * 2)) 
-        && ai_fuzzy(pplayer, TRUE)) {
-      /* NB: great wall is under domestic */
-      choice->choice = B_CITY;
-      /* building_want is hacked by assess_danger */
-      choice->want = pcity->ai.building_want[B_CITY];
-      if (urgency == 0 && choice->want > 100) {
-        choice->want = 100;
-      }
-      choice->type = CT_BUILDING;
-
-    } else if (pcity->ai.building_want[B_COASTAL] != 0 && our_def != 0 
-               && can_build_improvement(pcity, B_COASTAL) 
-               && (danger < 101 || num_defenders > 1) 
-               && ai_fuzzy(pplayer, TRUE)) {
-      choice->choice = B_COASTAL;
-      /* building_want is hacked by assess_danger */
-      choice->want = pcity->ai.building_want[B_COASTAL];
-      if (urgency == 0 && choice->want > 100) {
-        choice->want = 100;
-      }
-      choice->type = CT_BUILDING;
-
-    } else if (pcity->ai.building_want[B_SAM] != 0 && our_def != 0 
-               && can_build_improvement(pcity, B_SAM) 
-               && (danger < 101 || num_defenders > 1) 
-               && ai_fuzzy(pplayer, TRUE)) {
-      choice->choice = B_SAM;
-      /* building_want is hacked by assess_danger */
-      choice->want = pcity->ai.building_want[B_SAM];
-      if (urgency == 0 && choice->want > 100) {
-        choice->want = 100;
-      }
-      choice->type = CT_BUILDING;
-
-    } else if (danger > 0 && num_defenders <= urgency) {
-      /* Consider building defensive units units */
-      process_defender_want(pplayer, pcity, danger, choice);
-      if (urgency == 0 && unit_types[choice->choice].defense_strength == 1) {
-        if (city_got_barracks(pcity)) {
-          /* unlikely */
-          choice->want = MIN(49, danger);
-        } else {
-          choice->want = MIN(25, danger);
+    /* We will build defenses if we can and want and have "enough" defenders */
+    /* pcity->ai.building_want is hacked by assess_danger */
+    if (num_defenders > 1 && our_def > 0) {
+      if (pcity->ai.building_want[B_CITY] > 0
+          && can_build_improvement(pcity, B_CITY)) {
+        choice->choice = B_CITY;
+        choice->want = pcity->ai.building_want[B_CITY];
+        if (urgency == 0 && choice->want > 100) {
+          choice->want = 100;
         }
-      } else {
-        choice->want = danger;
+        choice->type = CT_BUILDING;
       }
+      if (pcity->ai.building_want[B_COASTAL] 
+           > pcity->ai.building_want[B_CITY] > 0
+          && can_build_improvement(pcity, B_COASTAL)) {
+        choice->choice = B_COASTAL;
+        choice->want = pcity->ai.building_want[B_COASTAL];
+        choice->type = CT_BUILDING;
+      }
+      if (pcity->ai.building_want[B_SAM] > pcity->ai.building_want[B_COASTAL] 
+          && pcity->ai.building_want[B_SAM] > pcity->ai.building_want[B_CITY]
+          && pcity->ai.building_want[B_SAM] > 0
+          && can_build_improvement(pcity, B_SAM)) {
+        choice->choice = B_SAM;
+        choice->want = pcity->ai.building_want[B_SAM];
+        choice->type = CT_BUILDING;
+      }
+    } else if (num_defenders <= urgency
+               && (pcity->shield_surplus > 0 
+                   || (our_def == 0 && pcity->ai.grave_danger > 0))) {
+      /* Consider building defensive units units */
+      process_defender_want(pplayer, pcity, pcity->ai.danger, choice);
+      choice->want = pcity->ai.danger;
       freelog(LOG_DEBUG, "%s wants %s to defend with desire %d.",
                     pcity->name, get_unit_type(choice->choice)->name,
                     choice->want);
     }
-  } /* ok, don't need to defend */
+  }
 
   if (pcity->shield_surplus <= 0 
       || pcity->ppl_unhappy[4] > pcity->ppl_unhappy[2]) {
Index: ai/advmilitary.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/advmilitary.c,v
retrieving revision 1.150
diff -u -r1.150 advmilitary.c
--- ai/advmilitary.c    10 Sep 2003 17:51:03 -0000      1.150
+++ ai/advmilitary.c    10 Sep 2003 21:45:30 -0000
@@ -396,7 +396,7 @@
     return;
   }
 
-  *value = 100 + MAX(0, urgency); /* default */
+  *value = MAX(*value, 100 + MAX(0, urgency)); /* default */
 
   if (urgency > 0 && danger > defense * 2) {
     *value += 100;
Index: ai/advmilitary.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/advmilitary.c,v
retrieving revision 1.150
diff -u -r1.150 advmilitary.c
--- ai/advmilitary.c    10 Sep 2003 17:51:03 -0000      1.150
+++ ai/advmilitary.c    10 Sep 2003 21:45:30 -0000
@@ -427,11 +430,8 @@
   bool pikemen = FALSE;
   int urgency = 0;
   int igwall_threat = 0;
-  struct unit virtualunit;
-  struct unit *funit = &virtualunit; /* saves me a lot of typing. -- Syela */
   struct tile *ptile = map_get_tile(pcity->x, pcity->y);
 
-  memset(&virtualunit, 0, sizeof(struct unit));
   memset(&danger, 0, sizeof(danger));
 
   generate_warmap(pcity, NULL);        /* generates both land and sea maps */
@@ -498,16 +507,16 @@
 
       if (!igwall) {
         danger[1] += vulnerability * move_rate / MAX(dist, 1); /* walls */
-      } else if (is_sailing_unit(funit)) {
+      } else if (is_sailing_unit(punit)) {
         danger[2] += vulnerability * move_rate / MAX(dist, 1); /* coastal */
-      } else if (is_air_unit(funit) && !unit_flag(funit, F_NUCLEAR)) {
+      } else if (is_air_unit(punit) && !unit_flag(punit, F_NUCLEAR)) {
         danger[3] += vulnerability * move_rate / MAX(dist, 1); /* SAM */
       }
-      if (unit_flag(funit, F_MISSILE)) {
+      if (unit_flag(punit, F_MISSILE)) {
         /* SDI */
         danger[4] += vulnerability * move_rate / MAX(move_rate, dist);
       }
-      if (!unit_flag(funit, F_NUCLEAR)) {
+      if (!unit_flag(punit, F_NUCLEAR)) {
         /* only SDI helps against NUCLEAR */
         vulnerability = dangerfunct(vulnerability, move_rate, dist);
         danger[0] += vulnerability;
Index: ai/advmilitary.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/advmilitary.c,v
retrieving revision 1.150
diff -u -r1.150 advmilitary.c
--- ai/advmilitary.c    10 Sep 2003 17:51:03 -0000      1.150
+++ ai/advmilitary.c    10 Sep 2003 21:45:30 -0000
@@ -953,6 +962,16 @@
   /* Is the defender veteran? */
   bool def_vet;
   struct ai_choice best_choice;
+  int adjust_want = 0; /* adjust want if lots of attackers already */
+
+  /* Set adjust_want exponentially */
+  unit_list_iterate(pcity->units_supported, other) {
+    if (IS_ATTACKER(other) && other->moves_left == unit_move_rate(other)
+        && (other->activity == ACTIVITY_SENTRY
+            || other->activity == ACTIVITY_FORTIFIED)) {
+      adjust_want += MAX(adjust_want / 2, 1);
+    }
+  } unit_list_iterate_end;
 
   init_choice(&best_choice);
   best_choice.choice = myunit->type;
@@ -1079,6 +1098,13 @@
                           &best_choice, ferryboat, boattype);
   }
 
+  /* Adjust want for lots of attackers idling in town */
+  while (adjust_want > 0) {
+    best_choice.want -= (best_choice.want / 10) * MIN(adjust_want, 90);
+    adjust_want -= MAX(adjust_want, 9);
+  }
+  best_choice.want = MAX(0, best_choice.want);
+
   if (best_choice.want > choice->want) {
     /* We want attacker more that what we have selected before */
     copy_if_better_choice(&best_choice, choice);
Index: ai/advdomestic.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/advdomestic.c,v
retrieving revision 1.103
diff -u -r1.103 advdomestic.c
--- ai/advdomestic.c    29 Apr 2003 08:40:11 -0000      1.103
+++ ai/advdomestic.c    10 Sep 2003 21:45:30 -0000
@@ -812,7 +816,7 @@
   /* Final massage */
   impr_type_iterate(id) {
     if (values[id] >= 0) {
-      if (!is_wonder(id)) {
+      if (!is_wonder(id) && id != B_SAM && id != B_CITY && id != B_COASTAL) {
         /* trying to buy fewer improvements */
         values[id]-= improvement_upkeep(pcity, id) * t;
         values[id] = (values[id] <= 0 

[Prev in Thread] Current Thread [Next in Thread]
  • [Freeciv-Dev] (PR#6131) bunch of changes to AI wall, coastal & SAM code, Per I. Mathisen <=