[Freeciv-Dev] Re: (PR#15249) Aggressive AI Could Fight Itself to Obsolen
[Top] [All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
<URL: http://bugs.freeciv.org/Ticket/Display.html?id=15249 >
Here is a patch. I have extracted this patch from my reworking of the
wants code (PR#14923). This patch should cause the AI to be less stupid
when it has extreme tax needs. It uses negative feedback to correct the
tax rate.
diff -ruN -Xvendor.freeciv.current/diff_ignore
vendor.freeciv.current/ai/aihand.c freeciv.PR15249/ai/aihand.c
--- vendor.freeciv.current/ai/aihand.c 2005-12-19 22:41:47.000000000 +0000
+++ freeciv.PR15249/ai/aihand.c 2006-03-17 18:45:57.000000000 +0000
@@ -83,6 +83,81 @@
}
}
+/*
+ * Over how many turns to try and smooth out changes in the gold reserves.
+ * WAG
+ */
+#define T_RESERVE_SMOOTH 4
+
+/**************************************************************************
+ How much tax should we raise this turn?
+ This may be negative, indicating we may diminish our reserves instead of
+ collecting tax.
+
+ This uses several WAGS to guess a good value.
+**************************************************************************/
+static int ai_min_income(struct player *pplayer,
+ int trade,
+ int expenses)
+{
+ const struct ai_data *ai = ai_data_get(pplayer);
+ const int n_cities = city_list_size(pplayer->cities);
+ const int reserve = ai_gold_reserve(pplayer);
+
+ /* The fraction of our income to divert to purchases,
+ * as a percentage.
+ */
+ int f;
+
+ int purchases, income;
+
+ assert(pplayer);
+ assert(0 <= expenses);
+
+ f = 5; /* minimum */
+ if (ai_wants_no_science(pplayer)) {
+ /* Instead of science research, we should purchase things. */
+ f += 20;
+ }
+ if (ai_on_war_footing(pplayer)) {
+ /* We should spend income on attack units */
+ f += 35;
+ }
+ if (n_cities / 8 < ai->stats.units.upgradeable) {
+ /* We should spend cash on upgrading units */
+ f += 10;
+ }
+
+ if (0 < trade) {
+ /* If our reserves are low or expenses are high,
+ * we should reduce our purchases.
+ */
+ const int f2 = 100 * expenses / trade;
+ const int f3 = 100 * (reserve - pplayer->economic.gold) / trade;
+
+ f -= MIN(f2 / 3, f); /* WAG */
+ if (0 < f3) {
+ f -= MIN(f3 / 4, f); /* WAG */
+ }
+ }
+
+ f = MIN(f, 100);
+ assert(0 <= f && f <= 100);
+
+ /* How much of our resources should we spend on purchases this turn? */
+ purchases = f * trade / 100;
+
+ /* Use simple feedback to ensure that our taxation will roughly balance
+ * our expenditure, even if our estimation has been inaccurate:
+ * if we raise more tax than we need, pplayer->economic.gold will grow
+ * until it exceeds (purchases + reserve), which will than cause
+ * us to reduce our taxation.
+ */
+ income = expenses + (purchases + reserve - pplayer->economic.gold)
+ / T_RESERVE_SMOOTH;
+ return income;
+}
+
/**************************************************************************
Set tax/science/luxury rates.
@@ -90,18 +165,31 @@
all cities are content and the trade output (minus what is consumed by
luxuries) is maximal. For this we need some more information from the
city management code.
-
- TODO: Audit the use of pplayer->ai.maxbuycost in the code elsewhere,
- then add support for it here.
**************************************************************************/
static void ai_manage_taxes(struct player *pplayer)
{
- int maxrate = (ai_handicap(pplayer, H_RATES)
- ? get_player_bonus(pplayer, EFT_MAX_RATES) : 100);
+ const bool no_science = ai_wants_no_science(pplayer);
+ /* Should we celebrate? */
+ /* TODO: In the future, we should check if we should
+ * celebrate for other reasons than growth. Currently
+ * this is ignored. Maybe we need ruleset AI hints. */
+ /* TODO: Allow celebrate individual cities? No modpacks use this yet. */
+ const bool try_celebrate = get_player_bonus(pplayer, EFT_RAPTURE_GROW) > 0
+ && !ai_handicap(pplayer, H_AWAY);
+ const int maxrate = (ai_handicap(pplayer, H_RATES)
+ ? get_player_bonus(pplayer, EFT_MAX_RATES) : 100);
+ const int rate2 = MIN(maxrate, 100 - maxrate);
+ const int rate3 = (100 - maxrate - rate2); /* Spillover, often 0 */
+
bool celebrate = TRUE;
int can_celebrate = 0, total_cities = 0;
int trade = 0; /* total amount of trade generated */
int expenses = 0; /* total amount of gold upkeep */
+ int min_income = 0;
+
+ assert(maxrate + rate2 + rate3 == 100);
+ assert(rate2 <= maxrate);
+ assert(rate3 <= rate2);
if (!game.info.changable_tax) {
return; /* This ruleset does not support changing tax rates. */
@@ -117,15 +205,32 @@
expenses += pcity->usage[O_GOLD];
} city_list_iterate_end;
- /* Find minimum tax rate which gives us a positive balance. We assume
- * that we want science most and luxuries least here, and reverse or
- * modify this assumption later. on */
+ min_income = ai_min_income(pplayer, trade, expenses);
+
+ /* Find minimum tax rate which gives us the required net income. */
/* First set tax to the minimal available number */
- pplayer->economic.science = maxrate; /* Assume we want science here */
- pplayer->economic.tax = MAX(0, 100 - maxrate * 2); /* If maxrate < 50% */
- pplayer->economic.luxury = (100 - pplayer->economic.science
- - pplayer->economic.tax); /* Spillover */
+ if (no_science && try_celebrate) {
+ /* Science, rather than taxes, should be the minimum */
+ pplayer->economic.luxury = maxrate;
+ pplayer->economic.tax = rate2;
+ pplayer->economic.science = rate3;
+ } else if (no_science) {
+ /* Science and luxuries are not worthwhile, so no real choice here. */
+ pplayer->economic.tax = maxrate;
+ pplayer->economic.luxury = rate2;
+ pplayer->economic.science = rate3;
+ } else if (try_celebrate) {
+ /* Assume we want science most */
+ pplayer->economic.science = maxrate;
+ pplayer->economic.luxury = rate2;
+ pplayer->economic.tax = rate3;
+ } else {
+ /* Assume we want science most and that luxuries are worthless. */
+ pplayer->economic.science = maxrate;
+ pplayer->economic.tax = rate2;
+ pplayer->economic.luxury = rate3;
+ }
/* Now find the minimum tax with positive balance */
while(pplayer->economic.tax < maxrate
@@ -142,7 +247,8 @@
rates[TAX] = 100 - rates[SCIENCE] - rates[LUXURY];
distribute(trade, 3, rates, result);
- if (expenses - result[TAX] > 0) {
+ if (result[TAX] < min_income) {
+ /* Try a higher tax rate */
pplayer->economic.tax += 10;
if (pplayer->economic.luxury > 0) {
pplayer->economic.luxury -= 10;
@@ -151,27 +257,12 @@
}
} else {
/* Ok, got positive balance */
- if (pplayer->economic.gold < ai_gold_reserve(pplayer)) {
- /* Need to refill coffers, increase tax a bit */
- pplayer->economic.tax += 10;
- if (pplayer->economic.luxury > 0) {
- pplayer->economic.luxury -= 10;
- } else {
- pplayer->economic.science -= 10;
- }
- }
/* Done! Break the while loop */
break;
}
}
- /* Should we celebrate? */
- /* TODO: In the future, we should check if we should
- * celebrate for other reasons than growth. Currently
- * this is ignored. Maybe we need ruleset AI hints. */
- /* TODO: Allow celebrate individual cities? No modpacks use this yet. */
- if (get_player_bonus(pplayer, EFT_RAPTURE_GROW) > 0
- && !ai_handicap(pplayer, H_AWAY)) {
+ if (try_celebrate) {
int luxrate = pplayer->economic.luxury;
int scirate = pplayer->economic.science;
struct cm_parameter cmp;
@@ -240,16 +331,6 @@
/* TODO: Add general luxury code here. */
}
- /* Ok, we now have the desired tax and luxury rates. Do we really want
- * science? If not, swap it with tax if it is bigger. */
- if ((ai_wants_no_science(pplayer) || ai_on_war_footing(pplayer))
- && pplayer->economic.science > pplayer->economic.tax) {
- int science = pplayer->economic.science;
- /* Swap science and tax */
- pplayer->economic.science = pplayer->economic.tax;
- pplayer->economic.tax = science;
- }
-
assert(pplayer->economic.tax + pplayer->economic.luxury
+ pplayer->economic.science == 100);
freelog(LOGLEVEL_TAX, "%s rates: Sci=%d Lux=%d Tax=%d trade=%d expenses=%d"
diff -ruN -Xvendor.freeciv.current/diff_ignore
vendor.freeciv.current/ai/aitools.c freeciv.PR15249/ai/aitools.c
--- vendor.freeciv.current/ai/aitools.c 2006-01-22 20:34:17.000000000 +0000
+++ freeciv.PR15249/ai/aitools.c 2006-03-17 18:45:57.000000000 +0000
@@ -1106,15 +1106,55 @@
}
/**************************************************************************
- Credits the AI wants to have in reserves. We need some gold to bribe
- and incite cities.
+ How large a gold reserve should we try to maintain, on average?
+ This is the amount of gold we should usually aim to have after all
+ expenditures this turn. We may have more or less, but we should try
+ not to do so.
- "I still don't trust this function" -- Syela
+ This uses several WAGS to guess a good value.
**************************************************************************/
int ai_gold_reserve(struct player *pplayer)
{
- int i = total_player_citizens(pplayer)*2;
- return MAX(pplayer->ai.maxbuycost, i);
+ const struct ai_data *ai = ai_data_get(pplayer);
+ const int n_cities = city_list_size(pplayer->cities);
+
+ /* Number of turns of income we should hold in reserve,
+ * multiplied by 100.
+ */
+ int t_reserve;
+
+ int expenses = 0;
+ int reserve;
+
+ assert(pplayer);
+
+ /* Find total gold expenses */
+ city_list_iterate(pplayer->cities, pcity) {
+ expenses += pcity->usage[O_GOLD];
+ } city_list_iterate_end;
+
+ t_reserve = 300; /* minimum */
+ if (ai_wants_no_science(pplayer)) {
+ /* Instead of science research, we should build up a cash reserve */
+ t_reserve += 300;
+ }
+ if (n_cities / 8 < ai->stats.units.upgradeable) {
+ /* We should save cash to spend on emergency upgrades of units. */
+ t_reserve += 20;
+ }
+ assert(0 < t_reserve);
+
+ reserve = expenses * t_reserve / 100;
+
+ /* Ensure protection against extra upkeep for new city improvements,
+ * even if we currently have no expenses.
+ */
+ reserve = MAX(reserve, n_cities / 8);
+
+ /* Ensure we always have something in reserve */
+ reserve = MAX(reserve, 5);
+
+ return reserve;
}
/**************************************************************************
- [Freeciv-Dev] Re: (PR#15249) Aggressive AI Could Fight Itself to Obsolence,
Benedict Adamson <=
|
|