Complete.Org: Mailing Lists: Archives: freeciv-ai: March 2004:
[freeciv-ai] paratroopers
Home

[freeciv-ai] paratroopers

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
To: freeciv-ai@xxxxxxxxxxx
Subject: [freeciv-ai] paratroopers
From: Jordi Negrevernis i Font <jorneg@xxxxxxxxxxx>
Date: Thu, 18 Mar 2004 20:50:53 +0100


Hi, this is a first attempt to teach the AI how to use the paratrooper unit.

It's very simple and can be greatly improved. The wants of the advisor are generally too high.

   It's against cvs Feb-27.

   I can improve it if you plan to include in cvs.

   Comments and feedback are welcome.

diff -NurEbB -Xfreeciv-cvs-Feb-27/diff_ignore 
freeciv-cvs-Feb-27/ai/advmilitary.c 
freeciv-cvs-Feb-27-paratroop/ai/advmilitary.c
--- freeciv-cvs-Feb-27/ai/advmilitary.c 2004-02-26 07:01:21.000000000 +0100
+++ freeciv-cvs-Feb-27-paratroop/ai/advmilitary.c       2004-03-18 
02:37:15.000000000 +0100
@@ -35,6 +35,7 @@
 #include "aidiplomat.h"
 #include "aihand.h"
 #include "ailog.h"
+#include "aiparatrooper.h"
 #include "aitools.h"
 #include "aiunit.h"

@@ -1306,6 +1307,9 @@
   /* Consider making an airplane */
   (void) ai_choose_attacker_air(pplayer, pcity, choice);

+  /* Consider making a paratrooper */
+  ai_choose_paratrooper(pplayer, pcity, choice);
+
   /* Check if we want a sailing attacker. Have to put sailing first
      before we mung the seamap */
   unit_type = ai_choose_attacker(pcity, SEA_MOVING);
diff -NurEbB -Xfreeciv-cvs-Feb-27/diff_ignore 
freeciv-cvs-Feb-27/ai/aiparatrooper.c 
freeciv-cvs-Feb-27-paratroop/ai/aiparatrooper.c
--- freeciv-cvs-Feb-27/ai/aiparatrooper.c       1970-01-01 01:00:00.000000000 
+0100
+++ freeciv-cvs-Feb-27-paratroop/ai/aiparatrooper.c     2004-03-18 
18:08:07.000000000 +0100
@@ -0,0 +1,286 @@
+/**********************************************************************
+ Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <assert.h>
+
+#include "city.h"
+#include "citytools.h"
+#include "log.h"
+#include "pf_tools.h"
+#include "player.h"
+#include "unit.h"
+#include "unittools.h"
+
+#include "ailog.h"
+#include "aiparatrooper.h"
+#include "aiunit.h"
+#include "aitools.h"
+
+#define LOGLEVEL_PARATROOPER LOG_NORMAL
+
+/**********************************************************************
+  Find own city to go there to recover and paradroop.
+
+  TODO: Actually check how safe the city is. This is a difficult
+  decision not easily taken, since we also want to protect unsafe
+  cities, at least most of the time.
+***********************************************************************/
+static struct city *find_nearest_own_city_at(struct player *pplayer, int x, 
int y)
+{ int best = 0, cur = 0;
+  int continent = map_get_continent(x, y);
+  struct city *acity = NULL;
+
+  city_list_iterate(pplayer->cities, pcity) {
+    cur = real_map_distance(pcity->x, pcity->y, x ,y);
+    if (city_got_building(pcity, B_BARRACKS)
+       || city_got_building(pcity, B_BARRACKS2)
+       || city_got_building(pcity, B_BARRACKS3)) {
+      cur /= 3;
+    }
+    if (continent != map_get_continent(pcity->x, pcity->y)) {
+      /* it must be in the same continent */
+      cur = 0;
+    }
+    if (cur < best) {
+      best = cur;
+      acity = pcity;
+    }
+  } city_list_iterate_end;
+
+  return acity;
+}
+
+/*************************************************************************
+ This function does manage the paratrooper units of the AI.
+ 1st.- checks for cities left alone without defenders
+ 2nd.- checks for enemy units in range
+ 3th.- checks for enemy cities left alone
+**************************************************************************/
+void ai_manage_paratrooper(struct player *pplayer, struct unit *punit)
+{
+  struct city *pcity = map_get_city(punit->x, punit->y);
+  struct city *acity = NULL;
+  int sanity = punit->id;
+  int x_dest = 0, y_dest = 0, best = 0;
+
+  CHECK_UNIT(punit);
+
+  /* defend attacking (and be opportunistic too)*/
+  if (!ai_military_rampage(punit, RAMPAGE_ANYTHING, 
RAMPAGE_FREE_CITY_OR_BETTER)) {
+    UNIT_LOG(LOGLEVEL_PARATROOPER, punit, "dead defending.",
+             pplayer->name, unit_type(punit)->name, punit->id, punit->x,
+             punit->y);
+    return;
+  }
+
+  /* check to recover hit points */
+  if ((punit->hp < unit_type(punit)->hp) && pcity) {
+    UNIT_LOG(LOGLEVEL_PARATROOPER, punit, "recovering hit points.",
+             pplayer->name, unit_type(punit)->name, punit->id, punit->x, 
punit->y);
+    return;
+  }
+
+  if (can_unit_paradrop(punit)) {
+    /* unit can paradrop, so use it! */
+    int range = unit_type(punit)->paratroopers_range;
+
+    /* first, we search for undefended cities */
+    square_iterate(punit->x, punit->y, range, x, y) {
+      acity = map_get_city(x,y);
+      if ((acity) && (city_owner(acity) == pplayer) &&
+          (unit_list_size(&(map_get_tile(x, y)->units)) == 0)) {
+        /* own city and empty! */
+        if (best < (pcity->size * pcity->ai.danger)) {
+          best = pcity->size * pcity->ai.danger;
+          x_dest = acity->x; y_dest = acity->y;
+        }
+      }
+    } square_iterate_end;
+
+    /* second, we search for enemy units near us,
+       if we don't find any own empty city */
+    if (best == 0) {
+      square_iterate(punit->x, punit->y, range, x, y) {
+        struct tile *ptile = map_get_tile(x, y);
+        if (unit_list_size(&(ptile->units)) > 0) {
+          struct unit *pdef = unit_list_get(&ptile->units, 0);
+         if (pplayers_at_war(pplayer, unit_owner(pdef))) {
+           int benefit = stack_cost(pdef);
+            benefit = (benefit * punit->hp) / unit_type(punit)->hp;
+            if (benefit > best) {
+              /* best enemy unit to kill! */
+             best = benefit;
+             x_dest = x; y_dest = y;
+           }
+         }
+        }
+      } square_iterate_end;
+
+      if (best > 0) {
+        /* now we have the location of the enemy unit, we find the best tile 
around it,
+          to attack him */
+       struct city *acity = find_nearest_own_city_at(unit_owner(punit), 
x_dest, y_dest);
+       best = 0;
+
+       square_iterate(x_dest, y_dest, 1, x, y) {
+         int rating = 0;
+         if (is_ocean(map_get_terrain(x, y))) {
+           /*  do not paradrop to ocean! */
+           continue;
+         }
+          if (could_unit_move_to_tile(punit, x, y)) {
+           switch(map_get_terrain(x, y)) {
+             case T_FOREST:
+             case T_HILLS:
+             case T_JUNGLE:
+               rating = 2; break;
+             case T_MOUNTAINS:
+               rating = 4; break;
+             default:
+               rating = 0; break;
+           };
+           rating += real_map_distance(punit->x, punit->y, acity->x, acity->y) 
+ 1;
+
+           if (rating > best) {
+             /* we assign the best location to attack the unit */
+             best = rating;
+             x_dest = x; y_dest = y;
+           }
+
+         }
+       } square_iterate_end;
+      }
+    }
+
+    /* third, we search for undefended enemy cities near us */
+    if (best == 0) {
+      square_iterate(punit->x, punit->y, range, x, y) {
+        acity = map_get_city(x,y);
+        if ((acity) && pplayers_at_war(pplayer, city_owner(acity)) &&
+            (unit_list_size(&(map_get_tile(x, y)->units)) == 0)) {
+          /* enemy empty city! */
+          if (best < pcity->size) {
+            best = pcity->size;
+            x_dest = acity->x; y_dest = acity->y;
+          }
+        }
+      } square_iterate_end;
+    }
+
+    if (best) {
+      /* we move the unit */
+      set_goto_dest(punit, x_dest, y_dest);
+      UNIT_LOG(LOGLEVEL_PARATROOPER, punit, "paradroping.",
+               pplayer->name, unit_type(punit)->name, punit->id, punit->x,
+               punit->y, x_dest, y_dest);
+      if (do_paradrop(punit, x_dest, y_dest)) {
+        /* successfull! */
+        if (!find_unit_by_id(sanity)) {
+          /* the unit did not survive the move */
+          return;
+        }
+        /* and we attack the target */
+        (void)ai_military_rampage(punit, RAMPAGE_ANYTHING, RAMPAGE_ANYTHING);
+      }
+      clear_goto_dest(punit);
+    } else {
+      UNIT_LOG(LOGLEVEL_PARATROOPER, punit, "dind't find objective to paradrop 
to.",
+               pplayer->name, unit_type(punit)->name, punit->id, punit->x,
+               punit->y, x_dest, y_dest);
+      /* TODO: go to zones in danger */
+    }
+  } else {
+    /* we can't paradrop :-(  */
+    struct city *acity = find_nearest_own_city_at(unit_owner(punit), punit->x, 
punit->y);
+
+    if (acity) {
+      if (!ai_unit_goto(punit, acity->x, acity->y)) {
+        freelog(LOGLEVEL_PARATROOPER, "died trying to return to city to 
recover and paradrop");
+      }
+    } else {
+      freelog(LOGLEVEL_PARATROOPER, "didn't find city to go and recover");
+    }
+  }
+}
+
+/*******************************************************************
+  Computes the want for an operation
+ ******************************************************************/
+static int find_something_to_paradrop(struct unit *punit, int x, int y)
+{ int profit = 0;
+  int range = unit_type(punit)->paratroopers_range;
+  struct city *acity = NULL;
+  struct player *pplayer = unit_owner(punit);
+
+  /* first, we search for undefended cities */
+  square_iterate(punit->x, punit->y, range, x, y) {
+    acity = map_get_city(x,y);
+    if ((acity) && (city_owner(acity) == pplayer) &&
+        (unit_list_size(&(map_get_tile(x, y)->units)) == 0)) {
+      /* own city and empty! */
+      if (profit < (acity->trade_prod + acity->shield_prod + acity->food_prod) 
* acity->size) {
+        profit = (acity->trade_prod + acity->shield_prod + acity->food_prod) * 
acity->size;
+      }
+    }
+  } square_iterate_end;
+
+  /* second, we search for enemy units near us,
+     if we don't find any own empty city */
+
+  /* third, we search for undefended enemy cities near us */
+
+  return profit;
+}
+
+/*******************************************************************
+ * Chooses to build a paratroop if necessary
+ ******************************************************************/
+void ai_choose_paratrooper(struct player *pplayer, struct city *pcity,
+                           struct ai_choice *choice)
+{
+
+  /* military_advisor_choose_build does something idiotic,
+   * this function should not be called if there is danger... */
+  if (choice->want >= 100 && choice->type != CT_ATTACKER) {
+    return;
+  }
+
+  unit_type_iterate(u_type) {
+    if (!unit_type_flag(u_type, F_PARATROOPERS)) {
+      continue;
+    }
+
+    if (!can_build_unit(pcity, u_type)) {
+      continue;
+    }
+
+    struct unit *virtual_unit = create_unit_virtual(pplayer, pcity, u_type,
+                                                    
do_make_unit_veteran(pcity, u_type));
+    int profit = find_something_to_paradrop(virtual_unit, pcity->x, pcity->y);
+    if (profit > choice->want){
+      /* Update choice */
+      choice->want = profit;
+      choice->choice = u_type;
+      choice->type = CT_ATTACKER;
+      freelog(LOGLEVEL_PARATROOPER, "%s wants to build %s (want=%d)",
+              pcity->name, get_unit_type(u_type)->name, profit);
+    }
+    destroy_unit_virtual(virtual_unit);
+  } unit_type_iterate_end;
+
+  return;
+}
diff -NurEbB -Xfreeciv-cvs-Feb-27/diff_ignore 
freeciv-cvs-Feb-27/ai/aiparatrooper.h 
freeciv-cvs-Feb-27-paratroop/ai/aiparatrooper.h
--- freeciv-cvs-Feb-27/ai/aiparatrooper.h       1970-01-01 01:00:00.000000000 
+0100
+++ freeciv-cvs-Feb-27-paratroop/ai/aiparatrooper.h     2004-03-18 
02:34:36.000000000 +0100
@@ -0,0 +1,25 @@
+/**********************************************************************
+ Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+***********************************************************************/
+#ifndef FC__AIPARATROOPER_H
+#define FC__AIPARATROOPER_H
+
+struct ai_choice;
+struct city;
+struct player;
+struct unit;
+
+void ai_manage_paratrooper(struct player *pplayer, struct unit *punit);
+void ai_choose_paratrooper(struct player *pplayer, struct city *pcity,
+                          struct ai_choice *choice);
+
+#endif /* FC__AIPARATROOPER_H */
diff -NurEbB -Xfreeciv-cvs-Feb-27/diff_ignore freeciv-cvs-Feb-27/ai/aiunit.c 
freeciv-cvs-Feb-27-paratroop/ai/aiunit.c
--- freeciv-cvs-Feb-27/ai/aiunit.c      2004-02-26 07:01:21.000000000 +0100
+++ freeciv-cvs-Feb-27-paratroop/ai/aiunit.c    2004-03-18 13:15:13.000000000 
+0100
@@ -55,6 +55,7 @@
 #include "aidiplomat.h"
 #include "aihand.h"
 #include "ailog.h"
+#include "aiparatrooper.h"
 #include "aitools.h"

 #include "aiunit.h"
@@ -67,11 +68,6 @@
 static void ai_manage_barbarian_leader(struct player *pplayer,
                                       struct unit *leader);

-#define RAMPAGE_ANYTHING                 1
-#define RAMPAGE_HUT_OR_BETTER        99998
-#define RAMPAGE_FREE_CITY_OR_BETTER  99999
-static bool ai_military_rampage(struct unit *punit, int thresh_adj,
-                                int thresh_move);
 static void ai_military_findjob(struct player *pplayer,struct unit *punit);
 static void ai_military_gohome(struct player *pplayer,struct unit *punit);
 static void ai_military_attack(struct player *pplayer,struct unit *punit);
@@ -1052,7 +1048,7 @@

   Returns TRUE if survived the rampage session.
 **************************************************************************/
-static bool ai_military_rampage(struct unit *punit, int thresh_adj,
+bool ai_military_rampage(struct unit *punit, int thresh_adj,
                                 int thresh_move)
 {
   int count = punit->moves_left + 1; /* break any infinite loops */
@@ -2653,6 +2649,9 @@
   } else if (unit_has_role(punit->type, L_BARBARIAN_LEADER)) {
     ai_manage_barbarian_leader(pplayer, punit);
     return;
+  } else if (unit_flag(punit, F_PARATROOPERS)) {
+    ai_manage_paratrooper(pplayer, punit);
+    return;
   } else if (get_transporter_capacity(punit) > 0) {
     ai_manage_ferryboat(pplayer, punit);
     return;
diff -NurEbB -Xfreeciv-cvs-Feb-27/diff_ignore freeciv-cvs-Feb-27/ai/aiunit.h 
freeciv-cvs-Feb-27-paratroop/ai/aiunit.h
--- freeciv-cvs-Feb-27/ai/aiunit.h      2004-01-12 07:16:15.000000000 +0100
+++ freeciv-cvs-Feb-27-paratroop/ai/aiunit.h    2004-03-18 11:34:49.000000000 
+0100
@@ -46,6 +46,11 @@

 extern Unit_Type_id simple_ai_types[U_LAST];

+#define RAMPAGE_ANYTHING                 1
+#define RAMPAGE_HUT_OR_BETTER        99998
+#define RAMPAGE_FREE_CITY_OR_BETTER  99999
+bool ai_military_rampage(struct unit *punit, int thresh_adj,
+                         int thresh_move);
 void ai_manage_units(struct player *pplayer);
 int could_unit_move_to_tile(struct unit *punit, int dest_x, int dest_y);
 int look_for_charge(struct player *pplayer, struct unit *punit,
diff -NurEbB -Xfreeciv-cvs-Feb-27/diff_ignore freeciv-cvs-Feb-27/ai/Makefile.am 
freeciv-cvs-Feb-27-paratroop/ai/Makefile.am
--- freeciv-cvs-Feb-27/ai/Makefile.am   2003-09-22 07:00:04.000000000 +0200
+++ freeciv-cvs-Feb-27-paratroop/ai/Makefile.am 2004-03-18 01:07:19.000000000 
+0100
@@ -25,6 +25,8 @@
                aihand.h        \
                ailog.c         \
                ailog.h         \
+               aiparatrooper.c \
+               aiparatrooper.h \
                aitech.c        \
                aitech.h        \
                aitools.c       \

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