Complete.Org: Mailing Lists: Archives: freeciv-dev: March 2000:
[Freeciv-Dev] A stab at implementing a trade advisor
Home

[Freeciv-Dev] A stab at implementing a trade advisor

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
To: freeciv-dev@xxxxxxxxxxx
Subject: [Freeciv-Dev] A stab at implementing a trade advisor
From: Matt Lowry <mclowry@xxxxxxxxxxxxxxxxxx>
Date: Wed, 8 Mar 2000 22:13:26 +1030 (CST)

Hello everybody.
I'm not sure why, but I was in the mood to delve into the FreeCiv source
and I turned my attention to the AI code. I realised there was a really
very simple way of getting trade/military/etc advisors to make tech goal
suggestions.

My basic idea is to have each advisor have a list of "direct techs" - i.e.
techs that are of direct interest. In the case of the trade advisor it is
those techs that increase trade and allow revenue-increasing city
buildings. These techs are given a want of 100. Then a wee recursive
function propogates these wants back down lines of prerequisition, but
attentuating them. What I mean is that "Banking" gets 100 (coz it's a
direct tech), while the prereqs. of Banking get 50, the prereqs. of those
prereqs. get 25, et cetera. This is all done cumulatively, and then all the
wants normalised. The result is an array giving a want for all techs, which
is saved. Then any call to the advisor to suggest a tech goal simply
searches this pregenerated array for the reachable tech that has the
highest want associated with it. Simple. :)

Infact, it's quite nieve and "static". But anyhoo, it seems to be sensible
(???). My problem is that I haven't nutted out the AI code enough to merge
it in properly. As far as I can tell my advisor gets called once for each
player when the game starts, but never again .... :(

I've reached the point where someone who actually know whats they're doing
has to have a look. I've attached a diff against a CVS checkout from ....
urmmm ... sometime this morning I think but that shouldn't matter. The two
changed files are advtrade.c and aitech.c.

Enjoy!
------------------------------------------------
 Matt Lowry      ( mclowry@xxxxxxxxxxxxxxxxxx )
------------------------------------------------
A social life ?
Where can I download that from ?
------------------------------------------------

--- advtrade.c.orig     Wed Mar  8 08:16:47 2000
+++ advtrade.c  Wed Mar  8 20:53:21 2000
@@ -11,10 +11,144 @@
    GNU General Public License for more details.
 ***********************************************************************/
 
-#include "aitools.h"
+#include <string.h>
+
+#include "city.h"
+#include "log.h"
+#include "player.h"
+#include "tech.h"
 
+#include "aitools.h"
 #include "advtrade.h"
 
+
+/********************************************************************** 
+... MAD MATT TRADE ADVISOR CODE BEGINS HERE
+    madmatt_trade_advisor implements a nieve trade advisor
+    (same interface as trade_advisor_choose_tech)
+***********************************************************************/
+
+
+/* direct_techs give the techs (for CivII ruleset) that directly improve the 
trade 
+   of a nation. These are given a want of 100, and then lesser wants are 
propagated 
+   back to the requirements for them. 
+   This means that what an advisor wants is constant for a given tech set, but 
the
+   choice that gets returned will to some extent be modulated by the way a 
game 
+   develops.
+*/
+
+#define NUM_DIRECT_TECHS 5
+char *direct_techs[ NUM_DIRECT_TECHS ] = { 
+  "Banking" , "Currency" , "Economics" , "Railroad" , "Trade" };
+
+
+int need_to_generate = 1;       /* Moderates the once-only code */
+int want_arr[ A_LAST ];         /* Filled in by once-only code */
+int reachable_arr[ A_LAST ];    /* Used on each call to make a choice */
+
+#define BLOODY_BIG_NUMBER 666000000
+
+/* Adds value to the want of tech and recursively adds value/2 to its 
prerequisites.
+   BLOODY_BIG_NUMBER is used as a marker value to prevent infinite looping */
+/* This will get used as a marker value in the propogation algorithm below. */
+
+void want_prop_rec( Tech_Type_id tech , int value ) {
+  if ( tech == A_NONE ) return;
+  if ( want_arr[tech] >= BLOODY_BIG_NUMBER ) return;
+  want_arr[tech] += value + BLOODY_BIG_NUMBER;
+  freelog( LOG_DEBUG , "Adding %d to %s (now %d)" , value , 
advances[tech].name , want_arr[tech] );
+  if ( advances[ tech ].req[0] ) want_prop_rec( advances[ tech ].req[0] , 
value/2 );
+  if ( advances[ tech ].req[1] ) want_prop_rec( advances[ tech ].req[1] , 
value/2 );
+}
+
+
+void madmatt_trade_advisor( struct player *pplayer , struct ai_choice *choice 
) {
+  int i,j;
+  int max_want , max_ind;
+  Tech_Type_id tid;
+
+  freelog( LOG_DEBUG , "MM-TA : Called for player %s." , pplayer->name );
+
+  /* First time this procedure is called it generates its want array, 
subsequent calls just
+     inspect the generated array. */
+  if ( need_to_generate ) {
+    need_to_generate = 0;
+    freelog( LOG_DEBUG , "First call to madmatt_trade_advisor ... generating 
want_arr." );
+
+    /* Use the predefined direct_tech array to generate the want_arr */
+    memset( want_arr , 0 , sizeof( want_arr ) );
+    for ( i=0 ; i<NUM_DIRECT_TECHS ; i++ ) {
+      tid = find_tech_by_name( direct_techs[i] );
+      if ( tech_exists( tid ) ) { 
+       /* Firstly give the direct trade-improving techs a want of 100 (if they 
exist!) */
+       want_arr[ tid ] += 100;
+       freelog( LOG_DEBUG , "Added 100 to %s (now %d)" , advances[tid].name , 
want_arr[tid] );
+       /* Now propagate want values to all the prerequisites of the direct 
tech */
+       if ( advances[ tid ].req[0] ) want_prop_rec( advances[ tid ].req[0] , 
50 );
+       if ( advances[ tid ].req[1] ) want_prop_rec( advances[ tid ].req[1] , 
50 );
+       /* OK - all prerequisites have been visited so get rid of the marker 
flags */
+       for ( j=A_FIRST ; j<A_LAST ; j++ ) {
+         if ( want_arr[j] >= BLOODY_BIG_NUMBER ) want_arr[j] -= 
BLOODY_BIG_NUMBER;
+       }
+      }
+    }
+
+    /* The want_arr has been generated , now normalise the values. */
+    max_want = 0;
+    for ( i=A_FIRST ; i<A_LAST ; i++ ) {
+      if ( want_arr[i] > max_want ) {
+       max_want = want_arr[i];
+      }
+    }
+    for ( i=A_FIRST ; i<A_LAST ; i++ ) {
+      want_arr[i] = ( want_arr[i] * 100 ) / max_want;
+    }
+
+    /* Sanity check */
+    for ( i=A_FIRST ; i<A_LAST ; i++ ) {
+      /* Give all the direct techs 100 (which isn't always the case after 
normalisation). */
+      for ( j=0 ; j<NUM_DIRECT_TECHS ; j++ ) {
+       if ( strcmp( direct_techs[j] , advances[i].name ) == 0 ) {
+         want_arr[i] = 100;
+       }
+      }
+      if ( want_arr[i] > 0 ) {
+       freelog( LOG_DEBUG , "Tech %s is wanted with value %d" , 
advances[i].name , want_arr[i] );
+      }
+    }
+
+  }  /* END IF need to generate */
+
+  /* Generate reachable_arr from want_arr */
+  for ( i=0 ; i<A_LAST ; i++ ) {
+    if ( get_invention( pplayer , i ) == TECH_REACHABLE ) {
+      reachable_arr[i] = want_arr[i];
+    } else {
+      reachable_arr[i] = 0;
+    }
+  }
+  /* Find max reachable want */
+  max_want = 0;
+  for ( i=A_FIRST ; i<A_LAST ; i++ ) {
+    if ( reachable_arr[i] > reachable_arr[max_want] ) {
+      max_want = i;
+    }
+  }
+
+  /* Return it! */
+  freelog( LOG_DEBUG , "MM-TA : Choosing tech %s (wanted %d)" , 
advances[max_want].name ,
+                      reachable_arr[max_want] );
+  choice->choice = max_want;
+  choice->want = reachable_arr[max_want];
+}
+
+
+/********************************************************************** 
+... MAD MATT TRADE ADVISOR CODE ENDS HERE
+***********************************************************************/
+
+
+
 /********************************************************************** 
 ... this function should assign a value to choice and want, where 
     want is a value between 1 and 100.
@@ -24,7 +158,11 @@
 
 void trade_advisor_choose_tech(struct player *pplayer, struct ai_choice 
*choice)
 {
-  choice->choice = A_NONE;
-  choice->want   = 0;
+  madmatt_trade_advisor( pplayer , choice );
+
+  /* choice->choice = A_NONE;
+     choice->want   = 0; */
   /* this function haven't been implemented yet */
 }
+
+
--- aitech.c.orig       Wed Mar  8 20:01:35 2000
+++ aitech.c    Wed Mar  8 21:13:37 2000
@@ -285,6 +285,8 @@
   bestchoice.choice = A_NONE;      
   bestchoice.want   = 0;
 
+  freelog( LOG_DEBUG , "*** : Doing ai_next_tech_goal for %s." , pplayer->name 
);
+
   calculate_tech_turns(pplayer);
   ai_select_tech_goal(pplayer, &curchoice);
   copy_if_better_choice(&curchoice, &bestchoice); /* not dealing with the rest 
*/
@@ -292,9 +294,15 @@
   military_advisor_choose_tech(pplayer, &curchoice);  
   adjust_tech_choice(pplayer, &curchoice, &bestchoice, ADV_MILITARY);
   
-  trade_advisor_choose_tech(pplayer, &curchoice);  
+  freelog( LOG_DEBUG , "*** : Before call to trade advisor bestchoice is %s 
(want %d)." ,
+                      advances[bestchoice.choice].name , bestchoice.want );
+
+  trade_advisor_choose_tech(pplayer, &curchoice);
   adjust_tech_choice(pplayer, &curchoice, &bestchoice, ADV_TRADE);
   
+  freelog( LOG_DEBUG , "*** : After call to trade advisor bestchoice is %s 
(want %d)." ,
+                      advances[bestchoice.choice].name , bestchoice.want );
+
   science_advisor_choose_tech(pplayer, &curchoice);  
   adjust_tech_choice(pplayer, &curchoice, &bestchoice, ADV_SCIENCE);
 
@@ -304,9 +312,14 @@
   attitude_advisor_choose_tech(pplayer, &curchoice);
   adjust_tech_choice(pplayer, &curchoice , &bestchoice, ADV_ATTITUDE);
 
-  if (bestchoice.want == 0) {/* remove when the ai is done */
-    ai_next_tech_goal_default(pplayer, &bestchoice); 
-  }
+  ai_next_tech_goal_default(pplayer, &curchoice); 
+  copy_if_better_choice(&curchoice, &bestchoice); 
+  freelog( LOG_DEBUG , "*** : Default ai has returned %s (want %d)." ,
+                      advances[curchoice.choice].name , curchoice.want );
+
+  freelog( LOG_DEBUG , "*** : At end of ai_next_tech_goal bestchoice is %s 
(want %d)." ,
+                      advances[bestchoice.choice].name , bestchoice.want );
+
   if (bestchoice.want) 
     pplayer->ai.tech_goal = bestchoice.choice;
 }

[Prev in Thread] Current Thread [Next in Thread]
  • [Freeciv-Dev] A stab at implementing a trade advisor, Matt Lowry <=