|
Complete.Org:
Mailing Lists:
Archives:
freeciv-ai:
May 2004: [freeciv-ai] (PR#8778) New settler code |
|
[freeciv-ai] (PR#8778) New settler code[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
<URL: http://rt.freeciv.org/Ticket/Display.html?id=8778 > > > By the way, why not restrict overseas search only to coastal spots? > > Yes, that is a bright idea. Done. The code is much cleaner now but works the same. > > Give me a couple of days, I will put in provisions for building > > ferries. Done. > > By the way, when we commit it, we kill the old settling code, right? > > We don't need to. The advantage of keeping it around for a few weeks > is > that people can compare the two implementations more easily. But then, > I am not sure if people will do so anyway... I am pretty sure nobody will. Just run a few of your tests, put up the results as the proof and kill the old code. After you do that, we should rearrane how contemplate_new_city is called. It is now called in a strange place to re-use the warmap, but this is obsolete. The new code is attached (I think citymap isn't changed but I include it just in case). It builds ferries if they are needed. When it considers whether to build a boat it uses a fully-fledged virtual boat so that if we only know triremes, it won't consider going to far-away islands. I think it's more ready than not. I know one buglet (after a ferry is loaded it waits for the next turn to go), but I can fix it in situ. The code depends on the find_ferry2 patch (8777). G.
? ferry_and_settler.txt
? settle4.gz
? settle5.gz
? stuck.gz
? ai/aisettler.c
? ai/aisettler.h
? common/aicore/citymap.c
? common/aicore/citymap.h
Index: ai/Makefile.am
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/Makefile.am,v
retrieving revision 1.17
diff -u -r1.17 Makefile.am
--- ai/Makefile.am 2 May 2004 12:13:51 -0000 1.17
+++ ai/Makefile.am 21 May 2004 17:46:53 -0000
@@ -27,6 +27,8 @@
aihunt.h \
ailog.c \
ailog.h \
+ aisettler.c \
+ aisettler.h \
aitech.c \
aitech.h \
aitools.c \
Index: ai/aidata.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/aidata.c,v
retrieving revision 1.24
diff -u -r1.24 aidata.c
--- ai/aidata.c 1 May 2004 03:22:11 -0000 1.24
+++ ai/aidata.c 21 May 2004 17:46:56 -0000
@@ -226,6 +226,10 @@
}
}
} unit_list_iterate_end;
+ freelog(LOG_NORMAL, "Boat stats: free %d of total %d. Passengers: %d",
+ ai->stats.available_boats, ai->stats.boats,
+ ai->stats.passengers);
+
/*** Diplomacy ***/
@@ -305,6 +309,9 @@
ai->angry_priority = TRADE_WEIGHTING * 3; /* grave danger */
ai->pollution_priority = POLLUTION_WEIGHTING;
+ ai->growth_priority = 15; /* WAG */
+
+ /* Goals */
ai_best_government(pplayer);
/*** Interception engine ***/
@@ -368,6 +375,26 @@
struct ai_data *ai = &aidata[pplayer->player_no];
int i;
+ /* The values below are WAGs that have been optimized to the
+ * default rules. They are not changed during the game. */
+
+ /* Perfection gives us an idea of how long to search for optimal
+ * solutions, instead of going for quick and dirty solutions that
+ * waste valuable time. Decrease for maps where good city placements
+ * are hard to find. Lower means more perfection. */
+ ai->perfection = 3;
+ /* How much to deemphasise the potential for city growth for city
+ * placements. Decrease this value if large cities are important
+ * or planned. Increase if running strict smallpox. */
+ ai->growth_potential_deemphasis = 8;
+ /* Percentage bonus to city locations near an ocean. */
+ ai->naval_emphasis = 20;
+ /* Modifier for defense bonus that is applied to city location want.
+ * Increase this to lower emphasis on defensive positions, increase
+ * it if you want more emphasis on heavily defended cities. */
+ ai->defense_emphasis = 4000;
+
+ /* Government variables */
ai->govt_reeval = 0;
ai->government_want = fc_calloc(game.government_count + 1, sizeof(int));
@@ -466,3 +493,4 @@
free(ai->government_want);
}
+
Index: ai/aidata.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/aidata.h,v
retrieving revision 1.11
diff -u -r1.11 aidata.h
--- ai/aidata.h 9 Oct 2003 00:07:33 -0000 1.11
+++ ai/aidata.h 21 May 2004 17:46:56 -0000
@@ -91,9 +91,11 @@
struct {
int *workers; /* cities to workers on continent*/
int *cities; /* number of cities on continent */
+
int passengers; /* number of passengers waiting for boats */
- int boats;
- int available_boats;
+ int boats; /* total number of boats */
+ int available_boats; /* number of boats not booked or used */
+
int average_production;
bv_id diplomat_reservations;
} stats;
@@ -110,6 +112,11 @@
int unhappy_priority;
int angry_priority;
int pollution_priority;
+ int growth_priority;
+ int perfection;
+ int growth_potential_deemphasis;
+ int naval_emphasis;
+ int defense_emphasis;
/* Government data */
int *government_want;
Index: ai/ailog.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/ailog.c,v
retrieving revision 1.12
diff -u -r1.12 ailog.c
--- ai/ailog.c 2 May 2004 12:33:29 -0000 1.12
+++ ai/ailog.c 21 May 2004 17:46:57 -0000
@@ -120,9 +120,6 @@
if (punit->debug) {
minlevel = LOG_NORMAL;
} else {
- if (minlevel > fc_log_level) {
- return;
- }
/* Are we a virtual unit evaluated in a debug city?. */
if (punit->id == 0) {
struct city *pcity = map_get_city(punit->x, punit->y);
@@ -131,6 +128,9 @@
minlevel = LOG_NORMAL;
}
}
+ if (minlevel > fc_log_level) {
+ return;
+ }
}
if (is_goto_dest_set(punit)) {
Index: ai/aitools.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/aitools.c,v
retrieving revision 1.104
diff -u -r1.104 aitools.c
--- ai/aitools.c 19 May 2004 21:03:12 -0000 1.104
+++ ai/aitools.c 21 May 2004 17:47:00 -0000
@@ -15,6 +15,7 @@
#include <config.h>
#endif
+#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
@@ -48,6 +49,7 @@
#include "aidata.h"
#include "ailog.h"
#include "aiunit.h"
+#include "citymap.h"
#include "aitools.h"
@@ -453,7 +455,9 @@
}
if (punit->ai.ai_role == AIUNIT_BUILD_CITY) {
+ assert(is_normal_map_pos(goto_dest_x(punit), goto_dest_y(punit)));
remove_city_from_minimap(goto_dest_x(punit), goto_dest_y(punit));
+ citymap_free_city_spot(goto_dest_x(punit), goto_dest_y(punit), punit->id);
}
if (punit->ai.ai_role == AIUNIT_HUNTER) {
@@ -488,9 +492,11 @@
ai_unit_new_role(bodyguard, AIUNIT_NONE, -1, -1);
}
- if (punit->ai.ai_role == AIUNIT_BUILD_CITY) {
+ /* Reserve city spot, _unless_ we want to add ourselves to a city. */
+ if (punit->ai.ai_role == AIUNIT_BUILD_CITY && !map_get_city(x, y)) {
assert(is_normal_map_pos(x, y));
add_city_to_minimap(x, y);
+ citymap_reserve_city_spot(x, y, punit->id);
}
if (punit->ai.ai_role == AIUNIT_HUNTER) {
/* Set victim's hunted bit - the hunt is on! */
Index: common/aicore/Makefile.am
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/aicore/Makefile.am,v
retrieving revision 1.6
diff -u -r1.6 Makefile.am
--- common/aicore/Makefile.am 2 May 2004 12:13:51 -0000 1.6
+++ common/aicore/Makefile.am 21 May 2004 17:47:02 -0000
@@ -12,4 +12,6 @@
pf_tools.c \
pf_tools.h \
cm.c \
- cm.h
+ cm.h \
+ citymap.c \
+ citymap.h
Index: common/aicore/pf_tools.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/aicore/pf_tools.c,v
retrieving revision 1.14
diff -u -r1.14 pf_tools.c
--- common/aicore/pf_tools.c 19 May 2004 00:49:31 -0000 1.14
+++ common/aicore/pf_tools.c 21 May 2004 17:47:04 -0000
@@ -528,7 +528,6 @@
parameter->get_TB = NULL;
parameter->get_EC = NULL;
BV_CLR_ALL(parameter->unit_flags);
- parameter->omniscience = TRUE;
parameter->start_x = punit->x;
parameter->start_y = punit->y;
@@ -538,8 +537,6 @@
parameter->unit_flags = unit_type(punit)->flags;
parameter->omniscience = !ai_handicap(unit_owner(punit), H_MAP);
-
-
}
/**********************************************************************
Index: server/settlers.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/settlers.c,v
retrieving revision 1.181
diff -u -r1.181 settlers.c
--- server/settlers.c 19 May 2004 14:40:15 -0000 1.181
+++ server/settlers.c 21 May 2004 17:47:17 -0000
@@ -39,8 +39,10 @@
#include "aicity.h"
#include "aidata.h"
#include "ailog.h"
+#include "aisettler.h"
#include "aitools.h"
#include "aiunit.h"
+#include "citymap.h"
#include "settlers.h"
@@ -54,9 +56,6 @@
BV_DEFINE(enemy_mask, MAX_NUM_PLAYERS + MAX_NUM_BARBARIANS);
static enemy_mask enemies[MAX_NUM_PLAYERS + MAX_NUM_BARBARIANS];
-static void auto_settler_findwork(struct player *pplayer,
- struct unit *punit);
-static void auto_settlers_player(struct player *pplayer);
static bool is_already_assigned(struct unit *myunit, struct player *pplayer,
int x, int y);
static int city_desirability(struct player *pplayer, int x, int y);
@@ -69,6 +68,11 @@
int x = punit->x, y = punit->y;
struct city *pcity;
+ handle_unit_activity_request(punit, ACTIVITY_IDLE);
+
+ /* Free city reservations */
+ ai_unit_new_role(punit, AIUNIT_NONE, -1, -1);
+
handle_unit_build_city(pplayer, punit->id,
city_name_suggestion(pplayer, x, y));
pcity = map_get_city(x, y);
@@ -1207,7 +1211,7 @@
}
/**************************************************************************
- find some work for the settler
+ Find some work for the settler
**************************************************************************/
static void auto_settler_findwork(struct player *pplayer, struct unit *punit)
{
@@ -1252,9 +1256,9 @@
return;
}
- /* If we intent on building a city then reserve the square. */
- if (unit_flag(punit, F_CITIES) &&
- best_act == ACTIVITY_UNKNOWN /* flag */) {
+ /* If we intend to build a city then reserve the square. */
+ if (unit_flag(punit, F_CITIES)
+ && best_act == ACTIVITY_UNKNOWN /* flag */) {
ai_unit_new_role(punit, AIUNIT_BUILD_CITY, gx, gy);
} else {
ai_unit_new_role(punit, AIUNIT_AUTO_SETTLER, gx, gy);
@@ -1271,7 +1275,6 @@
&& same_pos(gx, gy, punit->x, punit->y)) {
if (best_act == ACTIVITY_UNKNOWN) {
remove_city_from_minimap(gx, gy); /* yeah, I know. -- Syela */
- handle_unit_activity_request(punit, ACTIVITY_IDLE);
(void) ai_do_build_city(pplayer, punit);
return;
}
@@ -1282,6 +1285,117 @@
}
/**************************************************************************
+ New implementation of server/settlers.c function with same name
+**************************************************************************/
+#define LOG_SETTLER LOG_NORMAL
+static void auto_settler_findwork2(struct player *pplayer, struct unit *punit)
+{
+ struct cityresult result;
+ int best_impr = 0; /* best terrain improvement we can do */
+ enum unit_activity best_act = ACTIVITY_IDLE; /* compat. kludge */
+ int gx = -1, gy = -1;
+
+ CHECK_UNIT(punit);
+
+ result.total = 0;
+
+ assert(pplayer && punit);
+ assert(unit_flag(punit, F_CITIES) || unit_flag(punit, F_SETTLERS));
+
+ /*** If we are on a city mission: Go where we should ***/
+
+ if (punit->ai.ai_role == AIUNIT_BUILD_CITY) {
+ int x = goto_dest_x(punit), y = goto_dest_y(punit), sanity = punit->id;
+
+ /* Check that missions is still possible */
+ if (!city_can_be_built_here(x, y, punit)) {
+ UNIT_LOG(LOG_SETTLER, punit, "city founding mission failed");
+ ai_unit_new_role(punit, AIUNIT_NONE, -1, -1);
+ return; /* avoid recursion at all cost */
+ } else {
+ /* Go there */
+ if ((!ai_gothere(pplayer, punit, x, y) && !find_unit_by_id(sanity))
+ || punit->moves_left <= 0) {
+ return;
+ }
+ if (same_pos(punit->x, punit->y, x, y)) {
+ if (!ai_do_build_city(pplayer, punit)) {
+ UNIT_LOG(LOG_ERROR, punit, "could not make city on %s",
+ map_get_tile_info_text(punit->x, punit->y));
+ ai_unit_new_role(punit, AIUNIT_NONE, -1, -1);
+ } else {
+ return; /* We came, we saw, we built... */
+ }
+ } else {
+ UNIT_LOG(LOG_SETTLER, punit, "could not go to target");
+ /* ai_unit_new_role(punit, AIUNIT_NONE, -1, -1); */
+ return;
+ }
+ }
+ }
+
+ CHECK_UNIT(punit);
+
+ /*** Try find some work ***/
+
+ if (unit_flag(punit, F_SETTLERS)) {
+ best_impr = evaluate_improvements(punit, &best_act, &gx, &gy);
+ }
+
+ if (unit_flag(punit, F_CITIES)) {
+ find_best_city_placement(punit, &result, TRUE, FALSE);
+ UNIT_LOG(LOG_SETTLER, punit, "city want %d (impr want %d)", result.total,
+ best_impr);
+ if (result.total > best_impr) {
+ if (map_get_city(result.x, result.y)) {
+ UNIT_LOG(LOG_SETTLER, punit, "immigrates to %s (%d, %d)",
+ map_get_city(result.x, result.y), result.x, result.y);
+ } else {
+ UNIT_LOG(LOG_SETTLER, punit, "makes city at (%d, %d)",
+ result.x, result.y);
+ }
+ /* Go make a city! */
+ ai_unit_new_role(punit, AIUNIT_BUILD_CITY, result.x, result.y);
+ set_goto_dest(punit, result.x, result.y); /* TMP */
+ } else if (best_impr > 0) {
+ UNIT_LOG(LOG_SETTLER, punit, "improves terrain");
+ /* Terrain improvements follows the old model, and is recalculated
+ * each turn. */
+ ai_unit_new_role(punit, AIUNIT_AUTO_SETTLER, gx, gy);
+ /* Mark the square as taken. */
+ if (gx != -1 && gy != -1) {
+ map_get_tile(gx, gy)->assigned =
+ map_get_tile(gx, gy)->assigned | 1<<pplayer->player_no;
+ } else {
+ UNIT_LOG(LOG_NORMAL, punit, "giving up trying to improve terrain");
+ return; /* We cannot do anything */
+ }
+ set_goto_dest(punit, gx, gy); /* TMP */
+ if (do_unit_goto(punit, GOTO_MOVE_ANY, FALSE) == GR_DIED) {
+ return;
+ }
+ if (punit->moves_left > 0
+ && same_pos(gx, gy, punit->x, punit->y)) {
+ handle_unit_activity_request(punit, best_act);
+ send_unit_info(NULL, punit);
+ return;
+ }
+ } else {
+ UNIT_LOG(LOG_SETTLER, punit, "cannot find work");
+ ai_unit_new_role(punit, AIUNIT_NONE, -1, -1);
+ return;
+ }
+ }
+
+ /*** Recurse if we want to found a city ***/
+
+ if (punit->ai.ai_role == AIUNIT_BUILD_CITY) {
+ auto_settler_findwork2(pplayer, punit);
+ }
+}
+#undef LOG_SETTLER
+
+/**************************************************************************
Do all tile improvement calculations and cache them for later.
**************************************************************************/
void initialize_infrastructure_cache(struct city *pcity)
@@ -1316,15 +1430,20 @@
}
/**************************************************************************
- run through all the players settlers and let those on ai.control work
- automagically
+ Run through all the players settlers and let those on ai.control work
+ automagically.
**************************************************************************/
-static void auto_settlers_player(struct player *pplayer)
+void auto_settlers_player(struct player *pplayer)
{
static struct timer *t = NULL; /* alloc once, never free */
t = renew_timer_start(t, TIMER_CPU, TIMER_DEBUG);
+ if (pplayer->ai.control && ai_handicap(pplayer, H_EXPERIMENTAL)) {
+ /* Set up our city map. */
+ citymap_turn_init(pplayer);
+ }
+
city_list_iterate(pplayer->cities, pcity)
initialize_infrastructure_cache(pcity); /* saves oodles of time -- Syela */
city_list_iterate_end;
@@ -1352,9 +1471,12 @@
handle_unit_activity_request(punit, ACTIVITY_IDLE);
}
if (punit->activity == ACTIVITY_IDLE) {
- auto_settler_findwork(pplayer, punit);
+ if (pplayer->ai.control && ai_handicap(pplayer, H_EXPERIMENTAL)) {
+ auto_settler_findwork2(pplayer, punit);
+ } else {
+ auto_settler_findwork(pplayer, punit);
+ }
}
- freelog(LOG_DEBUG, "Has been processed.");
}
}
unit_list_iterate_end;
@@ -1473,7 +1595,6 @@
*/
}
-
/**************************************************************************
Recalculate enemies[] table
**************************************************************************/
@@ -1489,9 +1610,9 @@
}
/**************************************************************************
- Do the auto_settler stuff for all the players.
+ Initialize autosettler code.
**************************************************************************/
-void auto_settlers(void)
+void auto_settlers_init(void)
{
assign_settlers();
assign_territory();
@@ -1502,8 +1623,8 @@
}
/**************************************************************************
-used to use old crappy formulas for settler want, but now using actual
-want!
+ Return want for city settler. Note that we rely here on the fact that
+ ai_settler_init() has been run while doing autosettlers.
**************************************************************************/
void contemplate_new_city(struct city *pcity)
{
@@ -1523,24 +1644,38 @@
virtualunit = create_unit_virtual(pplayer, pcity, unit_type, 0);
virtualunit->x = pcity->x;
virtualunit->y = pcity->y;
- want = evaluate_city_building(virtualunit, &gx, &gy, &ferryboat);
- free(virtualunit);
-
- unit_list_iterate(pplayer->units, qpass) {
- /* We want a ferryboat with want 199 */
- if (qpass->ai.ferryboat == pcity->id)
- want = -199;
- } unit_list_iterate_end;
- /* Did we count on using an existing boat. If yes we need to keep it
- * in the city. */
- pcity->ai.founder_boat = (ferryboat != NULL);
+ assert(pplayer->ai.control);
- if (gx == -1) {
- pcity->ai.founder_want = -want;
+ if (pplayer->ai.control && ai_handicap(pplayer, H_EXPERIMENTAL)) {
+ struct cityresult result;
+ bool is_coastal = is_at_coast(pcity->x, pcity->y);
+
+ find_best_city_placement(virtualunit, &result, is_coastal, is_coastal);
+
+ CITY_LOG(LOG_NORMAL, pcity, "wants (%d much) to establish new city at"
+ " (%d, %d) and will %s to get there", result.total,
+ result.x, result.y,
+ (result.virt_boat ? "build a boat" :
+ (result.overseas ? "use a boat" : "walk")));
+
+ pcity->ai.founder_want = (result.virt_boat ?
+ -result.total : result.total);
+ pcity->ai.founder_boat = result.overseas;
} else {
- pcity->ai.founder_want = want; /* boat */
+ want = evaluate_city_building(virtualunit, &gx, &gy, &ferryboat);
+
+ /* Did we count on using an existing boat. If yes we need to keep it
+ * in the city. */
+ pcity->ai.founder_boat = (ferryboat != NULL);
+
+ if (gx == -1) {
+ pcity->ai.founder_want = -want;
+ } else {
+ pcity->ai.founder_want = want; /* boat */
+ }
}
+ free(virtualunit);
}
/**************************************************************************
Index: server/settlers.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/settlers.h,v
retrieving revision 1.23
diff -u -r1.23 settlers.h
--- server/settlers.h 23 Sep 2003 15:59:05 -0000 1.23
+++ server/settlers.h 21 May 2004 17:47:18 -0000
@@ -19,7 +19,8 @@
struct unit;
struct city;
-void auto_settlers(void);
+void auto_settlers_init(void);
+void auto_settlers_player(struct player *pplayer);
int find_boat(struct player *pplayer, int *x, int *y, int cap);
#define MORT 24
Index: server/srv_main.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/srv_main.c,v
retrieving revision 1.160
diff -u -r1.160 srv_main.c
--- server/srv_main.c 2 May 2004 14:47:12 -0000 1.160
+++ server/srv_main.c 21 May 2004 17:47:24 -0000
@@ -97,6 +97,8 @@
#include "advmilitary.h"
#include "aidata.h"
#include "aihand.h"
+#include "aisettler.h"
+#include "citymap.h"
#include "srv_main.h"
@@ -488,8 +490,13 @@
nocity_send = TRUE;
/* AI end of turn activities */
+ auto_settlers_init();
players_iterate(pplayer) {
if (pplayer->ai.control) {
+ ai_settler_init(pplayer);
+ }
+ auto_settlers_player(pplayer);
+ if (pplayer->ai.control) {
ai_do_last_activities(pplayer);
}
} players_iterate_end;
@@ -1403,8 +1410,6 @@
summon_barbarians(); /* wild guess really, no idea where to put it, but
I want to give them chance to move their units */
/* Moved this to after the human turn for efficiency -- Syela */
- freelog(LOG_DEBUG, "Autosettlers");
- auto_settlers();
freelog(LOG_DEBUG, "Auto-Attack phase");
auto_attack();
freelog(LOG_DEBUG, "Endturn");
|