[freeciv-ai] Re: (PR#4349) New tax code
[Top] [All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
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));
}
/**************************************************************************
|
|