Complete.Org: Mailing Lists: Archives: freeciv-dev: June 2003:
[Freeciv-Dev] (PR#4349) New tax code
Home

[Freeciv-Dev] (PR#4349) New tax code

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
To: undisclosed-recipients: ;
Subject: [Freeciv-Dev] (PR#4349) New tax code
From: "Per I. Mathisen" <per@xxxxxxxxxxx>
Date: Mon, 2 Jun 2003 09:51:34 -0700
Reply-to: rt@xxxxxxxxxxxxxx

This is the rewrite of the tax code done in the previously posted
CM-in-server patch, split out and tested separately. It does seem to work.
In short games, the AI does not seem to miss the destroyed functionality.
I have not tested longer games, I predict it might find it hard to keep
Republic or Democracy alive for long, since current AI city management
routines are very poor at keeping dissent at bay at any cost.

Some ideas on how the AI should be thinking about luxury tax settings
appreciated (and I am not thinking about rapture here, we'll get to that
later).

The calls to rearrange workers were removed, and the fixes I had in the CM
patch that fixed cases where insane cities were created were removed also,
so the result might be insane cities for longer periods of time than
normal. I guess I should audit that.

Speed. It is only marginally faster, despite the volume of removed code. I
guess this is due to this code not being called very often (once per
turn). From 0m48.800s to 0m0.110s.

The usual AI performance table (turns to republic):
                     1  2  3  4  5
Old code, cheat     49 70 61 51 60
New tax, cheat      49 66 64 53 61
New tax, no cheat   71 76 70 77 71

I decided to add the cheat back in... For now.

Also cities in turn 90:
                     1  2  3  4  5
Old code            41 39 37 48 40
New code            43 44 41 47 44

  - Per

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 30 May 2003 18:50:59 -0000      1.140
+++ ai/aicity.c 2 Jun 2003 16:27:40 -0000
@@ -55,6 +55,7 @@
 
 #include "aicity.h"
 
+static void resolve_city_emergency(struct player *pplayer, struct city *pcity);
 static void ai_manage_city(struct player *pplayer, struct city *pcity);
 
 /**************************************************************************
@@ -509,6 +510,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,9 +901,9 @@
   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];
 
@@ -934,9 +939,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, "%s resolved", report);
     goto cleanup;
   }
 
@@ -955,11 +960,10 @@
     }
   } 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);
-  } else {
+  if (CITY_EMERGENCY(pcity)) {
     freelog(LOG_EMERGENCY, "%s remains unresolved", report);
+  } else {
+    freelog(LOG_EMERGENCY, "%s resolved by disbanding unit(s)", report);
   }
 
   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 21 Dec 2002 11:44:00 -0000      1.18
+++ ai/aicity.h 2 Jun 2003 16:27:40 -0000
@@ -15,6 +15,10 @@
 
 #include "unit.h"              /* enum unit_move_type */
 
+#define CITY_EMERGENCY(pcity)                        \
+ (pcity->shield_surplus < 0 || city_unhappy(pcity)   \
+  || pcity->food_stock + pcity->food_surplus < 0)    \
+
 struct player;
 struct city;
 struct ai_choice;
@@ -31,7 +35,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 29 May 2003 13:44:38 -0000      1.16
+++ ai/aidata.c 2 Jun 2003 16:27:40 -0000
@@ -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 = 1;
+    ai->science_priority = TRADE_WEIGHTING;
+  } else {
+    ai->luxury_priority = TRADE_WEIGHTING;
+    ai->science_priority = 1;
+  }
   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.82
diff -u -r1.82 aihand.c
--- ai/aihand.c 15 May 2003 16:02:00 -0000      1.82
+++ ai/aihand.c 2 Jun 2003 16:27:41 -0000
@@ -77,232 +77,57 @@
 }
 
 /**************************************************************************
-.. Set tax/science/luxury rates. Tax Rates > 40 indicates a crisis.
- total rewrite by Syela 
+  Set tax/science/luxury rates.
+
+  TODO: Audit the use of pplayer->ai.maxbuycost in the code elsewhere,
+  then add support for it here.
+
+  TODO: Add support for rapture, needs to be coordinated for entire
+  empire.
 **************************************************************************/
 static void ai_manage_taxes(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;
+  int trade = 0, expense = 0;
+  int maxrate = 100; /* AI cheat. FIXME: Remove */
 
-  if (ai_handicap(pplayer, H_RATES))
-    maxrate = get_government_max_rate(pplayer->government) / 10;
+  if (ai_handicap(pplayer, H_RATES)) {
+    maxrate = get_government_max_rate(pplayer->government);
+  }
 
-  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);
+  city_list_iterate(pplayer->cities, 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;
-
+  } 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;
-
-  city_list_iterate(pplayer->cities, pcity) {
-
-    /* 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 */
-
-    /* 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;
-      } else {
-        while (i <= pcity->size) {
-          waste[i++] = tot;
-        }
-        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;
+    pplayer->economic.tax = maxrate;
+    pplayer->economic.luxury = MIN(100 - pplayer->economic.tax, maxrate);
+    pplayer->economic.science = 100 - pplayer->economic.tax
+                                - pplayer->economic.luxury;
+  } else {
+    if (pplayer->economic.gold >= ai_gold_reserve(pplayer)) {
+      pplayer->economic.science = maxrate; /* Max research */
+    } else {
+      pplayer->economic.science = maxrate / 2; /* Refill tresury */
+    }
+    pplayer->economic.tax = MIN(100 - pplayer->economic.science, maxrate);
+    pplayer->economic.luxury = 100 - pplayer->economic.tax
+                                - pplayer->economic.science;
+    /* Now adjust to get enough money to pay for expenses */
+    while (expense > (trade * pplayer->economic.tax / 100)
+           && pplayer->economic.science > 10
+           && pplayer->economic.tax < maxrate) {
+      pplayer->economic.tax += 10;
+      pplayer->economic.science -= 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_DEBUG, "%s rates: science%d luxury%d tax%d expenses%d income%d",
+          pplayer->name, pplayer->economic.science,
+          pplayer->economic.luxury, pplayer->economic.tax,
+          expense, trade / 100 * pplayer->economic.tax);
 }
 
 /**************************************************************************

[Prev in Thread] Current Thread [Next in Thread]
  • [Freeciv-Dev] (PR#4349) New tax code, Per I. Mathisen <=