[freeciv-ai] Re: (PR#6199) even huger fstk/ksw/paw/ferry cleanup
[Top] [All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
On Mon, 29 Sep 2003, Gregory Berkolaiko wrote:
> I will describe the path-finding below, but first I want to advertise it a
> little bit. It's for finding paths to locations on other continents
> assuming our (land) unit is in a port or on a ferry. It will find
> beachheads automatically and the best ones at that (not just 95% best).
> It will be possible to read off exact time to destintation off this map.
>
> We construct a map of paths going over water and then over land by using a
> mixed move_cost function. Unfortunately, the move rates of this pseudo
> unit over land and over sea are different. So we will record the move
> costs over sea in extra_cost and over land in normal cost.
>
> TB-callback:
> do not attack units on sea squares
>
> EC-callback:
> on sea squares return
> SINGLE_MOVE * PF_TURN_FACTOR / ferry_move_rate
> otherwise 0
> /* The rescaling is to make get_total_CC compare the cost properly,
> * 1 turn of ferry == 1 turn over land */
>
> cost-callback:
> move to land
> return normal cost
> move sea to sea
> return 0
> move land to sea
> return INFINITY
>
>
> then to estimate turns to destination use
> pos.turns + pos.total_EC / PF_TURN_FACTOR
>
>
> In fact, it all looks so simple I will do it for rampage off the boat.
And I did. And it works. Try the attached patch on the attached
savegame, login as pille, start, make Pille AI, and hit turn-done button.
See the path for the rampage attack!
Now, if we do fstk properly in this fashion it will make rampage
unnecessary, since it will find all the same great targets but will go
further if necessary. Even now, fstk finds the empty cities [1], but not
if they were moved inside the continent (I really need to build CivWorld for
making these fun savegames).
So this patch is really just a proof-of-concept.
G.
[1] And definitely gets them with my ferry-patch.
mmm.gz
Description: mmm.gz
? mmm.gz
? ttt.gz
Index: ai/aitools.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/aitools.c,v
retrieving revision 1.92
diff -u -r1.92 aitools.c
--- ai/aitools.c 2003/09/28 01:04:59 1.92
+++ ai/aitools.c 2003/09/29 18:23:43
@@ -117,7 +117,20 @@
if (i == path->length - 1) {
result = ai_unit_attack(punit, x, y);
} else {
- ai_unit_move(punit, x, y);
+
+ if (is_ground_unit(punit) && is_ocean(map_get_tile(x, y)->terrain)
+ && find_unit_by_id(punit->transported_by)) {
+ /* Our ferry is the one who will do the move */
+ struct unit *ferry = find_unit_by_id(punit->transported_by);
+
+ if (ferry->owner == punit->owner) {
+ /* Otherwise might end up driving human ally's transport */
+ ai_unit_move(ferry, x, y);
+ }
+ } else {
+ ai_unit_move(punit, x, y);
+ }
+
result = (find_unit_by_id(id) != NULL);
}
if (!result) {
Index: ai/aiunit.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/aiunit.c,v
retrieving revision 1.297
diff -u -r1.297 aiunit.c
--- ai/aiunit.c 2003/09/28 09:33:21 1.297
+++ ai/aiunit.c 2003/09/29 18:23:43
@@ -1001,6 +1001,94 @@
return 0;
}
+/****************************************************************************
+ Combined cost function for a land unit on a ferry, taking into account
+ possibilities of attacking on land. For movements sea-to-sea the cost is
+ collected via the extra cost call-back.
+****************************************************************************/
+static int combined_land_attack_move(int x, int y, enum direction8 dir,
+ int x1, int y1,
+ struct pf_parameter *param)
+{
+ struct tile *src_tile = map_get_tile(x, y);
+ struct tile *tgt_tile = map_get_tile(x1, y1);
+ int move_cost;
+
+ if (is_ocean(tgt_tile->terrain)) {
+
+ /* Any-to-Sea */
+ if(is_ocean(src_tile->terrain)) {
+ move_cost = 0;
+ } else {
+ move_cost = PF_IMPOSSIBLE_MC;
+ }
+ } else if (src_tile->terrain == T_OCEAN) {
+
+ /* Sea-to-Land. */
+ if (!is_non_allied_unit_tile(tgt_tile, param->owner)
+ && !is_non_allied_city_tile(tgt_tile, param->owner)) {
+ move_cost
+ = get_tile_type(tgt_tile->terrain)->movement_cost * SINGLE_MOVE;
+ } else if (BV_ISSET(param->unit_flags, F_MARINES)) {
+ /* Can attack!! */
+ move_cost = SINGLE_MOVE;
+ } else {
+ move_cost = PF_IMPOSSIBLE_MC;
+ }
+ } else {
+
+ /* Land-to-Land */
+ if (is_non_allied_unit_tile(src_tile, param->owner)) {
+ /* Cannot pass through defended tiles */
+ move_cost = PF_IMPOSSIBLE_MC;
+ } else if (is_non_allied_unit_tile(tgt_tile, param->owner)) {
+
+ /* Attack! */
+ move_cost = SINGLE_MOVE;
+ } else {
+ /* Normal move */
+ move_cost = src_tile->move_cost[dir];
+ }
+ }
+
+ return move_cost;
+}
+
+/****************************************************************************
+ TB callback to prohibit attacking anyone on water.
+****************************************************************************/
+static enum tile_behavior no_fights_on_sea(int x, int y,
+ enum known_type known,
+ struct pf_parameter *param)
+{
+ struct tile *ptile = map_get_tile(x, y);
+
+ if (is_ocean(ptile->terrain)
+ && (is_non_allied_unit_tile(ptile, param->owner)
+ || is_non_allied_city_tile(ptile, param->owner))) {
+ /* Can't attack */
+ return TB_IGNORE;
+ }
+ return TB_NORMAL;
+}
+
+/****************************************************************************
+ EC callback to account for the cost of sea moves by a unit carried by a
+ ferry. To use we need to put the ferry move_rate into the data field of
+ param.
+****************************************************************************/
+static int sea_move(int x, int y, enum known_type known,
+ struct pf_parameter *param)
+{
+ int moverate = *(int *)(param->data);
+
+ if (is_ocean(map_get_tile(x, y)->terrain)) {
+ return SINGLE_MOVE * PF_TURN_FACTOR / moverate;
+ } else {
+ return 0;
+ }
+}
+
/*************************************************************************
Look for worthy targets within a one-turn horizon.
*************************************************************************/
@@ -1015,9 +1103,32 @@
/* Want of the best target */
int max_want = 0;
struct player *pplayer = unit_owner(punit);
-
+ bool combined = FALSE;
+ static int ferry_rate = 0;
+
pft_fill_default_parameter(¶meter);
pft_fill_unit_attack_param(¶meter, punit);
+ if (punit->transported_by > 0) {
+ struct unit *ferry = find_unit_by_id(punit->transported_by);
+
+ if (ferry->ai.passenger != punit->id) {
+ /* We are not the boss of the boat we are in */
+ // return NULL;
+ }
+ combined = TRUE;
+ /* TODO: Make pft_fill_unit_default_parameter */
+ parameter.turn_mode = TM_WORST_TIME;
+ parameter.get_TB = no_fights_on_sea;
+ parameter.get_EC = sea_move;
+ parameter.get_MC = combined_land_attack_move;
+ if (!unit_flag(punit, F_IGZOC)) {
+ parameter.get_zoc = is_my_zoc;
+ } else {
+ parameter.get_zoc = NULL;
+ }
+ ferry_rate = ferry->moves_left;
+ parameter.data = &ferry_rate;
+ }
tgt_map = pf_create_map(¶meter);
while (pf_next(tgt_map)) {
@@ -1028,8 +1139,17 @@
pf_next_get_position(tgt_map, &pos);
- if (pos.total_MC > punit->moves_left) {
- /* This is too far */
+ if (combined) {
+ if (pos.turn > 0 && pos.total_EC / PF_TURN_FACTOR > 0) {
+ /* Too far, time to break the PF */
+ break;
+ }
+ if (pos.turn > 0 || pos.total_EC / PF_TURN_FACTOR > 0) {
+ /* Too far, but might still discover good places */
+ continue;
+ }
+ } else if (pos.total_MC > punit->moves_left) {
+ /* Too far, time to break the PF */
break;
}
@@ -1059,7 +1179,11 @@
if (max_want > 0) {
/* We found something */
+ UNIT_LOG(LOG_NORMAL, punit,
+ "wants to rampage (%d,%d); want %d, thresh %d/%d",
+ x, y, max_want, thresh_adj, thresh_move);
path = pf_get_path(tgt_map, x, y);
+ pf_print_path(LOG_NORMAL, path);
assert(path);
}
|
|