[freeciv-ai] (PR#8832) Cleaning ai/aitech.c
[Top] [All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
<URL: http://rt.freeciv.org/Ticket/Display.html?id=8832 >
ai/aitech.c is cleaned, code is shortened, comments added generously
The reason I attacked it was that it hijacked the ai_choice
(build-choice struct). I gave it a personal and tailored ai_tech_choice.
Detected a little problem with it -- some time is spent on computing new
tech goal every turn. Then this info is just neglected, when it comes
to actually act according to the goal -- choose new tech -- the goal is
recomputed. Added commentary to this effect too.
In general I would like to rewrite the way it selects techs and goals to
make it more transparent. But this is in the future.
For now the savegames are identical -- wasted 1 hour trying to achieve this.
G.
? core.3789
? settle4.gz
? settle5.gz
? stuck.gz
? ai/aisettler.c
? ai/aisettler.h
Index: ai/aicity.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/aicity.c,v
retrieving revision 1.153
diff -u -r1.153 aicity.c
--- ai/aicity.c 24 May 2004 02:09:27 -0000 1.153
+++ ai/aicity.c 25 May 2004 04:58:27 -0000
@@ -561,8 +561,6 @@
worker allocations,
build choices,
extra gold spending.
-
- TODO: Treat ai_gov_tech_hints somewhere else
**************************************************************************/
void ai_manage_cities(struct player *pplayer)
{
@@ -599,30 +597,6 @@
} city_list_iterate_end;
ai_spend_gold(pplayer);
-
- /* use ai_gov_tech_hints: */
- for(i=0; i<MAX_NUM_TECH_LIST; i++) {
- struct ai_gov_tech_hint *hint = &ai_gov_tech_hints[i];
-
- if (hint->tech == A_LAST) {
- break;
- }
-
- if (get_invention(pplayer, hint->tech) != TECH_KNOWN) {
- pplayer->ai.tech_want[hint->tech] +=
- city_list_size(&pplayer->cities)
- * (hint->turns_factor
- * num_unknown_techs_for_goal(pplayer, hint->tech)
- + hint->const_factor);
- if (hint->get_first) {
- break;
- }
- } else {
- if (hint->done) {
- break;
- }
- }
- }
}
/**************************************************************************
Index: ai/aitech.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/aitech.c,v
retrieving revision 1.43
diff -u -r1.43 aitech.c
--- ai/aitech.c 14 Feb 2004 02:21:25 -0000 1.43
+++ ai/aitech.c 25 May 2004 04:58:28 -0000
@@ -31,6 +31,13 @@
#include "aitech.h"
+struct ai_tech_choice {
+ Tech_Type_id choice; /* The id of the most needed tech */
+ int want; /* Want of the most needed tech */
+ int current_want; /* Want of the tech which currenlty researched
+ * or is our current goal */
+};
+
/**************************************************************************
Returns tech corresponding to players wonder goal from nations[],
if it makes sense, and wonder is not already built and not obsolete.
@@ -54,10 +61,11 @@
}
/**************************************************************************
- ...
+ Puts into choice the closest (in terms of unknown techs needed) of
+ national tech goals,
+ requirements for the national wonder goal
**************************************************************************/
-static void ai_next_tech_goal_default(struct player *pplayer,
- struct ai_choice *choice)
+static Tech_Type_id ai_next_tech_goal_default(struct player *pplayer)
{
struct nation_type *prace = get_nation_by_plr(pplayer);
int bestdist = A_LAST + 1;
@@ -65,6 +73,7 @@
Tech_Type_id goal = A_UNSET;
Tech_Type_id tech;
+ /* Find the closest of the national tech goals */
for (i = 0 ; i < MAX_NUM_TECH_GOALS; i++) {
Tech_Type_id j = prace->goals.tech[i];
if (!tech_is_available(pplayer, j)
@@ -78,130 +87,175 @@
break; /* remove this to restore old functionality -- Syela */
}
}
+
+ /* Find the requirement for the national wonder */
tech = get_wonder_tech(pplayer);
- if (tech != A_UNSET) {
- dist = num_unknown_techs_for_goal(pplayer, tech);
- if (dist < bestdist) {
-/* bestdist = dist; */ /* useless, reinclude when adding a new if statement
*/
- goal = tech;
- }
- }
- if (goal != A_UNSET) {
- choice->choice = goal;
- choice->want = 1;
+ if (tech != A_UNSET
+ && num_unknown_techs_for_goal(pplayer, tech) < bestdist) {
+ goal = tech;
}
+
+ return goal;
}
/**************************************************************************
- ...
+ Massage the numbers provided to us by ai.tech_want into unrecognizable
+ pulp.
+
+ TODO: Write a transparent formula.
+
+ Notes: 1. num_unknown_techs_for_goal returns 0 for known techs, 1 if tech
+ is immediately available etc.
+ 2. A tech is reachable means we can research it now; tech is available
+ means it's on our tech tree (different nations can have different techs).
+ 3. ai.tech_want is usually upped by each city, so it is divided by number
+ of cities here.
+ 4. A tech isn't a requirement of itself.
**************************************************************************/
-static void ai_select_tech(struct player *pplayer, struct ai_choice *choice,
- struct ai_choice *gol)
+static void ai_select_tech(struct player *pplayer,
+ struct ai_tech_choice *choice,
+ struct ai_tech_choice *goal)
{
- Tech_Type_id k, l;
- int j;
- int num_cities_nonzero;
+ Tech_Type_id newtech, newgoal;
+ int num_cities_nonzero = MAX(1, city_list_size(&pplayer->cities));
int values[A_LAST];
int goal_values[A_LAST];
- if((num_cities_nonzero = city_list_size(&pplayer->cities)) < 1)
- num_cities_nonzero = 1;
memset(values, 0, sizeof(values));
memset(goal_values, 0, sizeof(goal_values));
+
+ /* Fill in values for the techs: want of the tech
+ * + average want of those we will discover en route */
tech_type_iterate(i) {
- j = num_unknown_techs_for_goal(pplayer, i);
- if (j > 0) { /* if we already got it we don't want it */
+ int steps = num_unknown_techs_for_goal(pplayer, i);
+
+ /* We only want it if we haven't got it (so AI is human after all) */
+ if (steps > 0) {
values[i] += pplayer->ai.tech_want[i];
tech_type_iterate(k) {
if (is_tech_a_req_for_goal(pplayer, k, i)) {
- values[k] += pplayer->ai.tech_want[i] / j;
+ values[k] += pplayer->ai.tech_want[i] / steps;
}
} tech_type_iterate_end;
}
} tech_type_iterate_end;
+ /* Fill in the values for the tech goals */
tech_type_iterate(i) {
- if (num_unknown_techs_for_goal(pplayer, i) > 0) {
- tech_type_iterate(k) {
- if (is_tech_a_req_for_goal(pplayer, k, i)) {
- goal_values[i] += values[k];
- }
- } tech_type_iterate_end;
- goal_values[i] += values[i];
-
-/* this is the best I could do. It still sometimes does freaky stuff like
-setting goal to Republic and learning Monarchy, but that's what it's supposed
-to be doing; it just looks strange. -- Syela */
-
- goal_values[i] /= num_unknown_techs_for_goal(pplayer, i);
- if (num_unknown_techs_for_goal(pplayer, i) < 6) {
- freelog(LOG_DEBUG, "%s: want = %d, value = %d, goal_value = %d",
- advances[i].name, pplayer->ai.tech_want[i],
- values[i], goal_values[i]);
+ int steps = num_unknown_techs_for_goal(pplayer, i);
+
+ if (steps == 0) {
+ continue;
+ }
+
+ goal_values[i] = values[i];
+ tech_type_iterate(k) {
+ if (is_tech_a_req_for_goal(pplayer, k, i)) {
+ goal_values[i] += values[k];
}
- } else goal_values[i] = 0;
+ } tech_type_iterate_end;
+ /* This is the best I could do. It still sometimes does freaky stuff
+ * like setting goal to Republic and learning Monarchy, but that's what
+ * it's supposed to be doing; it just looks strange. -- Syela */
+ goal_values[i] /= steps;
+ if (steps < 6) {
+ freelog(LOG_DEBUG, "%s: want = %d, value = %d, goal_value = %d",
+ advances[i].name, pplayer->ai.tech_want[i],
+ values[i], goal_values[i]);
+ }
} tech_type_iterate_end;
- l = A_UNSET; /* currently researched tech */
- k = A_UNSET; /* current tech goal */
+ newtech = A_UNSET;
+ newgoal = A_UNSET;
tech_type_iterate(i) {
- if (values[i] > values[l]
+ if (values[i] > values[newtech]
&& tech_is_available(pplayer, i)
&& get_invention(pplayer, i) == TECH_REACHABLE) {
- l = i;
+ newtech = i;
}
- if (goal_values[i] > goal_values[k]
+ if (goal_values[i] > goal_values[newgoal]
&& tech_is_available(pplayer, i)) {
- k = i;
+ newgoal = i;
}
} tech_type_iterate_end;
- freelog(LOG_DEBUG, "%s wants %s with desire %d (%d).", pplayer->name,
- advances[l].name, values[l], pplayer->ai.tech_want[l]);
+ freelog(LOG_DEBUG, "%s wants %s with desire %d (%d).",
+ pplayer->name, advances[newtech].name, values[newtech],
+ pplayer->ai.tech_want[newtech]);
if (choice) {
- choice->choice = l;
- choice->want = values[l] / num_cities_nonzero;
- choice->type = values[pplayer->research.researching] / num_cities_nonzero;
- /* hijacking this ... in order to leave tech_wants alone */
+ choice->choice = newtech;
+ choice->want = values[newtech] / num_cities_nonzero;
+ choice->current_want =
+ values[pplayer->research.researching] / num_cities_nonzero;
}
- if (gol) {
- gol->choice = k;
- gol->want = goal_values[k] / num_cities_nonzero;
- gol->type = goal_values[pplayer->ai.tech_goal] / num_cities_nonzero;
+ if (goal) {
+ goal->choice = newgoal;
+ goal->want = goal_values[newgoal] / num_cities_nonzero;
+ goal->current_want = goal_values[pplayer->ai.tech_goal] /
num_cities_nonzero;
freelog(LOG_DEBUG,
- "Gol->choice = %s, gol->want = %d, goal_value = %d, "
+ "Goal->choice = %s, goal->want = %d, goal_value = %d, "
"num_cities_nonzero = %d",
- advances[gol->choice].name, gol->want, goal_values[k],
+ advances[goal->choice].name, goal->want, goal_values[newgoal],
num_cities_nonzero);
}
return;
}
/**************************************************************************
- ...
+ Choose our next tech goal. Called by the server when a new tech is
+ discovered to determine new goal and, from it, the new tech to be
+ researched, which is quite stupid since ai_manage_tech sets a goal in
+ ai.tech_goal and we should either respect it or not bother doing it.
+
+ TODO: Kill this function.
**************************************************************************/
-static void ai_select_tech_goal(struct player *pplayer, struct ai_choice
*choice)
+void ai_next_tech_goal(struct player *pplayer)
{
- ai_select_tech(pplayer, NULL, choice);
+ struct ai_tech_choice goal_choice = {0, 0, 0};
+
+ ai_select_tech(pplayer, NULL, &goal_choice);
+
+ if (goal_choice.want == 0) {
+ goal_choice.choice = ai_next_tech_goal_default(pplayer);
+ }
+ if (goal_choice.choice != A_UNSET) {
+ pplayer->ai.tech_goal = goal_choice.choice;
+ freelog(LOG_DEBUG, "next_tech_goal for %s is set to %s",
+ pplayer->name, advances[goal_choice.choice].name);
+ }
}
/**************************************************************************
- ...
+ Use AI tech hints provided in governments.ruleset to up corresponding
+ tech wants.
+
+ TODO: The hints structure is too complicated, simplify.
**************************************************************************/
-void ai_next_tech_goal(struct player *pplayer)
+static void ai_use_gov_tech_hint(struct player *pplayer)
{
- struct ai_choice bestchoice, curchoice;
+ int i;
- init_choice(&bestchoice);
-
- ai_select_tech_goal(pplayer, &curchoice);
- copy_if_better_choice(&curchoice, &bestchoice);
-
- if (bestchoice.want == 0) {
- ai_next_tech_goal_default(pplayer, &bestchoice);
- }
- if (bestchoice.want != 0) {
- pplayer->ai.tech_goal = bestchoice.choice;
+ for(i=0; i<MAX_NUM_TECH_LIST; i++) {
+ struct ai_gov_tech_hint *hint = &ai_gov_tech_hints[i];
+
+ if (hint->tech == A_LAST) {
+ break;
+ }
+
+ if (get_invention(pplayer, hint->tech) != TECH_KNOWN) {
+ int steps = num_unknown_techs_for_goal(pplayer, hint->tech);
+
+ pplayer->ai.tech_want[hint->tech] +=
+ city_list_size(&pplayer->cities)
+ * (hint->turns_factor * steps + hint->const_factor);
+ if (hint->get_first) {
+ break;
+ }
+ } else {
+ if (hint->done) {
+ break;
+ }
+ }
}
}
@@ -211,9 +265,11 @@
**************************************************************************/
void ai_manage_tech(struct player *pplayer)
{
- struct ai_choice choice, gol;
- int penalty;
+ struct ai_tech_choice choice, goal;
+ /* Penalty for switching research */
+ int penalty = (pplayer->got_tech ? 0 : pplayer->research.bulbs_researched);
+ /* If there are humans in our team, they will choose the techs */
players_iterate(aplayer) {
const struct player_diplstate *ds = pplayer_get_diplstate(pplayer,
aplayer);
@@ -222,12 +278,12 @@
}
} players_iterate_end;
- penalty = (pplayer->got_tech ? 0 : pplayer->research.bulbs_researched);
+ ai_use_gov_tech_hint(pplayer);
- ai_select_tech(pplayer, &choice, &gol);
+ ai_select_tech(pplayer, &choice, &goal);
if (choice.choice != pplayer->research.researching) {
/* changing */
- if ((choice.want - choice.type) > penalty &&
+ if ((choice.want - choice.current_want) > penalty &&
penalty + pplayer->research.bulbs_researched <=
total_bulbs_required(pplayer)) {
freelog(LOG_DEBUG, "%s switching from %s to %s with penalty of %d.",
@@ -236,11 +292,14 @@
choose_tech(pplayer, choice.choice);
}
}
+
/* crossing my fingers on this one! -- Syela (seems to have worked!) */
- if (gol.choice != pplayer->ai.tech_goal) {
- freelog(LOG_DEBUG, "%s changing goal from %s (want = %d) to %s (want =
%d)",
- pplayer->name, advances[pplayer->ai.tech_goal].name, gol.type,
- advances[gol.choice].name, gol.want);
- choose_tech_goal(pplayer, gol.choice);
+ /* It worked, in particular, because the value it sets (ai.tech_goal)
+ * is practically never used, see the comment for ai_next_tech_goal */
+ if (goal.choice != pplayer->ai.tech_goal) {
+ freelog(LOG_DEBUG, "%s change goal from %s (want=%d) to %s (want=%d)",
+ pplayer->name, advances[pplayer->ai.tech_goal].name,
+ goal.current_want, advances[goal.choice].name, goal.want);
+ choose_tech_goal(pplayer, goal.choice);
}
}
Index: common/government.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/government.h,v
retrieving revision 1.26
diff -u -r1.26 government.h
--- common/government.h 30 Jun 2003 20:53:24 -0000 1.26
+++ common/government.h 25 May 2004 04:58:31 -0000
@@ -157,8 +157,7 @@
};
/* This should possibly disappear; we don't bother sending these to client;
- see code in ai_city.c: ai_manage_cities() for what they mean...
-*/
+ * See code in aitech.c for what the fields mean */
struct ai_gov_tech_hint {
int tech;
int turns_factor;
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [freeciv-ai] (PR#8832) Cleaning ai/aitech.c,
Gregory Berkolaiko <=
|
|