Complete.Org: Mailing Lists: Archives: freeciv-ai: July 2003:
[freeciv-ai] Re: (PR#4349) New tax code
Home

[freeciv-ai] Re: (PR#4349) New tax code

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
To: per@xxxxxxxxxxx
Subject: [freeciv-ai] Re: (PR#4349) New tax code
From: "Gregory Berkolaiko" <Gregory.Berkolaiko@xxxxxxxxxxxx>
Date: Sat, 12 Jul 2003 11:41:39 -0700
Reply-to: rt@xxxxxxxxxxxxxx

Here is my version of the tax code.  It's simple and it works.  I don't 
trust maxbuycost to give sensible values, so it's effect is minimal.  When 
we have a genuine emergency triggered variable, we can use it.

I think it can be committed.

G.

? ai/aisettler.c
? ai/aisettler.h
? ai/aiunit.cy
? common/aicore/citymap.c
? common/aicore/citymap.h
Index: ai/aicity.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/aicity.c,v
retrieving revision 1.140
diff -u -r1.140 aicity.c
--- ai/aicity.c 2003/05/30 18:50:59     1.140
+++ ai/aicity.c 2003/07/12 18:34:36
@@ -55,6 +55,11 @@
 
 #include "aicity.h"
 
+#define CITY_EMERGENCY(pcity)                        \
+ (pcity->shield_surplus < 0 || city_unhappy(pcity)   \
+  || pcity->food_stock + pcity->food_surplus < 0)    \
+
+static void resolve_city_emergency(struct player *pplayer, struct city *pcity);
 static void ai_manage_city(struct player *pplayer, struct city *pcity);
 
 /**************************************************************************
@@ -509,6 +514,10 @@
   pplayer->ai.maxbuycost = 0;
 
   city_list_iterate(pplayer->cities, pcity)
+    if (CITY_EMERGENCY(pcity)) {
+      /* Fix critical shortages or unhappiness */
+      resolve_city_emergency(pplayer, pcity);
+    }
     ai_manage_city(pplayer, pcity);
   city_list_iterate_end;
 
@@ -896,17 +905,16 @@
   Syela is wrong. It happens quite too often, mostly due to unhappiness.
   Also, most of the time we are unable to resolve the situation. 
 **************************************************************************/
-void emergency_reallocate_workers(struct player *pplayer, struct city *pcity)
+static void resolve_city_emergency(struct player *pplayer, struct city *pcity)
 #define LOG_EMERGENCY LOG_DEBUG
-{ 
+{
   struct city_list minilist;
-  char report[500];
 
-  my_snprintf(report, sizeof(report),
-              "Emergency in %s (%s, angry%d, unhap%d food%d, prod%d)",
-              pcity->name, city_unhappy(pcity) ? "unhappy" : "content",
-              pcity->ppl_angry[4], pcity->ppl_unhappy[4],
-              pcity->food_surplus, pcity->shield_surplus);
+  freelog(LOG_EMERGENCY,
+          "Emergency in %s (%s, angry%d, unhap%d food%d, prod%d)",
+          pcity->name, city_unhappy(pcity) ? "unhappy" : "content",
+          pcity->ppl_angry[4], pcity->ppl_unhappy[4],
+          pcity->food_surplus, pcity->shield_surplus);
 
   city_list_init(&minilist);
   map_city_radius_iterate(pcity->x, pcity->y, x, y) {
@@ -934,9 +942,9 @@
   if (ai_fix_unhappy(pcity) && ai_fuzzy(pplayer, TRUE)) {
     ai_scientists_taxmen(pcity);
   }
-  if (pcity->shield_surplus >= 0 && !city_unhappy(pcity)
-      && pcity->food_stock + pcity->food_surplus >= 0) {
-    freelog(LOG_EMERGENCY, "%s resolved without disbanding", report);
+
+  if (!CITY_EMERGENCY(pcity)) {
+    freelog(LOG_EMERGENCY, "Emergency in %s resolved", pcity->name);
     goto cleanup;
   }
 
@@ -955,11 +963,12 @@
     }
   } unit_list_iterate_end;
 
-  if (pcity->shield_surplus >= 0 && !city_unhappy(pcity)
-      && pcity->food_stock + pcity->food_surplus >= 0) {
-    freelog(LOG_EMERGENCY, "%s resolved by disbanding unit(s)", report);
+  if (CITY_EMERGENCY(pcity)) {
+    freelog(LOG_EMERGENCY, "Emergency in %s remains unresolved", 
+            pcity->name);
   } else {
-    freelog(LOG_EMERGENCY, "%s remains unresolved", report);
+    freelog(LOG_EMERGENCY, 
+            "Emergency in %s resolved by disbanding unit(s)", pcity->name);
   }
 
   cleanup:
Index: ai/aicity.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/aicity.h,v
retrieving revision 1.18
diff -u -r1.18 aicity.h
--- ai/aicity.h 2002/12/21 11:44:00     1.18
+++ ai/aicity.h 2003/07/12 18:34:36
@@ -31,7 +31,6 @@
 int ai_make_elvis(struct city *pcity);
 void ai_scientists_taxmen(struct city *pcity);
 bool ai_fix_unhappy(struct city *pcity);
-void emergency_reallocate_workers(struct player *pplayer, struct city *pcity);
 
 enum ai_city_task { AICITY_NONE, AICITY_TECH, AICITY_TAX, AICITY_PROD};
 /* These are not used (well, except AICITY_NONE)  --dwp */
Index: ai/aidata.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/aidata.c,v
retrieving revision 1.16
diff -u -r1.16 aidata.c
--- ai/aidata.c 2003/05/29 13:44:38     1.16
+++ ai/aidata.c 2003/07/12 18:34:36
@@ -253,8 +253,13 @@
    * are all WAGs. */
   ai->food_priority = FOOD_WEIGHTING;
   ai->shield_priority = SHIELD_WEIGHTING;
-  ai->luxury_priority = 1;
-  ai->science_priority = TRADE_WEIGHTING;
+  if (ai_wants_no_science(pplayer)) {
+    ai->luxury_priority = TRADE_WEIGHTING;
+    ai->science_priority = 1;
+  } else {
+    ai->luxury_priority = 1;
+    ai->science_priority = TRADE_WEIGHTING;
+  }
   ai->gold_priority = TRADE_WEIGHTING;
   ai->happy_priority = 1;
   ai->unhappy_priority = TRADE_WEIGHTING; /* danger */
Index: ai/aihand.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/aihand.c,v
retrieving revision 1.83
diff -u -r1.83 aihand.c
--- ai/aihand.c 2003/06/30 20:53:24     1.83
+++ ai/aihand.c 2003/07/12 18:34:36
@@ -77,232 +77,86 @@
 }
 
 /**************************************************************************
-.. Set tax/science/luxury rates. Tax Rates > 40 indicates a crisis.
- total rewrite by Syela 
+  Refresh all cities of the given player.  This function is only used by 
+  AI so we keep it here. 
+
+  Do not send_unit_info because it causes client to blink.
 **************************************************************************/
-static void ai_manage_taxes(struct player *pplayer) 
+static void ai_player_cities_refresh(struct player *pplayer)
 {
-  struct government *g = get_gov_pplayer(pplayer);
-  int gnow = pplayer->economic.gold;
-  int trade = 0, m, n, i, expense = 0, tot;
-  int waste[40]; /* waste with N elvises */
-  int elvises[11] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
-  int hhjj[11] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
-  int cities = 0;
-  struct packet_unit_request pack;
-  struct city *incity; /* stay a while, until the night is over */
-  struct unit *defender;
-  int maxrate = 10;
+  city_list_iterate(pplayer->cities, pcity) {
+    generic_city_refresh(pcity, TRUE, NULL);
+  } city_list_iterate_end;
+}
+
+/**************************************************************************
+  Set tax/science/luxury rates.
+
+  TODO: Add support for luxuries: select the luxury rate at which all 
+  cities are content and the trade output (minus what is consumed by 
+  luxuries) is maximal.
 
-  if (ai_handicap(pplayer, H_RATES))
-    maxrate = get_government_max_rate(pplayer->government) / 10;
+  TODO: Audit the use of pplayer->ai.maxbuycost in the code elsewhere,
+  then add support for it here.
 
-  pplayer->economic.science += pplayer->economic.luxury;
-/* without the above line, auto_arrange does strange things we must avoid -- 
Syela */
-  pplayer->economic.luxury = 0;
-  city_list_iterate(pplayer->cities, pcity) 
-    cities++;
-    pcity->ppl_elvis = 0; pcity->ppl_taxman = 0; pcity->ppl_scientist = 0;
-    add_adjust_workers(pcity); /* less wasteful than auto_arrange, required */
-    city_refresh(pcity);
-    trade += pcity->trade_prod * city_tax_bonus(pcity) / 100;
-    freelog(LOG_DEBUG, "%s has %d trade.", pcity->name, pcity->trade_prod);
-    built_impr_iterate(pcity, id) {
-      expense += improvement_upkeep(pcity, id);
-    } built_impr_iterate_end;
-
-  city_list_iterate_end;
-
-  pplayer->ai.est_upkeep = expense;
-
-  if (trade == 0) { /* can't return right away - thanks for the evidence, Muzz 
*/
-    city_list_iterate(pplayer->cities, pcity) 
-      if (ai_fix_unhappy(pcity) && ai_fuzzy(pplayer, TRUE))
-        ai_scientists_taxmen(pcity);
-    city_list_iterate_end;
-    return; /* damn division by zero! */
-  }
-
-  pplayer->economic.luxury = 0;
+  TODO: Add support for rapture, needs to be coordinated for entire
+  empire.
+**************************************************************************/
+static void ai_manage_taxes(struct player *pplayer) 
+{
+  int maxrate = (ai_handicap(pplayer, H_RATES) 
+                 ? get_government_max_rate(pplayer->government) : 100);
 
-  city_list_iterate(pplayer->cities, pcity) {
+  /* Otherwise stupid problems arise */
+  assert(maxrate >= 50);
 
-    /* this code must be ABOVE the elvises[] if SIMPLISTIC is off */
-    freelog(LOG_DEBUG, "Does %s want to be bigger? %d",
-                 pcity->name, wants_to_be_bigger(pcity));
-    if (government_has_flag(g, G_RAPTURE_CITY_GROWTH)
-       && pcity->size >= g->rapture_size && pcity->food_surplus > 0
-       && pcity->ppl_unhappy[4] == 0 && pcity->ppl_angry[4] == 0
-       && wants_to_be_bigger(pcity) && ai_fuzzy(pplayer, TRUE)) {
-      freelog(LOG_DEBUG, "%d happy people in %s",
-                   pcity->ppl_happy[4], pcity->name);
-      n = ((pcity->size/2) - pcity->ppl_happy[4]) * 20;
-      if (n > pcity->ppl_content[1] * 20) n += (n - pcity->ppl_content[1] * 
20);
-      m = ((((city_got_effect(pcity, B_GRANARY) ? 3 : 2) *
-            city_granary_size(pcity->size))/2) -
-           pcity->food_stock) * food_weighting(pcity->size);
-      freelog(LOG_DEBUG, "Checking HHJJ for %s, m = %d", pcity->name, m);
-      tot = 0;
-      for (i = 0; i <= 10; i++) {
-        if (pcity->trade_prod * i * city_tax_bonus(pcity) >= n * 100) {
-         if (tot == 0) freelog(LOG_DEBUG, "%s celebrates at %d.",
-                           pcity->name, i * 10);
-          hhjj[i] += (pcity->was_happy ? m : m/2);
-          tot++;
-        }
-      }
-    } /* hhjj[i] is (we think) the desirability of partying with lux = 10 * i 
*/
-/* end elevated code block */
+  /* Add proper support for luxury here */
+  pplayer->economic.luxury = 0;
+  /* After this moment don't touch luxury, it's optimal! */
 
-    /* need this much lux */
-    n = (2 * pcity->ppl_angry[4] + pcity->ppl_unhappy[4] -
-        pcity->ppl_happy[4]) * 20;
-
-/* this could be an unholy CPU glutton; it's only really useful when we need
-   lots of luxury, like with pcity->size = 12 and only a temple */
-
-    memset(waste, 0, sizeof(waste));
-    tot = pcity->food_prod * food_weighting(pcity->size) +
-            pcity->trade_prod * pcity->ai.trade_want +
-            pcity->shield_prod * SHIELD_WEIGHTING;
-
-    for (i = 1; i <= pcity->size; i++) {
-      m = ai_make_elvis(pcity);
-      if (m != 0) {
-        waste[i] = waste[i-1] + m;
+  if (ai_wants_no_science(pplayer)) {
+    /* Maximum tax, leftovers into science */
+    pplayer->economic.tax = MIN(maxrate, 100 - pplayer->economic.luxury);
+    pplayer->economic.science = (100 - pplayer->economic.tax
+                                 - pplayer->economic.luxury);
+    ai_player_cities_refresh(pplayer);
+  } else {
+    /* Set tax to the bare minimum which allows positive balance */
+
+    /* First set tax to the minimal available number */
+    pplayer->economic.science = MIN(maxrate, 100 - pplayer->economic.luxury);
+    pplayer->economic.tax = (100 - pplayer->economic.science
+                             - pplayer->economic.luxury);
+    ai_player_cities_refresh(pplayer);
+
+    /* Now find the minimum tax with positive balance */
+    while(pplayer->economic.tax < maxrate 
+          && pplayer->economic.science > 10) {
+
+      if (player_get_expected_income(pplayer) < 0) {
+        pplayer->economic.tax += 10;
+        pplayer->economic.science -= 10;
+        ai_player_cities_refresh(pplayer);
       } else {
-        while (i <= pcity->size) {
-          waste[i++] = tot;
+        /* Ok, got positive balance */
+        if (pplayer->economic.gold < ai_gold_reserve(pplayer)) {
+          /* Need to refill coffers, increase tax a bit */
+          pplayer->economic.tax += 10;
+          pplayer->economic.science -= 10;
+          ai_player_cities_refresh(pplayer);
         }
+        /* Done! Break the while loop */
         break;
       }
-    }
-    for (i = 0; i <= 10; i++) {
-      m = ((n * 100 - pcity->trade_prod * city_tax_bonus(pcity) * i + 1999) / 
2000);
-      if (m >= 0) elvises[i] += waste[m];
-    }
-  }
-  city_list_iterate_end;
-    
-  for (i = 0; i <= 10; i++) elvises[i] += (trade * i) / 10 * TRADE_WEIGHTING;
-  /* elvises[i] is the production + income lost to elvises with lux = i * 10 */
-  n = 0; /* default to 0 lux */
-  for (i = 1; i <= maxrate; i++) if (elvises[i] < elvises[n]) n = i;
-  /* two thousand zero zero party over it's out of time */
-  for (i = 0; i <= 10; i++) {
-    hhjj[i] -= (trade * i) / 10 * TRADE_WEIGHTING; /* hhjj is now our bonus */
-    freelog(LOG_DEBUG, "hhjj[%d] = %d for %s.", i, hhjj[i], pplayer->name);
-  }
 
-  m = n; /* storing the lux we really need */
-  pplayer->economic.luxury = n * 10; /* temporary */
-
-/* Less-intelligent previous versions of the follow equation purged. -- Syela 
*/
-  n = ((expense - gnow + cities + pplayer->ai.maxbuycost) * 10 + trade - 1) / 
trade;
-  if (n < 0) n = 0;
-  while (n > maxrate) n--; /* Better to cheat on lux than on tax -- Syela */
-  if (m > 10 - n) m = 10 - n;
-
-  freelog(LOG_DEBUG, "%s has %d trade and %d expense."
-         "  Min lux = %d, tax = %d", pplayer->name, trade, expense, m, n);
-
-/* Peter Schaefer points out (among other things) that in pathological cases
-(like expense == 468) the AI will try to celebrate with m = 10 and then abort 
*/
-
-  /* want to max the hhjj */
-  for (i = m; i <= maxrate && i <= 10 - n; i++)
-    if (hhjj[i] > hhjj[m] && (trade * (10 - i) >= expense * 10)) m = i;
-/* if the lux rate necessary to celebrate cannot be maintained, don't bother */
-  pplayer->economic.luxury = 10 * m;
-
-  if (ai_wants_no_science(pplayer)) {
-    pplayer->economic.tax = 100 - pplayer->economic.luxury;
-    while (pplayer->economic.tax > maxrate * 10) {
-      pplayer->economic.tax -= 10;
-      pplayer->economic.luxury += 10;
     }
-  } else { /* have to balance things logically */
-/* if we need 50 gold and we have trade = 100, need 50 % tax (n = 5) */
-/*  n = ((ai_gold_reserve(pplayer) - gnow - expense) ... I hate typos. -- 
Syela */
-    n = ((ai_gold_reserve(pplayer) - gnow + expense + cities) * 20 + (trade*2) 
- 1) / (trade*2);
-/* same bug here as above, caused us not to afford city walls we needed. -- 
Syela */
-    if (n < 0) n = 0; /* shouldn't allow 0 tax? */
-    while (n > 10 - (pplayer->economic.luxury / 10) || n > maxrate) n--;
-    pplayer->economic.tax = 10 * n;
-  }
 
-/* once we have tech_want established, can compare it to cash want here -- 
Syela */
-  pplayer->economic.science = 100 - pplayer->economic.tax - 
pplayer->economic.luxury;
-  while (pplayer->economic.science > maxrate * 10) {
-    pplayer->economic.tax += 10;
-    pplayer->economic.science -= 10;
   }
-
-  city_list_iterate(pplayer->cities, pcity) 
-    pcity->ppl_elvis = 0;
-    city_refresh(pcity);
-    add_adjust_workers(pcity);
-    city_refresh(pcity);
-    if (ai_fix_unhappy(pcity) && ai_fuzzy(pplayer, TRUE))
-      ai_scientists_taxmen(pcity);
-    if (pcity->shield_surplus < 0 || city_unhappy(pcity) ||
-        pcity->food_stock + pcity->food_surplus < 0) 
-       emergency_reallocate_workers(pplayer, pcity);
-    if (pcity->shield_surplus < 0) {
-      defender = NULL;
-      unit_list_iterate(pcity->units_supported, punit)
-        incity = map_get_city(punit->x, punit->y);
-        if (incity && pcity->shield_surplus < 0) {
-         /* Note that disbanding here is automatically safe (we don't
-          * need to use handle_unit_disband_safe()), because the unit is
-          * in a city, so there are no passengers to get disbanded. --dwp
-          */
-          if (incity == pcity) {
-            if (defender) {
-              if (unit_def_rating_basic(punit) <
-                  unit_def_rating_basic(defender)) {
-               freelog(LOG_VERBOSE, "Disbanding %s in %s",
-                       unit_type(punit)->name, pcity->name);
-                pack.unit_id = punit->id;
-                handle_unit_disband(pplayer, &pack);
-                city_refresh(pcity);
-              } else {
-               freelog(LOG_VERBOSE, "Disbanding %s in %s",
-                       unit_type(defender)->name, pcity->name);
-                pack.unit_id = defender->id;
-                handle_unit_disband(pplayer, &pack);
-                city_refresh(pcity);
-                defender = punit;
-              }
-            } else defender = punit;
-          } else if (incity->shield_surplus > 0) {
-            pack.unit_id = punit->id;
-            pack.city_id = incity->id;
-            handle_unit_change_homecity(pplayer, &pack);
-            city_refresh(pcity);
-           freelog(LOG_VERBOSE, "Reassigning %s from %s to %s",
-                   unit_type(punit)->name, pcity->name, incity->name);
-          }
-        } /* end if */
-      unit_list_iterate_end;
-      if (pcity->shield_surplus < 0) {
-        unit_list_iterate(pcity->units_supported, punit)
-          if (punit != defender && pcity->shield_surplus < 0) {
-           /* the defender MUST NOT be disbanded! -- Syela */
-           freelog(LOG_VERBOSE, "Disbanding %s's %s",
-                   pcity->name, unit_type(punit)->name);
-            pack.unit_id = punit->id;
-            handle_unit_disband_safe(pplayer, &pack, &myiter);
-            city_refresh(pcity);
-          }
-        unit_list_iterate_end;
-      }
-    } /* end if we can't meet payroll */
-    /* FIXME: this shouldn't be here, but in the server... */
-    send_city_info(city_owner(pcity), pcity);
-  city_list_iterate_end;
 
-  sync_cities();
+  freelog(LOG_NORMAL, "%s rates: Sci %d Lux%d Tax %d NetIncome %d",
+          pplayer->name, pplayer->economic.science,
+          pplayer->economic.luxury, pplayer->economic.tax,
+          player_get_expected_income(pplayer));
 }
 
 /**************************************************************************

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