[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

Re: [crimson-list] Improve AI behavior



Le 08/04/2014 18:37, Jens Granseuer a Ãcrit :
On Mo, 2014-04-07 at 19:43 +0200, SÃbastien Dailly wrote:
Jens : do you think that it would be easy to add some tests in the
compilation process ? I think that that the AI is the more important
piece in the code, and I could try to write some test in order to
check regression in future evolution, but I'll need help to write the
frame.


It shouldn't be too hard to add some kind of test harness, but since I
don't have a lot of time to spend on the project at the moment, I won't
be a big help there.


Ok, I'll try to see what I can do. I do not know about the C++ world and existing testing framework, but I think that provide some little situations for the AI and test the expected result is a good way to proceed. It allow to collect all the problems and give some help for improving it.

In the past, we've toyed with the idea of making the AI pluggable, at
least for testing purposes, and having several AIs face off against each
other to see which fared better. I think we did have a working prototype
at one point, but I no longer remember the details (damn, getting old I
am).

I'll try to give your changes a spin soon (I'm curious to see what
happens when the unit in the centre is artillery instead of a tank...)
but once again, no promises...

I didn't though of testing inequal situation, but I did it after I read your mail, and it worked as expected :)


And a tangential note: please generate patches in unified format.
They're much easier to read at a glance (to me anyway).


I've joined the patch made with `cvs diff -u`  which should be the good format now. (for me, it would be easer to ask you to `git pull` a remote branchâ)

--
SÃbastien
Index: src/cf/ai.h
===================================================================
RCS file: /home/cvspsrv/cvsroot/games/crimson/src/cf/ai.h,v
retrieving revision 1.7
diff -u -r1.7 ai.h
--- src/cf/ai.h	20 Jan 2007 10:19:26 -0000	1.7
+++ src/cf/ai.h	9 Apr 2014 20:07:42 -0000
@@ -91,6 +91,7 @@
   Point FollowPath( const Unit *u, const Path &path, unsigned short dist = 0 ) const;
   Point FindBestHex( const Unit *u, const Unit *enemy ) const;
   Unit *FindBestTarget( const Unit *u );
+  int EvaluateSupport( const Unit *attacker, const Point position, const Unit *target) const;
   Transport *FindTransport( const Unit *u, const Point &dest,
              unsigned short dist, bool forreal );
   bool SameDirection( const Point &pos, const Point &dest1, const Point &dest2 ) const;
Index: src/cf/ai.cpp
===================================================================
RCS file: /home/cvspsrv/cvsroot/games/crimson/src/cf/ai.cpp,v
retrieving revision 1.13
diff -u -r1.13 ai.cpp
--- src/cf/ai.cpp	20 Jan 2007 10:19:26 -0000	1.13
+++ src/cf/ai.cpp	9 Apr 2014 20:07:43 -0000
@@ -851,6 +851,7 @@
   if ( u->IsDefensive() ) return NULL;
 
   Path path( map );
+
   for ( Unit *tg = static_cast<Unit *>( mission.GetUnits().Head() );
         tg; tg = static_cast<Unit *>( tg->Next() ) ) {
     if ( (tg->Owner() == &mission.GetOtherPlayer(*player)) && u->CanHitType( tg )
@@ -862,7 +863,7 @@
                                 PATH_FAST, u->WeaponRange( tg ) );
 
         if ( cost >= 0 ) {
-          val = MAX( 0, 10000 - UnitStrength( tg ) - cost * 50 );
+          val = MAX( 0, 10000 - cost * 50);
           if ( !tg->CanHitType( u ) ) val += 10;
 
           if ( tg->IsConquer() ) val += 20;
@@ -870,6 +871,14 @@
           else if ( tg->IsMine() ) val = MAX( 0, val - 40 );
 
           if ( (u->IsSlow() || (u->Type()->Speed() == 0)) && u->CanHit( tg ) ) val += 80;
+
+          if (cost <= 1) {
+            Point position = FindBestHex(u, tg);
+            int support = EvaluateSupport( u, position, tg );
+            val += support;
+          }
+
+
         } else {
           // not yet directly accessible - make that a relatively unlikely target
           val = MAX( 0, 5000 - UnitStrength( tg ) );
@@ -882,6 +891,7 @@
       }
     }
   }
+ 
   return best;
 }
 
@@ -909,9 +919,8 @@
   if ( (turns > 1) || ((u->WeaponRange(enemy) > 1) && (turns >= 0)) )
     hex = FollowPath( u, path );
   else if ( turns >= 0 ) {
-    Unit *sup;
     Point nb[6], hlp;
-    short vals[6], bestval = _CF_BEST_HEX_INVALID;
+    short val, bestval = _CF_BEST_HEX_INVALID;
     int i;
 
     map->GetNeighbors( enemy->Position(), nb );
@@ -919,44 +928,95 @@
       if ( (nb[i].x != -1) && (nb[i].y != -1) && !map->GetUnit( nb[i] ) &&
            ((map->TerrainTypes( nb[i] ) & TT_ENTRANCE) == 0) &&
            (path.Find( u, u->Position(), nb[i], PATH_FAST ) == 1) ) {
-        vals[i] = -Distance( u->Position(), nb[i] );
-      } else vals[i] = _CF_BEST_HEX_INVALID;
+        val = -Distance( u->Position(), nb[i] );
+      } else {
+        continue;
+      }
+
+      int support = EvaluateSupport(u, nb[i], enemy);
+      val += support;
+
+      if ( val > bestval ) {
+        bestval = val;
+        hex = nb[i];
+      }
     }
+  }
 
-    for ( i = NORTH; i <= NORTHWEST; ++i ) {
-      if ( vals[i] != _CF_BEST_HEX_INVALID ) {
-        vals[i] += map->AttackMod( nb[i] );
+  return hex;
+}
+#undef _CF_BEST_HEX_INVALID
 
-        // check for support in the back of the enemy
-        int j = ReverseDir( (Direction)i );
-        if ( (nb[j].x != -1) && (nb[j].y != -1) ) {
-          sup = map->GetUnit( nb[j] );
-          if ( sup && (sup->Owner() == player) ) {
-            if ( sup->CouldHit( enemy ) ) vals[i] += 7;
-            else vals[i] += 2;
-          }
-        }
 
-        // check for enemy units supporting defence
-        Direction attdir = Hex2Dir( nb[i], enemy->Position() );
-        if ( !map->Dir2Hex( nb[i], TurnLeft(attdir), hlp ) &&
-           (sup = map->GetUnit( hlp )) && (sup->Owner() == player) ) vals[i] -= 8;
-        if ( !map->Dir2Hex( nb[i], TurnRight(attdir), hlp ) &&
-           (sup = map->GetUnit( hlp )) && (sup->Owner() == player) ) vals[i] -= 8;
+////////////////////////////////////////////////////////////////////////
+// NAME       : AI::EvaluateSupport
+// DESCRIPTION: Determine the hex from which an attack can be expected
+//              to bear the best result.
+// PARAMETERS : attacker - attacking unit
+//              position - the estimated attacker positon
+//              enemy    - target unit
+// RETURNS    : A value represent a modifier wich can be used as 
+//              modifier for evaluating if the position give bonus or 
+//              malus to the attacker.
+////////////////////////////////////////////////////////////////////////
+
+int AI::EvaluateSupport(const Unit *attacker, const Point position, const Unit *enemy) const {
+
+    Unit *sup;
+    Point neighbors[6], enemyNeighbors[6], hlp;
+    Point enemyPosition = enemy->Position();
+
+    int val = map->AttackMod( enemyPosition );
+
+    map->GetNeighbors( enemyPosition, enemyNeighbors );
+    map->GetNeighbors( position, neighbors );
+
+    Direction attdir = Hex2Dir( enemyPosition, position );
+
+    // check for support in the back of the enemy
+    int j = ReverseDir( static_cast<Direction> (enemy->Facing()) );
+    if ( (enemyNeighbors[j].x != -1) && (enemyNeighbors[j].y != -1) ) {
+      sup = map->GetUnit( enemyNeighbors[j] );
+      if ( sup && (sup->Owner() == enemy->Owner()) ) {
+        if ( sup->CouldHit( enemy ) ) val += 7;
+        else val += 2;
       }
     }
 
-    for ( i = NORTH; i <= NORTHWEST; ++i ) {
-      if ( vals[i] > bestval ) {
-        bestval = vals[i];
-        hex = nb[i];
+    // check for enemy units supporting defence
+    if ( !map->Dir2Hex( enemyPosition, TurnLeft(attdir), hlp ) &&
+       (sup = map->GetUnit( hlp )) && (sup->Owner() == enemy->Owner()) ) {
+          val -= 8;
+    }
+    if ( !map->Dir2Hex( enemyPosition, TurnRight(attdir), hlp ) &&
+       (sup = map->GetUnit( hlp )) && (sup->Owner() == enemy->Owner()) ) {
+          val -= 8;
+    }
+
+    // look for a counter-attack
+    for ( int i = NORTH; i <= NORTHWEST; ++i ) {
+      if ( (neighbors[i].x != -1) && (neighbors[i].y != -1) && 
+        (sup = map->GetUnit( neighbors[i] )) ) {
+        if (sup->Owner() != attacker->Owner()) val -= sup->OffensiveStrength( attacker );
+
       }
     }
-  }
 
-  return hex;
+    // now look for friend arount the target
+    for ( int i = NORTH; i <= NORTHWEST; ++i ) {
+      if ( (enemyNeighbors[i].x != -1) && (enemyNeighbors[i].y != -1) && 
+        (sup = map->GetUnit( enemyNeighbors[i] )) ) {
+        if (sup->Owner() == attacker->Owner()) {
+            val += 10;
+            val += sup->OffensiveStrength( enemy );
+        }
+
+      }
+    }
+
+    return val;
+
 }
-#undef _CF_BEST_HEX_INVALID
 
 ////////////////////////////////////////////////////////////////////////
 // NAME       : AI::FindTransport