[freeciv-ai] (PR#8992) Patch: Building ferries
[Top] [All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
<URL: http://rt.freeciv.org/Ticket/Display.html?id=8992 >
> [badamson@xxxxxxxxxxx - Wed Nov 10 00:32:38 2004]:
>
> Gregory Berkolaiko wrote:
> ...
> > This formula is dimensionnally incorrect: the left part is in boats, the
> > right part is in passengers/boats.
> ...
> > + psngrs = psngrs * DENOM + MAX(0, future_psngrs - boats * DENOM);
>
> If passengers and boats are considered different units (I was treating
> them as pure numbers -- what is the SI unit of boats?), then
> future_psngrs - boats is also dimensionally incorrect.
One boat cancels one waiting passenger, so they have the same SI units.
One Helen or one Argo will do :)
> > I think building more than one new boat at a time is needed very rarely
> > and is quite risky because we react too much to a potentially
> > short-lived surge in the demand.
>
> Not in my observations of auto games where I have allowed it. When the
> AI has built many boats using published versions of my patches, the boat
> utilisation has usually remained high--- the extra boats did not become
> surplus to requirements. Building several boats is useful to a
> successful AI in later stages of the game, when it is on the offensive
> and needs to ferry many attackers.
Ok, so we'll keep it in some form. I guess oceans can be pretty big...
> Which is what you coded in your original patch, but left as a TO-DO
> item. However, I subsequently examined the code and discovered that the
> AI never requests ferries if it does not have ferry technology, so I
> removed that section. The centralised ferry building code handles the
> _supply_ of ferries rather than the _demand_, so it makes some sense (to
> me) that it does not handle the demand for technology. *However*, the
> current military adviser currently does not generate demand for ferry
> technology either.
Yes, but it is in the unique position of knowing what is the total
demand! I think it makes sense to request technology here, in one
place, rather than each city doing it. I think there were some kludges
flying around but maybe we killed them... Anyway, now AI clearly
doesn't give a damn about Map Making, which isn't good.
I chopped your code up to my liking, without actually changing the
logic. Removed things that I thought are unnecessary, in particular
horizon. Right now I am reworking it to use channels and not to use PF.
I want to make trial runs for speed and then select the code which
looks the cutest of course ;)
The remix of your patch (it compiles but not sure if it works, it also
became quite a bit shorter) is attached.
Also, I know some people have a reputation of purging constants and
changing them to defines ;) but when something is used only once I think
it's much easier to read if it is written in its numerical form.
Good work by the way!
GB
Index: ai/advdomestic.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/advdomestic.c,v
retrieving revision 1.121
diff -u -r1.121 advdomestic.c
--- ai/advdomestic.c 20 Oct 2004 18:20:53 -0000 1.121
+++ ai/advdomestic.c 12 Nov 2004 05:42:01 -0000
@@ -204,7 +204,6 @@
choice->type = CT_NONMIL;
choice->choice = unit_type; /* default */
choice->need_boat = TRUE;
- ai_choose_role_unit(pplayer, pcity, choice, L_FERRYBOAT, -want);
}
}
Index: ai/advmilitary.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/advmilitary.c,v
retrieving revision 1.176
diff -u -r1.176 advmilitary.c
--- ai/advmilitary.c 30 Oct 2004 14:04:54 -0000 1.176
+++ ai/advmilitary.c 12 Nov 2004 05:42:01 -0000
@@ -962,8 +962,8 @@
3. calculates the relevant stats of the victim.
4. finds the best attacker for this type of victim (in process_attacker_want)
5. if we still want to attack, records the best attacker in choice.
-If the target is overseas, the function might suggest building a ferry
-to carry a land attack unit, instead of the land attack unit itself.
+If the target is overseas, the function might suggest using a ferry
+to carry a land attack unit.
**************************************************************************/
static void kill_something_with(struct player *pplayer, struct city *pcity,
struct unit *myunit, struct ai_choice *choice)
@@ -1126,23 +1126,9 @@
if (best_choice.want > choice->want) {
/* We want attacker more than what we have selected before */
copy_if_better_choice(&best_choice, choice);
- CITY_LOG(LOG_DEBUG, pcity, "ksw: %s has chosen attacker, %s, want=%d",
- pcity->name, unit_types[choice->choice].name, choice->want);
-
- if (go_by_boat && !ferryboat) { /* need a new ferry */
- /* We might need a new boat even if there are boats free,
- * if they are blockaded or in inland seas*/
- assert(is_ground_unit(myunit));
- ai_choose_role_unit(pplayer, pcity, choice, L_FERRYBOAT, choice->want);
- if (SEA_MOVING == unit_types[choice->choice].move_type) {
- struct ai_data *ai = ai_data_get(pplayer);
-
- freelog(LOG_DEBUG,
- "%s has chosen attacker ferry, %s, want=%d, %d of %d free",
- pcity->name, unit_types[choice->choice].name, choice->want,
- ai->stats.available_boats, ai->stats.boats);
- } /* else can not build ferries yet */
- }
+ CITY_LOG(LOG_DEBUG, pcity, "has chosen attacker, %s, want=%d%s",
+ unit_types[choice->choice].name, choice->want,
+ (best_choice.need_boat ? "(need boat)" : ""));
}
}
@@ -1390,9 +1376,7 @@
destroy_unit_virtual(virtualunit);
}
- /* Consider a land attacker or a ferried land attacker
- * (in which case, we might want a ferry before an attacker)
- */
+ /* Consider a land attacker or a ferried land attacker */
unit_type = ai_choose_attacker(pcity, LAND_MOVING);
if (unit_type >= 0) {
virtualunit = create_unit_virtual(pplayer, pcity, unit_type, 1);
Index: ai/aicity.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/aicity.c,v
retrieving revision 1.177
diff -u -r1.177 aicity.c
--- ai/aicity.c 31 Oct 2004 21:52:20 -0000 1.177
+++ ai/aicity.c 12 Nov 2004 05:42:01 -0000
@@ -46,6 +46,7 @@
#include "advdomestic.h"
#include "advmilitary.h"
#include "aidata.h"
+#include "aiferry.h"
#include "aihand.h"
#include "ailog.h"
#include "aitools.h"
@@ -981,6 +982,8 @@
ai_city_choose_build(pplayer, pcity);
} city_list_iterate_end;
+ aiferry_choose_build_global(pplayer);
+
ai_spend_gold(pplayer);
}
Index: ai/aiferry.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/aiferry.c,v
retrieving revision 1.10
diff -u -r1.10 aiferry.c
--- ai/aiferry.c 8 Nov 2004 14:14:30 -0000 1.10
+++ ai/aiferry.c 12 Nov 2004 05:42:02 -0000
@@ -14,24 +14,30 @@
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
+#include <math.h>
#include "log.h"
+#include "rand.h"
#include "unit.h"
#include "path_finding.h"
#include "pf_tools.h"
#include "hand_gen.h"
+#include "maphand.h"
#include "unithand.h"
#include "unittools.h"
#include "aidata.h"
#include "aiexplorer.h"
+#include "aihand.h"
+#include "aihunt.h"
#include "ailog.h"
#include "aitools.h"
#include "aiunit.h"
#include "aiferry.h"
+#include "settlers.h" /*for amortize*/
/* =================== constants with special meaning =================== */
@@ -51,12 +57,38 @@
/* Logging in ferry management functions */
#define LOGLEVEL_FERRY LOG_DEBUG
+#define LOGLEVEL_BUILDFERRY LOG_NORMAL
/* Logging in go_by_boat functions */
#define LOGLEVEL_GOBYBOAT LOG_DEBUG
/* Logging in find_ferry functions */
#define LOGLEVEL_FINDFERRY LOG_DEBUG
/* Extra consistency checks */
#define DEBUG_FERRY_STATS 0
+/*
+ * The maximum number of turns to look ahead.
+ * For each city, the code looks ahead no further than the completion of the
+ * item currently being built. This should therefore not be much longer
+ * than a typical build time.
+ */
+#define MAX_TURNS_HORIZON 10
+
+
+
+/*
+ * Data about one sea area for one player.
+ */
+struct sea_stats {
+ unsigned int psngrs;
+ unsigned int boats;
+ unsigned int avail_boats;
+ unsigned int future_psngrs;
+ double future_psngrs_weight;
+
+ unsigned int sea_area;
+ unsigned int n_cities; /*our cities*/
+
+ int ferry_want;
+};
/* ========= managing statistics and boat/passanger assignments ======== */
@@ -73,7 +105,7 @@
ai->stats.available_boats = 0;
unit_list_iterate(pplayer->units, punit) {
- if (is_sailing_unit(punit) && is_ground_units_transport(punit)) {
+ if (unit_has_role(punit->type, L_FERRYBOAT)) {
ai->stats.boats++;
if (punit->ai.passenger == FERRY_AVAILABLE) {
ai->stats.available_boats++;
@@ -95,8 +127,8 @@
struct ai_data *ai = ai_data_get(pplayer);
int n = 1;
- freelog(LOG_NORMAL, "Boat stats for %s[%d]",
- pplayer->name, pplayer->player_no);
+ freelog(LOG_NORMAL, "Boat stats for %s[%d] in turn %d",
+ pplayer->name, pplayer->player_no, game.turn);
freelog(LOG_NORMAL, "Registered: %d free out of total %d",
ai->stats.available_boats, ai->stats.boats);
unit_list_iterate(pplayer->units, punit) {
@@ -870,3 +902,459 @@
return;
}
+
+/*
+ * WAGs for controlling the new_boats_to_build function.
+ */
+#define TARGET_UTILISATION 0.4
+#define TARGET_QUEUE 0.7
+#define T_UTILISATION 3.0
+#define T_QUEUE 4.0
+/*
+ * The following two constants are to ensure that having many waiting
+ * passengers will increase the 'want' for ferries.
+ */
+/* The minimum 'want' for ferries if there are any massengers waiting. */
+#define WAIT_FERRY_WANT_0 200
+/* The extra 'want' for each currently waiting passenger per boat. */
+#define WAIT_FERRY_WANT_1 400
+/****************************************************************************
+ Convert facts about a sea into an opinion about how many boats to build
+ for that sea.
+
+ We should build more ferries
+ * if we have many passengers waiting and/or expect more in the future
+ * if the boats we have are very busy
+
+ The function implements a simple feedback control system.
+ However, it overides that calculation to prevent building boats on ponds
+ and to prevent passengers waiting forever.
+****************************************************************************/
+static unsigned int new_boats_to_build(struct sea_stats *sea)
+{
+ unsigned int all_psngrs = sea->psngrs + sea->future_psngrs;
+ bool force_no_build = (sea->sea_area < 49) || (0 == all_psngrs);
+ bool force_build = !force_no_build && (0 == sea->boats && 0 < all_psngrs);
+ double build, build_utilisation, build_queue;
+ double psngrs = sea->psngrs + sea->future_psngrs_weight;
+ double boats = sea->boats;
+ double avail_boats = sea->avail_boats;
+ double queue;
+
+ assert(avail_boats <= boats);
+
+ queue = psngrs / MAX(1, boats);
+
+ /* Calculate each contribution */
+ build_utilisation = (boats - avail_boats - TARGET_UTILISATION * boats)
+ * (1.0/T_UTILISATION);
+ build_queue = (queue - TARGET_QUEUE) * (1.0/T_QUEUE);
+
+ build = build_utilisation + build_queue;
+
+ if (build < 1 && force_build) {
+ /*Ensure we will always have at least one ferry
+ *for each sea that has passengers.
+ *Prevents passengers waiting forever*/
+ build = 1;
+ } else if (force_no_build) {
+ build = 0;
+ }
+
+ build = MAX(0.0, floor(build + 0.5));
+
+ /*if there are many waiting passsengers, increase the 'want' for ferries*/
+ if (sea->psngrs) {
+ int waiters_want = WAIT_FERRY_WANT_0
+ + sea->psngrs * WAIT_FERRY_WANT_1 / MAX(1, sea->boats);
+ sea->ferry_want = MAX(sea->ferry_want, waiters_want);
+ }
+
+ freelog(LOGLEVEL_BUILDFERRY, "Ferries: psngrs %3.1f, queue %3.1f, "
+ "build %3.1f=%3.1f%+3.1f (want %d)", psngrs, queue,
+ build, build_utilisation, build_queue, sea->ferry_want);
+
+ return build;
+}
+
+/****************************************************************************
+ Abstract interface for using the ferry building mode of a city
+****************************************************************************/
+static enum city_ferry_mode get_city_ferry_mode(const struct city *acity)
+{
+ return acity->ai.ferry_mode;
+}
+
+/****************************************************************************
+ Ditto
+****************************************************************************/
+static void set_city_ferry_mode(struct city *acity,
+ const enum city_ferry_mode mode)
+{
+ acity->ai.ferry_mode = mode;
+}
+
+#define SCORE_TIME_SCALE 1000
+/* Least Common Multiple of 2,3,..,8 (a very divisible number) */
+#define DENOM 840
+/****************************************************************************
+ Evaluate how suitable a city is as a ferry builder.
+ Larger values mean more suitable. only positive values indicate suitable
+ cities.
+
+ Cities to consider for ferry building.
+ * Only cities on the shore of the current ocean are suitable.
+ * Only cities not already building ferries are suitable.
+ * Cities that can complete a boat sooner are better.
+ * Cities that want a boat themselves are better.
+ * Cities building defenders are unsuitable.
+ * Cities with port facilities are better.
+ * Cities not building wonders are better.
+****************************************************************************/
+static int ferry_builder_score(struct player *pplayer, struct city *acity,
+ Unit_Type_id boattype)
+{
+ int score = 0;
+ Impr_Type_id port_facility;
+ int turns;
+
+ assert(0 <= acity->ai.choice.want);
+
+ /* Consider only appropriate cities: */
+ if (get_city_ferry_mode(acity) != CFM_COUNTED
+ || !can_build_unit(acity, boattype)
+ || (!acity->is_building_unit && is_wonder(acity->currently_building))) {
+ return 0;
+ }
+
+ if (acity->ai.choice.need_boat) {
+ /* if you *really* want a ferry, you should be prepared to build it
+ * yourself */
+ score = acity->ai.choice.want;
+ } else {
+ /* if you do not much care for what you are doing, you might be asked
+ * to build a ferry instead */
+ score = -acity->ai.choice.want;
+ }
+
+ turns = city_turns_to_build(acity, boattype, TRUE, TRUE);
+
+ /* Make some adjustments depending on what city is building now */
+ switch (acity->ai.choice.type) {
+ case CT_BUILDING:
+ /* Dont like to stop buildings */
+ turns = turns * 3;
+ break;
+ case CT_NONMIL:
+ turns = turns * 2 / 3;
+ break;
+ case CT_DEFENDER:
+ return 0;
+ }
+
+ /* Prefer building veteran units (resistant to hunters) */
+ port_facility = ai_find_source_building(pplayer, EFT_SEA_VETERAN);
+ if (port_facility != B_LAST && city_got_building(acity, port_facility)) {
+ turns = turns * 2 / 3;
+ }
+
+ /* Sooner is better */
+ score += SCORE_TIME_SCALE / MAX(1, turns);
+
+ return score;
+}
+
+/****************************************************************************
+ Choose the cities that will build the boats
+****************************************************************************/
+static void select_ferry_builders(struct player *pplayer,
+ unsigned int boats_to_be_built,
+ Unit_Type_id boattype)
+{
+ while (boats_to_be_built > 0) {
+ int best = 0;
+ struct city *bestcity = NULL;
+
+ /*Find the best city to build the next ferry*/
+ city_list_iterate(pplayer->cities, acity) {
+ int score = ferry_builder_score(pplayer, acity, boattype);
+ if (best < score && 0 < score) {
+ assert(is_ocean_near_tile(acity->tile));
+ best = score;
+ bestcity = acity;
+ }
+ } city_list_iterate_end;
+
+ if (!bestcity) {
+ break;
+ }
+
+ /* FIXME: separate a function ai_set_build from
+ * aicity.c:ai_city_choose_build and use it here */
+ CITY_LOG(LOGLEVEL_BUILDFERRY, bestcity, "will build a boat");
+ bestcity->currently_building = boattype;
+ bestcity->is_building_unit = TRUE;
+ set_city_ferry_mode(bestcity, CFM_BUILDING);
+ boats_to_be_built--;
+ }
+
+ if (0 < boats_to_be_built) {
+ freelog(LOGLEVEL_BUILDFERRY,
+ "Ferries: %s unable to build %d boats",
+ pplayer->name, boats_to_be_built);
+ }
+}
+
+/****************************************************************************
+ Adjust wants in the cities needing or building ferries. Otherwise AI buys
+ new passengers before boats get built. "Shortage" is TRUE if we couldn't
+ order as many boats as we wanted.
+****************************************************************************/
+static void adjust_wants(struct player *pplayer, bool shortage, int ferry_want)
+{
+ city_list_iterate(pplayer->cities, acity) {
+ if (get_city_ferry_mode(acity) == CFM_BUILDING) {
+ /*Building a ferry here.*/
+ acity->ai.choice.want = ferry_want;
+ } else if(shortage && get_city_ferry_mode(acity) == CFM_COUNTED
+ && acity->ai.choice.need_boat && ai_fuzzy(pplayer, TRUE)) {
+ /*We have a shortage, and this city will make the shortage worse,
+ so spending gold here would be foolish*/
+ acity->ai.choice.want = MIN(ferry_want - 1,
+ acity->ai.choice.want / 2);
+ }
+ } city_list_iterate_end;
+}
+
+/****************************************************************************
+ Initialise the statistics about one sea for one player.
+****************************************************************************/
+static void sea_init(struct sea_stats *sea)
+{
+ assert(sea);
+
+ sea->future_psngrs = 0;
+ sea->future_psngrs_weight = 0.0;
+ sea->psngrs = 0;
+ sea->boats = 0;
+ sea->avail_boats = 0;
+
+ sea->sea_area = 0;
+ sea->n_cities = 0;
+
+ sea->ferry_want = 0;
+}
+
+/* Weight of one future passenger (if weight of an existing passenger is 1)
+ * Also to be divided by the time required to finish building */
+#define WEIGHT_FUTURE 0.2
+/****************************************************************************
+ Add, to the various statistics about a sea for one player,
+ the contribution of a city.
+****************************************************************************/
+static void sea_examine_city(struct player *pplayer,
+ struct sea_stats *sea,
+ struct city *acity)
+{
+ bool is_building_unit;
+ int turns_to_build;
+
+ if (city_owner(acity) != pplayer) {
+ return;
+ }
+
+ is_building_unit = is_unit_choice_type(acity->ai.choice.type);
+ turns_to_build =
+ is_building_unit?
+ city_turns_to_build(acity, acity->ai.choice.choice, is_building_unit,
+ TRUE)
+ :FC_INFINITY;
+ assert(0 < turns_to_build);
+
+ assert(get_city_ferry_mode(acity) == CFM_UNPROCESSED);
+ set_city_ferry_mode(acity, CFM_COUNTED);
+
+ sea->n_cities++;
+ if (acity->ai.choice.need_boat) {
+ sea->future_psngrs++;
+ sea->future_psngrs_weight += WEIGHT_FUTURE / ((double)turns_to_build);
+ sea->ferry_want += acity->ai.choice.want;
+ }
+}
+
+/****************************************************************************
+ Add, to the various statistics about a sea for one player,
+ the contribution of a unit.
+****************************************************************************/
+static void sea_examine_unit(struct player *pplayer,
+ struct sea_stats *sea,
+ struct unit *aunit)
+{
+ if (unit_owner(aunit) != pplayer) {
+ return;
+ } else if (unit_has_role(aunit->type, L_FERRYBOAT)) {
+ sea->boats++;
+ if (aunit->ai.passenger == FERRY_AVAILABLE) {
+ sea->avail_boats++;
+ } else if (aunit->ai.passenger == 0) {
+ freelog(LOG_ERROR, "Passenger field set to 0");
+ sea->avail_boats++;
+ }
+ } else if (aunit->ai.ferryboat == FERRY_WANTED) {
+ sea->psngrs++;
+ }
+}
+
+/****************************************************************************
+ Add, to the various statistics about a sea for one player,
+ the contribution of a tile.
+ The tile may be in the sea or on its shore.
+****************************************************************************/
+static void sea_examine_tile(struct player *pplayer,
+ struct sea_stats *sea,
+ struct tile *ptile)
+{
+ struct city *acity = map_get_city(ptile);
+
+ if (is_ocean(map_get_terrain(ptile))) {
+ sea->sea_area++;
+ }
+
+ if (acity) {
+ sea_examine_city(pplayer, sea, acity);
+ }
+
+ unit_list_iterate(ptile->units, aunit) {
+ sea_examine_unit(pplayer, sea, aunit);
+ } unit_list_iterate_end;
+}
+
+/****************************************************************************
+ Compute various statistics about a sea for one player,
+ for use in determining how many ferries to build there.
+
+ *sea:
+ the computed statistics
+ pfmap:
+ a map of the sea and its shore
+****************************************************************************/
+static void sea_examine_sea(struct player *pplayer,
+ struct sea_stats *sea,
+ struct pf_map *pfmap)
+{
+ sea_init(sea);
+
+ /* We want to consider the place we are currently in too, hence the
+ * do-while loop */
+ do {/*all tiles in the sea or on its shore*/
+ struct pf_position pos;
+ pf_next_get_position(pfmap, &pos);
+ sea_examine_tile(pplayer, sea, pos.tile);
+ } while (pf_next(pfmap));
+
+ /*convert total to average*/
+ sea->ferry_want = sea->ferry_want / MAX(1, sea->future_psngrs);
+
+ assert(sea->avail_boats <= sea->boats);
+}
+
+/****************************************************************************
+ A global ferry build selector. Estimates our want for the boats and finds
+ cities who will build them.
+****************************************************************************/
+void aiferry_choose_build_global(struct player *pplayer)
+{
+ /* The worst case is that each of our cities
+ * is on the coast of a different ocean:*/
+ int inf_loop_guard = city_list_size(&pplayer->cities);
+
+ /* Path-finding stuff */
+ struct pf_map *pfmap;
+ struct pf_parameter parameter;
+
+ /*Choose type of boats to build*/
+ Unit_Type_id boattype = best_role_unit_for_player(pplayer, L_FERRYBOAT);
+ if (boattype == U_LAST) {
+ freelog(LOGLEVEL_BUILDFERRY,
+ "Ferries: %s lacks the technology to build boats",
+ pplayer->name);
+ return;
+ }
+
+ /* Initialize */
+ city_list_iterate(pplayer->cities, acity) {
+ set_city_ferry_mode(acity, CFM_UNPROCESSED);
+ } city_list_iterate_end;
+
+ parameter.turn_mode = TM_NONE;
+ parameter.get_MC = sea_overlap_move; /*an ocean and its shore*/
+ parameter.get_TB = NULL;
+ parameter.get_EC = NULL;
+ parameter.get_costs = NULL;
+ parameter.get_zoc = NULL;
+ parameter.is_pos_dangerous = NULL;
+ BV_CLR_ALL(parameter.unit_flags);
+ parameter.owner = pplayer;
+ parameter.omniscience = TRUE; /*this code handles ignorance itself*/
+ /* These don't matter */
+ parameter.moves_left_initially = 0;
+ parameter.move_rate = 3;
+
+ do {/*each ocean for which we have coastal cities*/
+ struct sea_stats sea;
+ unsigned int boats_to_be_built, shortage;
+ struct city *pcity = NULL;
+
+ /* Find an unprocessed coastal city;
+ * such a city is on the shore of an unprocessed ocean. */
+ city_list_iterate(pplayer->cities, acity) {
+ if (get_city_ferry_mode(acity) == CFM_UNPROCESSED
+ && is_ocean_near_tile(acity->tile)) {
+ pcity = acity;
+ break;
+ }
+ } city_list_iterate_end;
+
+ if (!pcity) {/*no more oceans*/
+ break;
+ }
+
+ /* Get a map of the sea plus shore accessible from pcity*/
+ /* If the city is adjacent to more than one ocean,
+ * or oceans are accessible from the city through channels in allied
+ * cities, this processes all those oceans as one sea.*/
+ parameter.start_tile = pcity->tile;
+ pfmap = pf_create_map(¶meter);
+
+ /* Part 1: measure the demand for boats for this ocean*/
+ sea_examine_sea(pplayer, &sea, pfmap);
+
+ pf_destroy_map(pfmap);
+
+ freelog(LOGLEVEL_BUILDFERRY, "Sea near %s's %s: %d/%d boats, "
+ "%d+%d/%d waiting, want %d", pplayer->name, pcity->name,
+ sea.avail_boats, sea.boats, sea.psngrs, sea.future_psngrs,
+ sea.n_cities, sea.ferry_want);
+
+ /* Part 2: Decide how many boats we want built */
+ boats_to_be_built = new_boats_to_build(&sea);
+ freelog(LOGLEVEL_BUILDFERRY,
+ "Sea near %s's %s: should build %d boats",
+ pplayer->name, pcity->name, boats_to_be_built);
+ shortage = 0 < boats_to_be_built;
+
+ /* Part 3: Decide where to build the boats */
+ select_ferry_builders(pplayer, boats_to_be_built, boattype);
+ adjust_wants(pplayer, shortage, sea.ferry_want);
+
+ /* Part 4: Cleanup */
+ city_list_iterate(pplayer->cities, acity) {
+ if (get_city_ferry_mode(acity) == CFM_COUNTED
+ || get_city_ferry_mode(acity) == CFM_BUILDING) {
+ set_city_ferry_mode(acity, CFM_DONE);
+ }
+ } city_list_iterate_end;
+
+ inf_loop_guard--;
+ } while(inf_loop_guard > 0);
+}
Index: ai/aiferry.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/aiferry.h,v
retrieving revision 1.3
diff -u -r1.3 aiferry.h
--- ai/aiferry.h 29 Sep 2004 02:24:18 -0000 1.3
+++ ai/aiferry.h 12 Nov 2004 05:42:02 -0000
@@ -48,4 +48,10 @@
*/
void ai_manage_ferryboat(struct player *pplayer, struct unit *punit);
+/*
+ * A function for a centralized (i.e. per-civilization rather than per-city
+ * estimation of need to build more ferries and where to build them
+ */
+void aiferry_choose_build_global(struct player *pplayer);
+
#endif /* FC__AIFERRY_H */
Index: common/city.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/city.h,v
retrieving revision 1.166
diff -u -r1.166 city.h
--- common/city.h 10 Nov 2004 17:01:59 -0000 1.166
+++ common/city.h 12 Nov 2004 05:42:02 -0000
@@ -161,6 +161,16 @@
#define ASSERT_REAL_CHOICE_TYPE(type) \
assert(type >= 0 && type < CT_LAST /* && type != CT_NONE */ );
+/*
+ * Used while determining how many and where to build ferries.
+ */
+enum city_ferry_mode {
+ CFM_UNPROCESSED,
+ CFM_COUNTED,
+ CFM_BUILDING,
+ CFM_DONE
+};
+
struct ai_choice {
int choice; /* what the advisor wants */
@@ -212,6 +222,7 @@
int worth; /* Cache city worth here, sum of all weighted incomes */
int next_recalc; /* Only recalc every Nth turn */
+ enum city_ferry_mode ferry_mode;
};
struct city {
Index: common/aicore/pf_tools.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/aicore/pf_tools.c,v
retrieving revision 1.24
diff -u -r1.24 pf_tools.c
--- common/aicore/pf_tools.c 20 Oct 2004 18:20:53 -0000 1.24
+++ common/aicore/pf_tools.c 12 Nov 2004 05:42:02 -0000
@@ -80,9 +80,9 @@
anywhere, unless we are leaving a friendly city, in which
case we can move into the ocean but not into the land.
************************************************************/
-static int sea_overlap_move(const struct tile *ptile, enum direction8 dir,
- const struct tile *ptile1,
- struct pf_parameter *param)
+int sea_overlap_move(const struct tile *ptile, enum direction8 dir,
+ const struct tile *ptile1,
+ struct pf_parameter *param)
{
if (is_ocean(ptile->terrain)) {
return SINGLE_MOVE;
Index: common/aicore/pf_tools.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/aicore/pf_tools.h,v
retrieving revision 1.8
diff -u -r1.8 pf_tools.h
--- common/aicore/pf_tools.h 29 Sep 2004 02:24:23 -0000 1.8
+++ common/aicore/pf_tools.h 12 Nov 2004 05:42:02 -0000
@@ -29,6 +29,10 @@
enum tile_behavior no_fights(const struct tile *ptile, enum known_type known,
struct pf_parameter *param);
+int sea_overlap_move(const struct tile *ptile, enum direction8 dir,
+ const struct tile *ptile1,
+ struct pf_parameter *param);
+
#define pf_iterator(map, position) { \
struct pf_position position; \
while (pf_next(map)) { \
- [freeciv-ai] Re: (PR#8992) Patch: Building ferries, (continued)
- [freeciv-ai] Re: (PR#8992) Patch: Building ferries, Benedict Adamson, 2004/11/05
- [freeciv-ai] Re: (PR#8992) Patch: Building ferries, Gregory Berkolaiko, 2004/11/04
- [freeciv-ai] Re: (PR#8992) Patch: Building ferries, Per I. Mathisen, 2004/11/05
- [freeciv-ai] Re: (PR#8992) Patch: Building ferries, Benedict Adamson, 2004/11/05
- [freeciv-ai] Re: (PR#8992) Patch: Building ferries, Benedict Adamson, 2004/11/05
[freeciv-ai] Re: (PR#8992) Patch: Building ferries, Benedict Adamson, 2004/11/05
|
|