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.
aisettler.h
citymap.c ? 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");
aisettler.c
citymap.h
|