1 /**********************************************************************
2 Freeciv - Copyright (C) 2003 - The Freeciv Project
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 2, or (at your option)
6 any later version.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12 ***********************************************************************/
13
14 #ifdef HAVE_CONFIG_H
15 #include <fc_config.h>
16 #endif
17
18 /* utility */
19 #include "bitvector.h"
20 #include "log.h"
21 #include "mem.h"
22 #include "support.h"
23
24 /* common */
25 #include "game.h"
26 #include "map.h"
27 #include "movement.h"
28
29 /* common/aicore */
30 #include "pf_tools.h"
31
32 #include "path_finding.h"
33
34 /* For explanations on how to use this module, see "path_finding.h". */
35
36 #define SPECPQ_TAG map_index
37 #define SPECPQ_DATA_TYPE int
38 #define SPECPQ_PRIORITY_TYPE int
39 #include "specpq.h"
40 #define INITIAL_QUEUE_SIZE 100
41
42 #ifdef DEBUG
43 /* Extra checks for debugging. */
44 #define PF_DEBUG
45 #endif
46
47 /* ======================== Internal structures ========================== */
48
49 #ifdef PF_DEBUG
50 /* The mode we use the pf_map. Used for cast converion checks. */
51 enum pf_mode {
52 PF_NORMAL = 1, /* Usual goto */
53 PF_DANGER, /* Goto with dangerous positions */
54 PF_FUEL /* Goto for fueled units */
55 };
56 #endif /* PF_DEBUG */
57
58 enum pf_node_status {
59 NS_UNINIT = 0, /* memory is calloced, hence zero means
60 * uninitialised. */
61 NS_INIT, /* node initialized, but we didn't search a route
62 * yet. */
63 NS_NEW, /* the optimal route isn't found yet. */
64 NS_WAITING, /* the optimal route is found, considering waiting.
65 * Only used for pf_danger_map and pf_fuel_map, it
66 * means we are waiting on a safe place for full
67 * moves before crossing a dangerous area. */
68 NS_PROCESSED /* the optimal route is found. */
69 };
70
71 enum pf_zoc_type {
72 ZOC_MINE = 0, /* My ZoC. */
73 ZOC_ALLIED, /* Allied ZoC. */
74 ZOC_NO /* No ZoC. */
75 };
76
77 /* Abstract base class for pf_normal_map, pf_danger_map, and pf_fuel_map. */
78 struct pf_map {
79 #ifdef PF_DEBUG
80 enum pf_mode mode; /* The mode of the map, for conversion checking. */
81 #endif /* PF_DEBUG */
82
83 /* "Virtual" function table. */
84 void (*destroy) (struct pf_map *pfm); /* Destructor. */
85 int (*get_move_cost) (struct pf_map *pfm, struct tile *ptile);
86 struct pf_path * (*get_path) (struct pf_map *pfm, struct tile *ptile);
87 bool (*get_position) (struct pf_map *pfm, struct tile *ptile,
88 struct pf_position *pos);
89 bool (*iterate) (struct pf_map *pfm);
90
91 /* Private data. */
92 struct tile *tile; /* The current position (aka iterator). */
93 struct pf_parameter params; /* Initial parameters. */
94 };
95
96 /* Down-cast macro. */
97 #define PF_MAP(pfm) ((struct pf_map *) (pfm))
98
99 /* ========================== Common functions =========================== */
100
101 /****************************************************************************
102 Return the number of "moves" started with.
103
104 This is different from the moves_left_initially because of fuel. For
105 units with fuel > 1 all moves on the same tank of fuel are considered to
106 be one turn. Thus the rest of the PF code doesn't actually know that the
107 unit has fuel, it just thinks it has that many more MP.
108 ****************************************************************************/
pf_moves_left_initially(const struct pf_parameter * param)109 static inline int pf_moves_left_initially(const struct pf_parameter *param)
110 {
111 return (param->moves_left_initially
112 + (param->fuel_left_initially - 1) * param->move_rate);
113 }
114
115 /****************************************************************************
116 Return the "move rate".
117
118 This is different from the parameter's move_rate because of fuel. For
119 units with fuel > 1 all moves on the same tank of fuel are considered
120 to be one turn. Thus the rest of the PF code doesn't actually know that
121 the unit has fuel, it just thinks it has that many more MP.
122 ****************************************************************************/
pf_move_rate(const struct pf_parameter * param)123 static inline int pf_move_rate(const struct pf_parameter *param)
124 {
125 return param->move_rate * param->fuel;
126 }
127
128 /****************************************************************************
129 Number of turns required to reach node. See comment in the body of
130 pf_normal_map_new(), pf_danger_map_new(), and pf_fuel_map_new() functions
131 about the usage of moves_left_initially().
132 ****************************************************************************/
pf_turns(const struct pf_parameter * param,int cost)133 static inline int pf_turns(const struct pf_parameter *param, int cost)
134 {
135 /* Negative cost can happen when a unit initially has more MP than its
136 * move-rate (due to wonders transfer etc). Although this may be a bug,
137 * we'd better be ready.
138 *
139 * Note that cost == 0 corresponds to the current turn with full MP. */
140 if (param->fuel_left_initially < param->fuel) {
141 cost -= (param->fuel - param->fuel_left_initially) * param->move_rate;
142 }
143 if (cost <= 0) {
144 return 0;
145 } else if (param->move_rate <= 0) {
146 return FC_INFINITY; /* This unit cannot move by itself. */
147 } else {
148 return cost / param->move_rate;
149 }
150 }
151
152 /****************************************************************************
153 Moves left after node is reached.
154 ****************************************************************************/
pf_moves_left(const struct pf_parameter * param,int cost)155 static inline int pf_moves_left(const struct pf_parameter *param, int cost)
156 {
157 int move_rate = pf_move_rate(param);
158
159 /* Cost may be negative; see pf_turns(). */
160 if (cost <= 0) {
161 return move_rate - cost;
162 } else if (move_rate <= 0) {
163 return 0; /* This unit never have moves left. */
164 } else {
165 return move_rate - (cost % move_rate);
166 }
167 }
168
169 /****************************************************************************
170 Obtain cost-of-path from pure cost and extra cost
171 ****************************************************************************/
pf_total_CC(const struct pf_parameter * param,int cost,int extra)172 static inline int pf_total_CC(const struct pf_parameter *param,
173 int cost, int extra)
174 {
175 return PF_TURN_FACTOR * cost + extra * pf_move_rate(param);
176 }
177
178 /****************************************************************************
179 Take a position previously filled out (as by fill_position) and "finalize"
180 it by reversing all fuel multipliers.
181
182 See pf_moves_left_initially() and pf_move_rate().
183 ****************************************************************************/
pf_finalize_position(const struct pf_parameter * param,struct pf_position * pos)184 static inline void pf_finalize_position(const struct pf_parameter *param,
185 struct pf_position *pos)
186 {
187 int move_rate = param->move_rate;
188
189 if (0 < move_rate) {
190 pos->moves_left %= move_rate;
191 }
192 }
193
194 static struct pf_path *
195 pf_path_new_to_start_tile(const struct pf_parameter *param);
196 static void pf_position_fill_start_tile(struct pf_position *pos,
197 const struct pf_parameter *param);
198
199
200 /* ================ Specific pf_normal_* mode structures ================= */
201
202 /* Normal path-finding maps are used for most of units with standard rules.
203 * See what units make pf_map_new() to pick danger or fuel maps instead. */
204
205 /* Node definition. Note we try to have the smallest data as possible. */
206 struct pf_normal_node {
207 signed short cost; /* total_MC. 'cost' may be negative, see comment in
208 * pf_turns(). */
209 unsigned extra_cost; /* total_EC. Can be huge, (higher than 'cost'). */
210 unsigned dir_to_here : 4; /* Direction from which we came. It's
211 * an 'enum direction8' including
212 * possibility of direction8_invalid (so we need
213 * 4 bits) */
214 unsigned status : 3; /* 'enum pf_node_status' really. */
215
216 /* Cached values */
217 unsigned move_scope : 3; /* 'enum pf_move_scope really. */
218 unsigned action : 2; /* 'enum pf_action really. */
219 unsigned node_known_type : 2; /* 'enum known_type' really. */
220 unsigned behavior : 2; /* 'enum tile_behavior' really. */
221 unsigned zoc_number : 2; /* 'enum pf_zoc_type' really. */
222 unsigned short extra_tile; /* EC */
223 };
224
225 /* Derived structure of struct pf_map. */
226 struct pf_normal_map {
227 struct pf_map base_map; /* Base structure, must be the first! */
228
229 struct map_index_pq *queue; /* Queue of nodes we have reached but not
230 * processed yet (NS_NEW), sorted by their
231 * total_CC. */
232 struct pf_normal_node *lattice; /* Lattice of nodes. */
233 };
234
235 /* Up-cast macro. */
236 #ifdef PF_DEBUG
237 static inline struct pf_normal_map *
pf_normal_map_check(struct pf_map * pfm,const char * file,const char * function,int line)238 pf_normal_map_check(struct pf_map *pfm, const char *file,
239 const char *function, int line)
240 {
241 fc_assert_full(file, function, line,
242 NULL != pfm && PF_NORMAL == pfm->mode,
243 return NULL, "Wrong pf_map to pf_normal_map conversion.");
244 return (struct pf_normal_map *) pfm;
245 }
246 #define PF_NORMAL_MAP(pfm) \
247 pf_normal_map_check(pfm, __FILE__, __FUNCTION__, __FC_LINE__)
248 #else
249 #define PF_NORMAL_MAP(pfm) ((struct pf_normal_map *) (pfm))
250 #endif /* PF_DEBUG */
251
252 /* ================ Specific pf_normal_* mode functions ================= */
253
254 /****************************************************************************
255 Calculates cached values of the target node. Set the node status to
256 NS_INIT to avoid recalculating all values. Returns FALSE if we cannot
257 enter node (in this case, most of the cached values are not set).
258 ****************************************************************************/
pf_normal_node_init(struct pf_normal_map * pfnm,struct pf_normal_node * node,struct tile * ptile,enum pf_move_scope previous_scope)259 static inline bool pf_normal_node_init(struct pf_normal_map *pfnm,
260 struct pf_normal_node *node,
261 struct tile *ptile,
262 enum pf_move_scope previous_scope)
263 {
264 const struct pf_parameter *params = pf_map_parameter(PF_MAP(pfnm));
265 enum known_type node_known_type;
266 enum pf_action action;
267
268 #ifdef PF_DEBUG
269 fc_assert(NS_UNINIT == node->status);
270 /* Else, not a critical problem, but waste of time. */
271 #endif
272
273 node->status = NS_INIT;
274
275 /* Establish the "known" status of node. */
276 if (params->omniscience) {
277 node_known_type = TILE_KNOWN_SEEN;
278 } else {
279 node_known_type = tile_get_known(ptile, params->owner);
280 }
281 node->node_known_type = node_known_type;
282
283 /* Establish the tile behavior. */
284 if (NULL != params->get_TB) {
285 node->behavior = params->get_TB(ptile, node_known_type, params);
286 if (TB_IGNORE == node->behavior && params->start_tile != ptile) {
287 return FALSE;
288 }
289 #ifdef ZERO_VARIABLES_FOR_SEARCHING
290 } else {
291 /* The default. */
292 node->behavior = TB_NORMAL;
293 #endif
294 }
295
296 if (TILE_UNKNOWN != node_known_type) {
297 bool can_disembark;
298
299 /* Test if we can invade tile. */
300 if (!utype_has_flag(params->utype, UTYF_CIVILIAN)
301 && !player_can_invade_tile(params->owner, ptile)) {
302 /* Maybe overwrite node behavior. */
303 if (params->start_tile != ptile) {
304 node->behavior = TB_IGNORE;
305 return FALSE;
306 } else if (TB_NORMAL == node->behavior) {
307 node->behavior = TB_IGNORE;
308 }
309 }
310
311 /* Test the possibility to perform an action. */
312 if (NULL != params->get_action) {
313 action = params->get_action(ptile, node_known_type, params);
314 if (PF_ACTION_IMPOSSIBLE == action) {
315 /* Maybe overwrite node behavior. */
316 if (params->start_tile != ptile) {
317 node->behavior = TB_IGNORE;
318 return FALSE;
319 } else if (TB_NORMAL == node->behavior) {
320 node->behavior = TB_IGNORE;
321 }
322 action = PF_ACTION_NONE;
323 } else if (PF_ACTION_NONE != action
324 && TB_DONT_LEAVE != node->behavior) {
325 /* Overwrite node behavior. */
326 node->behavior = TB_DONT_LEAVE;
327 }
328 node->action = action;
329 #ifdef ZERO_VARIABLES_FOR_SEARCHING
330 } else {
331 /* Nodes are allocated by fc_calloc(), so should be already set to
332 * 0. */
333 node->action = PF_ACTION_NONE;
334 #endif
335 }
336
337 /* Test the possibility to move from/to 'ptile'. */
338 node->move_scope = params->get_move_scope(ptile, &can_disembark,
339 previous_scope, params);
340 if (PF_MS_NONE == node->move_scope
341 && PF_ACTION_NONE == node->action
342 && params->ignore_none_scopes) {
343 /* Maybe overwrite node behavior. */
344 if (params->start_tile != ptile) {
345 node->behavior = TB_IGNORE;
346 return FALSE;
347 } else if (TB_NORMAL == node->behavior) {
348 node->behavior = TB_IGNORE;
349 }
350 } else if (PF_MS_TRANSPORT == node->move_scope
351 && !can_disembark
352 && (params->start_tile != ptile
353 || NULL == params->transported_by_initially)) {
354 /* Overwrite node behavior. */
355 node->behavior = TB_DONT_LEAVE;
356 }
357
358 /* ZOC_MINE means can move unrestricted from/into it, ZOC_ALLIED means
359 * can move unrestricted into it, but not necessarily from it. */
360 if (NULL != params->get_zoc
361 && NULL == tile_city(ptile)
362 && !terrain_has_flag(tile_terrain(ptile), TER_NO_ZOC)
363 && !params->get_zoc(params->owner, ptile)) {
364 node->zoc_number = (0 < unit_list_size(ptile->units)
365 ? ZOC_ALLIED : ZOC_NO);
366 #ifdef ZERO_VARIABLES_FOR_SEARCHING
367 } else {
368 /* Nodes are allocated by fc_calloc(), so should be already set to
369 * 0. */
370 node->zoc_number = ZOC_MINE;
371 #endif
372 }
373 } else {
374 node->move_scope = PF_MS_NATIVE;
375 #ifdef ZERO_VARIABLES_FOR_SEARCHING
376 /* Nodes are allocated by fc_calloc(), so should be already set to 0. */
377 node->action = PF_ACTION_NONE;
378 node->zoc_number = ZOC_MINE;
379 #endif
380 }
381
382 /* Evaluate the extra cost of the destination */
383 if (NULL != params->get_EC) {
384 node->extra_tile = params->get_EC(ptile, node_known_type, params);
385 #ifdef ZERO_VARIABLES_FOR_SEARCHING
386 } else {
387 /* Nodes are allocated by fc_calloc(), so should be already set to 0. */
388 node->extra_tile = 0;
389 #endif
390 }
391
392 return TRUE;
393 }
394
395 /****************************************************************************
396 Fill in the position which must be discovered already. A helper
397 for pf_normal_map_position(). This also "finalizes" the position.
398 ****************************************************************************/
pf_normal_map_fill_position(const struct pf_normal_map * pfnm,struct tile * ptile,struct pf_position * pos)399 static void pf_normal_map_fill_position(const struct pf_normal_map *pfnm,
400 struct tile *ptile,
401 struct pf_position *pos)
402 {
403 int tindex = tile_index(ptile);
404 struct pf_normal_node *node = pfnm->lattice + tindex;
405 const struct pf_parameter *params = pf_map_parameter(PF_MAP(pfnm));
406
407 #ifdef PF_DEBUG
408 fc_assert_ret_msg(NS_PROCESSED == node->status,
409 "Unreached destination (%d, %d).", TILE_XY(ptile));
410 #endif /* PF_DEBUG */
411
412 pos->tile = ptile;
413 pos->total_EC = node->extra_cost;
414 pos->total_MC = (node->cost - pf_move_rate(params)
415 + pf_moves_left_initially(params));
416 pos->turn = pf_turns(params, node->cost);
417 pos->moves_left = pf_moves_left(params, node->cost);
418 #ifdef PF_DEBUG
419 fc_assert(params->fuel == 1);
420 fc_assert(params->fuel_left_initially == 1);
421 #endif /* PF_DEBUG */
422 pos->fuel_left = 1;
423 pos->dir_to_here = node->dir_to_here;
424 pos->dir_to_next_pos = direction8_invalid(); /* This field does not apply. */
425
426 if (node->cost > 0) {
427 pf_finalize_position(params, pos);
428 }
429 }
430
431 /****************************************************************************
432 Read off the path to the node dest_tile, which must already be discovered.
433 A helper for pf_normal_map_path functions.
434 ****************************************************************************/
435 static struct pf_path *
pf_normal_map_construct_path(const struct pf_normal_map * pfnm,struct tile * dest_tile)436 pf_normal_map_construct_path(const struct pf_normal_map *pfnm,
437 struct tile *dest_tile)
438 {
439 struct pf_normal_node *node = pfnm->lattice + tile_index(dest_tile);
440 const struct pf_parameter *params = pf_map_parameter(PF_MAP(pfnm));
441 enum direction8 dir_next = direction8_invalid();
442 struct pf_path *path;
443 struct tile *ptile;
444 int i;
445
446 #ifdef PF_DEBUG
447 fc_assert_ret_val_msg(NS_PROCESSED == node->status, NULL,
448 "Unreached destination (%d, %d).",
449 TILE_XY(dest_tile));
450 #endif /* PF_DEBUG */
451
452 ptile = dest_tile;
453 path = fc_malloc(sizeof(*path));
454
455 /* 1: Count the number of steps to get here.
456 * To do it, backtrack until we hit the starting point */
457 for (i = 0; ; i++) {
458 if (ptile == params->start_tile) {
459 /* Ah-ha, reached the starting point! */
460 break;
461 }
462
463 ptile = mapstep(ptile, DIR_REVERSE(node->dir_to_here));
464 node = pfnm->lattice + tile_index(ptile);
465 }
466
467 /* 2: Allocate the memory */
468 path->length = i + 1;
469 path->positions = fc_malloc((i + 1) * sizeof(*(path->positions)));
470
471 /* 3: Backtrack again and fill the positions this time */
472 ptile = dest_tile;
473 node = pfnm->lattice + tile_index(ptile);
474
475 for (; i >= 0; i--) {
476 pf_normal_map_fill_position(pfnm, ptile, &path->positions[i]);
477 /* fill_position doesn't set direction */
478 path->positions[i].dir_to_next_pos = dir_next;
479
480 dir_next = node->dir_to_here;
481
482 if (i > 0) {
483 /* Step further back, if we haven't finished yet */
484 ptile = mapstep(ptile, DIR_REVERSE(dir_next));
485 node = pfnm->lattice + tile_index(ptile);
486 }
487 }
488
489 return path;
490 }
491
492 /****************************************************************************
493 Adjust MC to reflect the move_rate.
494 ****************************************************************************/
pf_normal_map_adjust_cost(int cost,int moves_left)495 static int pf_normal_map_adjust_cost(int cost, int moves_left)
496 {
497 return MIN(cost, moves_left);
498 }
499
500 /****************************************************************************
501 Bare-bones PF iterator. All Freeciv rules logic is hidden in 'get_costs'
502 callback (compare to pf_normal_map_iterate function). This function is
503 called when the pf_map was created with a 'get_cost' callback.
504
505 Plan: 1. Process previous position.
506 2. Get new nearest position and return it.
507
508 During the iteration, the node status will be changed:
509 A. NS_UNINIT: The node is not initialized, we didn't reach it at all.
510 (NS_INIT not used here)
511 B. NS_NEW: We have reached this node, but we are not sure it was the best
512 path.
513 (NS_WAITING not used here)
514 C. NS_PROCESSED: Now, we are sure we have the best path. Then, we won't
515 do anything more with this node.
516 ****************************************************************************/
pf_jumbo_map_iterate(struct pf_map * pfm)517 static bool pf_jumbo_map_iterate(struct pf_map *pfm)
518 {
519 struct pf_normal_map *pfnm = PF_NORMAL_MAP(pfm);
520 struct tile *tile = pfm->tile;
521 int tindex = tile_index(tile);
522 struct pf_normal_node *node = pfnm->lattice + tindex;
523 const struct pf_parameter *params = pf_map_parameter(pfm);
524
525 /* Processing Stage */
526
527 /* The previous position is defined by 'tile' (tile pointer), 'node'
528 * (the data of the tile for the pf_map), and index (the index of the
529 * position in the Freeciv map). */
530
531 adjc_dir_iterate(tile, tile1, dir) {
532 /* Calculate the cost of every adjacent position and set them in the
533 * priority queue for next call to pf_jumbo_map_iterate(). */
534 int tindex1 = tile_index(tile1);
535 struct pf_normal_node *node1 = pfnm->lattice + tindex1;
536 int priority, cost1, extra_cost1;
537
538 /* As for the previous position, 'tile1', 'node1' and 'tindex1' are
539 * defining the adjacent position. */
540
541 if (node1->status == NS_PROCESSED) {
542 /* This gives 15% speedup */
543 continue;
544 }
545
546 if (NS_UNINIT == node1->status) {
547 /* Set cost as impossible for initializing, params->get_costs(), will
548 * overwrite with the right value. */
549 cost1 = PF_IMPOSSIBLE_MC;
550 extra_cost1 = 0;
551 } else {
552 cost1 = node1->cost;
553 extra_cost1 = node1->extra_cost;
554 }
555
556 /* User-supplied callback 'get_costs' takes care of everything (ZOC,
557 * known, costs etc). See explanations in "path_finding.h". */
558 priority = params->get_costs(tile, dir, tile1, node->cost,
559 node->extra_cost, &cost1,
560 &extra_cost1, params);
561 if (priority >= 0) {
562 /* We found a better route to 'tile1', record it (the costs are
563 * recorded already). Node status step A. to B. */
564 if (NS_NEW == node1->status) {
565 map_index_pq_replace(pfnm->queue, tindex1, -priority);
566 } else {
567 map_index_pq_insert(pfnm->queue, tindex1, -priority);
568 }
569 node1->cost = cost1;
570 node1->extra_cost = extra_cost1;
571 node1->status = NS_NEW;
572 node1->dir_to_here = dir;
573 }
574 } adjc_dir_iterate_end;
575
576 /* Get the next node (the index with the highest priority). */
577 if (!map_index_pq_remove(pfnm->queue, &tindex)) {
578 /* No more indexes in the priority queue, iteration end. */
579 return FALSE;
580 }
581
582 #ifdef PF_DEBUG
583 fc_assert(NS_NEW == pfnm->lattice[tindex].status);
584 #endif
585
586 /* Change the pf_map iterator. Node status step B. to C. */
587 pfm->tile = index_to_tile(tindex);
588 pfnm->lattice[tindex].status = NS_PROCESSED;
589
590 return TRUE;
591 }
592
593 /****************************************************************************
594 Primary method for iterative path-finding.
595
596 Plan: 1. Process previous position.
597 2. Get new nearest position and return it.
598
599 During the iteration, the node status will be changed:
600 A. NS_UNINIT: The node is not initialized, we didn't reach it at all.
601 B. NS_INIT: We have initialized the cached values, however, we failed to
602 reach this node.
603 C. NS_NEW: We have reached this node, but we are not sure it was the best
604 path.
605 (NS_WAITING not used here)
606 D. NS_PROCESSED: Now, we are sure we have the best path. Then, we won't
607 do anything more with this node.
608 ****************************************************************************/
pf_normal_map_iterate(struct pf_map * pfm)609 static bool pf_normal_map_iterate(struct pf_map *pfm)
610 {
611 struct pf_normal_map *pfnm = PF_NORMAL_MAP(pfm);
612 struct tile *tile = pfm->tile;
613 int tindex = tile_index(tile);
614 struct pf_normal_node *node = pfnm->lattice + tindex;
615 const struct pf_parameter *params = pf_map_parameter(pfm);
616 int cost_of_path;
617 enum pf_move_scope scope = node->move_scope;
618
619 /* There is no exit from DONT_LEAVE tiles! */
620 if (node->behavior != TB_DONT_LEAVE
621 && scope != PF_MS_NONE
622 && (params->move_rate > 0 || node->cost < 0)) {
623 /* Processing Stage */
624
625 /* The previous position is defined by 'tile' (tile pointer), 'node'
626 * (the data of the tile for the pf_map), and index (the index of the
627 * position in the Freeciv map). */
628
629 adjc_dir_iterate(tile, tile1, dir) {
630 /* Calculate the cost of every adjacent position and set them in the
631 * priority queue for next call to pf_normal_map_iterate(). */
632 int tindex1 = tile_index(tile1);
633 struct pf_normal_node *node1 = pfnm->lattice + tindex1;
634 int cost;
635 int extra = 0;
636
637 /* As for the previous position, 'tile1', 'node1' and 'tindex1' are
638 * defining the adjacent position. */
639
640 if (node1->status == NS_PROCESSED) {
641 /* This gives 15% speedup. Node status already at step D. */
642 continue;
643 }
644
645 /* Initialise target tile if necessary. */
646 if (node1->status == NS_UNINIT) {
647 /* Only initialize once. See comment for pf_normal_node_init().
648 * Node status step A. to B. */
649 if (!pf_normal_node_init(pfnm, node1, tile1, scope)) {
650 continue;
651 }
652 } else if (TB_IGNORE == node1->behavior) {
653 /* We cannot enter this tile at all! */
654 continue;
655 }
656
657 /* Is the move ZOC-ok? */
658 if (node->zoc_number != ZOC_MINE && node1->zoc_number == ZOC_NO) {
659 continue;
660 }
661
662 /* Evaluate the cost of the move. */
663 if (PF_ACTION_NONE != node1->action) {
664 if (NULL != params->is_action_possible
665 && !params->is_action_possible(tile, scope, tile1, node1->action,
666 params)) {
667 continue;
668 }
669 /* action move cost depends on action and unit type. */
670 if (node1->action == PF_ACTION_ATTACK
671 && (utype_has_flag(params->utype, UTYF_ONEATTACK)
672 || uclass_has_flag(utype_class(params->utype), UCF_MISSILE))) {
673 cost = params->move_rate;
674 } else {
675 cost = SINGLE_MOVE;
676 }
677 } else if (node1->node_known_type == TILE_UNKNOWN) {
678 cost = params->utype->unknown_move_cost;
679 } else {
680 cost = params->get_MC(tile, scope, tile1, node1->move_scope, params);
681 }
682 if (cost < 0) {
683 /* e.g. PF_IMPOSSIBLE_MC */
684 continue;
685 }
686 cost = pf_normal_map_adjust_cost(cost,
687 pf_moves_left(params, node->cost));
688
689 /* Total cost at tile1. Cost may be negative; see pf_turns(). */
690 cost += node->cost;
691
692 /* Evaluate the extra cost if it's relevant */
693 if (NULL != params->get_EC) {
694 extra = node->extra_cost;
695 /* Add the cached value */
696 extra += node1->extra_tile;
697 }
698
699 /* Update costs. */
700 cost_of_path = pf_total_CC(params, cost, extra);
701
702 if (NS_INIT == node1->status) {
703 /* We are reaching this node for the first time. */
704 node1->status = NS_NEW;
705 node1->extra_cost = extra;
706 node1->cost = cost;
707 node1->dir_to_here = dir;
708 /* As we prefer lower costs, let's reverse the cost of the path. */
709 map_index_pq_insert(pfnm->queue, tindex1, -cost_of_path);
710 } else if (cost_of_path < pf_total_CC(params, node1->cost,
711 node1->extra_cost)) {
712 /* We found a better route to 'tile1'. Let's register 'tindex1' to
713 * the priority queue. Node status step B. to C. */
714 node1->status = NS_NEW;
715 node1->extra_cost = extra;
716 node1->cost = cost;
717 node1->dir_to_here = dir;
718 /* As we prefer lower costs, let's reverse the cost of the path. */
719 map_index_pq_replace(pfnm->queue, tindex1, -cost_of_path);
720 }
721 } adjc_dir_iterate_end;
722 }
723
724 /* Get the next node (the index with the highest priority). */
725 if (!map_index_pq_remove(pfnm->queue, &tindex)) {
726 /* No more indexes in the priority queue, iteration end. */
727 return FALSE;
728 }
729
730 #ifdef PF_DEBUG
731 fc_assert(NS_NEW == pfnm->lattice[tindex].status);
732 #endif
733
734 /* Change the pf_map iterator. Node status step C. to D. */
735 pfm->tile = index_to_tile(tindex);
736 pfnm->lattice[tindex].status = NS_PROCESSED;
737
738 return TRUE;
739 }
740
741 /****************************************************************************
742 Iterate the map until 'ptile' is reached.
743 ****************************************************************************/
pf_normal_map_iterate_until(struct pf_normal_map * pfnm,struct tile * ptile)744 static inline bool pf_normal_map_iterate_until(struct pf_normal_map *pfnm,
745 struct tile *ptile)
746 {
747 struct pf_map *pfm = PF_MAP(pfnm);
748 struct pf_normal_node *node = pfnm->lattice + tile_index(ptile);
749
750 if (NULL == pf_map_parameter(pfm)->get_costs) {
751 /* Start position is handled in every function calling this function. */
752 if (NS_UNINIT == node->status) {
753 /* Initialize the node, for doing the following tests. */
754 if (!pf_normal_node_init(pfnm, node, ptile, PF_MS_NONE)) {
755 return FALSE;
756 }
757 } else if (TB_IGNORE == node->behavior) {
758 /* Simpliciation: if we cannot enter this node at all, don't iterate
759 * the whole map. */
760 return FALSE;
761 }
762 } /* Else, this is a jumbo map, not dealing with normal nodes. */
763
764 while (NS_PROCESSED != node->status) {
765 if (!pf_map_iterate(pfm)) {
766 /* All reachable destination have been iterated, 'ptile' is
767 * unreachable. */
768 return FALSE;
769 }
770 }
771
772 return TRUE;
773 }
774
775 /****************************************************************************
776 Return the move cost at ptile. If ptile has not been reached
777 yet, iterate the map until we reach it or run out of map. This function
778 returns PF_IMPOSSIBLE_MC on unreachable positions.
779 ****************************************************************************/
pf_normal_map_move_cost(struct pf_map * pfm,struct tile * ptile)780 static int pf_normal_map_move_cost(struct pf_map *pfm, struct tile *ptile)
781 {
782 struct pf_normal_map *pfnm = PF_NORMAL_MAP(pfm);
783
784 if (ptile == pfm->params.start_tile) {
785 return 0;
786 } else if (pf_normal_map_iterate_until(pfnm, ptile)) {
787 return (pfnm->lattice[tile_index(ptile)].cost
788 - pf_move_rate(pf_map_parameter(pfm))
789 + pf_moves_left_initially(pf_map_parameter(pfm)));
790 } else {
791 return PF_IMPOSSIBLE_MC;
792 }
793 }
794
795 /****************************************************************************
796 Return the path to ptile. If ptile has not been reached yet, iterate the
797 map until we reach it or run out of map.
798 ****************************************************************************/
pf_normal_map_path(struct pf_map * pfm,struct tile * ptile)799 static struct pf_path *pf_normal_map_path(struct pf_map *pfm,
800 struct tile *ptile)
801 {
802 struct pf_normal_map *pfnm = PF_NORMAL_MAP(pfm);
803
804 if (ptile == pfm->params.start_tile) {
805 return pf_path_new_to_start_tile(pf_map_parameter(pfm));
806 } else if (pf_normal_map_iterate_until(pfnm, ptile)) {
807 return pf_normal_map_construct_path(pfnm, ptile);
808 } else {
809 return NULL;
810 }
811 }
812
813 /****************************************************************************
814 Get info about position at ptile and put it in pos. If ptile has not been
815 reached yet, iterate the map until we reach it. Should _always_ check the
816 return value, forthe position might be unreachable.
817 ****************************************************************************/
pf_normal_map_position(struct pf_map * pfm,struct tile * ptile,struct pf_position * pos)818 static bool pf_normal_map_position(struct pf_map *pfm, struct tile *ptile,
819 struct pf_position *pos)
820 {
821 struct pf_normal_map *pfnm = PF_NORMAL_MAP(pfm);
822
823 if (ptile == pfm->params.start_tile) {
824 pf_position_fill_start_tile(pos, pf_map_parameter(pfm));
825 return TRUE;
826 } else if (pf_normal_map_iterate_until(pfnm, ptile)) {
827 pf_normal_map_fill_position(pfnm, ptile, pos);
828 return TRUE;
829 } else {
830 return FALSE;
831 }
832 }
833
834 /****************************************************************************
835 'pf_normal_map' destructor.
836 ****************************************************************************/
pf_normal_map_destroy(struct pf_map * pfm)837 static void pf_normal_map_destroy(struct pf_map *pfm)
838 {
839 struct pf_normal_map *pfnm = PF_NORMAL_MAP(pfm);
840
841 free(pfnm->lattice);
842 map_index_pq_destroy(pfnm->queue);
843 free(pfnm);
844 }
845
846 /****************************************************************************
847 'pf_normal_map' constructor.
848 ****************************************************************************/
pf_normal_map_new(const struct pf_parameter * parameter)849 static struct pf_map *pf_normal_map_new(const struct pf_parameter *parameter)
850 {
851 struct pf_normal_map *pfnm;
852 struct pf_map *base_map;
853 struct pf_parameter *params;
854 struct pf_normal_node *node;
855
856 pfnm = fc_malloc(sizeof(*pfnm));
857 base_map = &pfnm->base_map;
858 params = &base_map->params;
859 #ifdef PF_DEBUG
860 /* Set the mode, used for cast check. */
861 base_map->mode = PF_NORMAL;
862 #endif /* PF_DEBUG */
863
864 /* Allocate the map. */
865 pfnm->lattice = fc_calloc(MAP_INDEX_SIZE, sizeof(struct pf_normal_node));
866 pfnm->queue = map_index_pq_new(INITIAL_QUEUE_SIZE);
867
868 if (NULL == parameter->get_costs) {
869 /* 'get_MC' callback must be set. */
870 fc_assert_ret_val(NULL != parameter->get_MC, NULL);
871
872 /* 'get_move_scope' callback must be set. */
873 fc_assert_ret_val(parameter->get_move_scope != NULL, NULL);
874 }
875
876 /* Copy parameters. */
877 *params = *parameter;
878
879 /* Initialize virtual function table. */
880 base_map->destroy = pf_normal_map_destroy;
881 base_map->get_move_cost = pf_normal_map_move_cost;
882 base_map->get_path = pf_normal_map_path;
883 base_map->get_position = pf_normal_map_position;
884 if (NULL != params->get_costs) {
885 base_map->iterate = pf_jumbo_map_iterate;
886 } else {
887 base_map->iterate = pf_normal_map_iterate;
888 }
889
890 /* Initialise starting node. */
891 node = pfnm->lattice + tile_index(params->start_tile);
892 if (NULL == params->get_costs) {
893 if (!pf_normal_node_init(pfnm, node, params->start_tile, PF_MS_NONE)) {
894 /* Always fails. */
895 fc_assert(TRUE == pf_normal_node_init(pfnm, node, params->start_tile,
896 PF_MS_NONE));
897 }
898
899 if (NULL != params->transported_by_initially) {
900 /* Overwrite. It is safe because we cannot return to start tile with
901 * pf_normal_map. */
902 node->move_scope |= PF_MS_TRANSPORT;
903 if (!utype_can_freely_unload(params->utype,
904 params->transported_by_initially)
905 && NULL == tile_city(params->start_tile)
906 && !tile_has_native_base(params->start_tile,
907 params->transported_by_initially)) {
908 /* Cannot disembark, don't leave transporter. */
909 node->behavior = TB_DONT_LEAVE;
910 }
911 }
912 }
913
914 /* Initialise the iterator. */
915 base_map->tile = params->start_tile;
916
917 /* This makes calculations of turn/moves_left more convenient, but we
918 * need to subtract this value before we return cost to the user. Note
919 * that cost may be negative if moves_left_initially > move_rate
920 * (see pf_turns()). */
921 node->cost = pf_move_rate(params) - pf_moves_left_initially(params);
922 node->extra_cost = 0;
923 node->dir_to_here = direction8_invalid();
924 node->status = NS_PROCESSED;
925
926 return PF_MAP(pfnm);
927 }
928
929
930 /* ================ Specific pf_danger_* mode structures ================= */
931
932 /* Danger path-finding maps are used for units which can cross some areas
933 * but not ending their turn there. It used to be used for triremes notably.
934 * But since Freeciv 2.2, units with the "Trireme" flag just have
935 * restricted moves, then it is not use anymore. */
936
937 /* Node definition. Note we try to have the smallest data as possible. */
938 struct pf_danger_node {
939 signed short cost; /* total_MC. 'cost' may be negative, see comment in
940 * pf_turns(). */
941 unsigned extra_cost; /* total_EC. Can be huge, (higher than 'cost'). */
942 unsigned dir_to_here : 4; /* Direction from which we came. It's
943 * an 'enum direction8' including
944 * possibility of direction8_invalid (so we need
945 * 4 bits) */
946 unsigned status : 3; /* 'enum pf_node_status' really. */
947
948 /* Cached values */
949 unsigned move_scope : 3; /* 'enum pf_move_scope really. */
950 unsigned action : 2; /* 'enum pf_action really. */
951 unsigned node_known_type : 2; /* 'enum known_type' really. */
952 unsigned behavior : 2; /* 'enum tile_behavior' really. */
953 unsigned zoc_number : 2; /* 'enum pf_zoc_type' really. */
954 bool is_dangerous : 1; /* Whether we cannot end the turn there. */
955 bool waited : 1; /* TRUE if waited to get there. */
956 unsigned short extra_tile; /* EC */
957
958 /* Segment leading across the danger area back to the nearest safe node:
959 * need to remeber costs and stuff. */
960 struct pf_danger_pos {
961 signed short cost; /* See comment above. */
962 unsigned extra_cost; /* See comment above. */
963 signed dir_to_here : 4; /* See comment above. */
964 } *danger_segment;
965 };
966
967 /* Derived structure of struct pf_map. */
968 struct pf_danger_map {
969 struct pf_map base_map; /* Base structure, must be the first! */
970
971 struct map_index_pq *queue; /* Queue of nodes we have reached but not
972 * processed yet (NS_NEW and NS_WAITING),
973 * sorted by their total_CC. */
974 struct map_index_pq *danger_queue; /* Dangerous positions. */
975 struct pf_danger_node *lattice; /* Lattice of nodes. */
976 };
977
978 /* Up-cast macro. */
979 #ifdef PF_DEBUG
980 static inline struct pf_danger_map *
pf_danger_map_check(struct pf_map * pfm,const char * file,const char * function,int line)981 pf_danger_map_check(struct pf_map *pfm, const char *file,
982 const char *function, int line)
983 {
984 fc_assert_full(file, function, line,
985 NULL != pfm && PF_DANGER == pfm->mode,
986 return NULL, "Wrong pf_map to pf_danger_map conversion.");
987 return (struct pf_danger_map *) pfm;
988 }
989 #define PF_DANGER_MAP(pfm) \
990 pf_danger_map_check(pfm, __FILE__, __FUNCTION__, __FC_LINE__)
991 #else
992 #define PF_DANGER_MAP(pfm) ((struct pf_danger_map *) (pfm))
993 #endif /* PF_DEBUG */
994
995 /* =============== Specific pf_danger_* mode functions ================== */
996
997 /****************************************************************************
998 Calculates cached values of the target node. Set the node status to
999 NS_INIT to avoid recalculating all values. Returns FALSE if we cannot
1000 enter node (in this case, most of the cached values are not set).
1001 ****************************************************************************/
pf_danger_node_init(struct pf_danger_map * pfdm,struct pf_danger_node * node,struct tile * ptile,enum pf_move_scope previous_scope)1002 static inline bool pf_danger_node_init(struct pf_danger_map *pfdm,
1003 struct pf_danger_node *node,
1004 struct tile *ptile,
1005 enum pf_move_scope previous_scope)
1006 {
1007 const struct pf_parameter *params = pf_map_parameter(PF_MAP(pfdm));
1008 enum known_type node_known_type;
1009 enum pf_action action;
1010
1011 #ifdef PF_DEBUG
1012 fc_assert(NS_UNINIT == node->status);
1013 /* Else, not a critical problem, but waste of time. */
1014 #endif
1015
1016 node->status = NS_INIT;
1017
1018 /* Establish the "known" status of node. */
1019 if (params->omniscience) {
1020 node_known_type = TILE_KNOWN_SEEN;
1021 } else {
1022 node_known_type = tile_get_known(ptile, params->owner);
1023 }
1024 node->node_known_type = node_known_type;
1025
1026 /* Establish the tile behavior. */
1027 if (NULL != params->get_TB) {
1028 node->behavior = params->get_TB(ptile, node_known_type, params);
1029 if (TB_IGNORE == node->behavior && params->start_tile != ptile) {
1030 return FALSE;
1031 }
1032 #ifdef ZERO_VARIABLES_FOR_SEARCHING
1033 } else {
1034 /* The default. */
1035 node->behavior = TB_NORMAL;
1036 #endif
1037 }
1038
1039 if (TILE_UNKNOWN != node_known_type) {
1040 bool can_disembark;
1041
1042 /* Test if we can invade tile. */
1043 if (!utype_has_flag(params->utype, UTYF_CIVILIAN)
1044 && !player_can_invade_tile(params->owner, ptile)) {
1045 /* Maybe overwrite node behavior. */
1046 if (params->start_tile != ptile) {
1047 node->behavior = TB_IGNORE;
1048 return FALSE;
1049 } else if (TB_NORMAL == node->behavior) {
1050 node->behavior = TB_IGNORE;
1051 }
1052 }
1053
1054 /* Test the possibility to perform an action. */
1055 if (NULL != params->get_action) {
1056 action = params->get_action(ptile, node_known_type, params);
1057 if (PF_ACTION_IMPOSSIBLE == action) {
1058 /* Maybe overwrite node behavior. */
1059 if (params->start_tile != ptile) {
1060 node->behavior = TB_IGNORE;
1061 return FALSE;
1062 } else if (TB_NORMAL == node->behavior) {
1063 node->behavior = TB_IGNORE;
1064 }
1065 action = PF_ACTION_NONE;
1066 } else if (PF_ACTION_NONE != action
1067 && TB_DONT_LEAVE != node->behavior) {
1068 /* Overwrite node behavior. */
1069 node->behavior = TB_DONT_LEAVE;
1070 }
1071 node->action = action;
1072 #ifdef ZERO_VARIABLES_FOR_SEARCHING
1073 } else {
1074 /* Nodes are allocated by fc_calloc(), so should be already set to
1075 * 0. */
1076 node->action = PF_ACTION_NONE;
1077 #endif
1078 }
1079
1080 /* Test the possibility to move from/to 'ptile'. */
1081 node->move_scope = params->get_move_scope(ptile, &can_disembark,
1082 previous_scope, params);
1083 if (PF_MS_NONE == node->move_scope
1084 && PF_ACTION_NONE == node->action
1085 && params->ignore_none_scopes) {
1086 /* Maybe overwrite node behavior. */
1087 if (params->start_tile != ptile) {
1088 node->behavior = TB_IGNORE;
1089 return FALSE;
1090 } else if (TB_NORMAL == node->behavior) {
1091 node->behavior = TB_IGNORE;
1092 }
1093 } else if (PF_MS_TRANSPORT == node->move_scope
1094 && !can_disembark
1095 && (params->start_tile != ptile
1096 || NULL == params->transported_by_initially)) {
1097 /* Overwrite node behavior. */
1098 node->behavior = TB_DONT_LEAVE;
1099 }
1100
1101 /* ZOC_MINE means can move unrestricted from/into it, ZOC_ALLIED means
1102 * can move unrestricted into it, but not necessarily from it. */
1103 if (NULL != params->get_zoc
1104 && NULL == tile_city(ptile)
1105 && !terrain_has_flag(tile_terrain(ptile), TER_NO_ZOC)
1106 && !params->get_zoc(params->owner, ptile)) {
1107 node->zoc_number = (0 < unit_list_size(ptile->units)
1108 ? ZOC_ALLIED : ZOC_NO);
1109 #ifdef ZERO_VARIABLES_FOR_SEARCHING
1110 } else {
1111 /* Nodes are allocated by fc_calloc(), so should be already set to
1112 * 0. */
1113 node->zoc_number = ZOC_MINE;
1114 #endif
1115 }
1116 } else {
1117 node->move_scope = PF_MS_NATIVE;
1118 #ifdef ZERO_VARIABLES_FOR_SEARCHING
1119 /* Nodes are allocated by fc_calloc(), so should be already set to 0. */
1120 node->action = PF_ACTION_NONE;
1121 node->zoc_number = ZOC_MINE;
1122 #endif
1123 }
1124
1125 /* Evaluate the extra cost of the destination. */
1126 if (NULL != params->get_EC) {
1127 node->extra_tile = params->get_EC(ptile, node_known_type, params);
1128 #ifdef ZERO_VARIABLES_FOR_SEARCHING
1129 } else {
1130 /* Nodes are allocated by fc_calloc(), so should be already set to 0. */
1131 node->extra_tile = 0;
1132 #endif
1133 }
1134
1135 #ifdef ZERO_VARIABLES_FOR_SEARCHING
1136 /* Nodes are allocated by fc_calloc(), so should be already set to
1137 * FALSE. */
1138 node->waited = FALSE;
1139 #endif
1140
1141 node->is_dangerous =
1142 params->is_pos_dangerous(ptile, node_known_type, params);
1143
1144 return TRUE;
1145 }
1146
1147 /****************************************************************************
1148 Fill in the position which must be discovered already. A helper
1149 for pf_danger_map_position(). This also "finalizes" the position.
1150 ****************************************************************************/
pf_danger_map_fill_position(const struct pf_danger_map * pfdm,struct tile * ptile,struct pf_position * pos)1151 static void pf_danger_map_fill_position(const struct pf_danger_map *pfdm,
1152 struct tile *ptile,
1153 struct pf_position *pos)
1154 {
1155 int tindex = tile_index(ptile);
1156 struct pf_danger_node *node = pfdm->lattice + tindex;
1157 const struct pf_parameter *params = pf_map_parameter(PF_MAP(pfdm));
1158
1159 #ifdef PF_DEBUG
1160 fc_assert_ret_msg(NS_PROCESSED == node->status
1161 || NS_WAITING == node->status,
1162 "Unreached destination (%d, %d).", TILE_XY(ptile));
1163 #endif /* PF_DEBUG */
1164
1165 pos->tile = ptile;
1166 pos->total_EC = node->extra_cost;
1167 pos->total_MC = (node->cost - pf_move_rate(params)
1168 + pf_moves_left_initially(params));
1169 pos->turn = pf_turns(params, node->cost);
1170 pos->moves_left = pf_moves_left(params, node->cost);
1171 #ifdef PF_DEBUG
1172 fc_assert(params->fuel == 1);
1173 fc_assert(params->fuel_left_initially == 1);
1174 #endif /* PF_DEBUG */
1175 pos->fuel_left = 1;
1176 pos->dir_to_here = node->dir_to_here;
1177 pos->dir_to_next_pos = direction8_invalid(); /* This field does not apply. */
1178
1179 if (node->cost > 0) {
1180 pf_finalize_position(params, pos);
1181 }
1182 }
1183
1184 /****************************************************************************
1185 This function returns the fills the cost needed for a position, to get
1186 full moves at the next turn. This would be called only when the status is
1187 NS_WAITING.
1188 ****************************************************************************/
1189 static inline int
pf_danger_map_fill_cost_for_full_moves(const struct pf_parameter * param,int cost)1190 pf_danger_map_fill_cost_for_full_moves(const struct pf_parameter *param,
1191 int cost)
1192 {
1193 int moves_left = pf_moves_left(param, cost);
1194
1195 if (moves_left < pf_move_rate(param)) {
1196 return cost + moves_left;
1197 } else {
1198 return cost;
1199 }
1200 }
1201
1202 /****************************************************************************
1203 Read off the path to the node 'ptile', but with dangers.
1204 NB: will only find paths to safe tiles!
1205 ****************************************************************************/
1206 static struct pf_path *
pf_danger_map_construct_path(const struct pf_danger_map * pfdm,struct tile * ptile)1207 pf_danger_map_construct_path(const struct pf_danger_map *pfdm,
1208 struct tile *ptile)
1209 {
1210 struct pf_path *path = fc_malloc(sizeof(*path));
1211 enum direction8 dir_next = direction8_invalid();
1212 struct pf_danger_pos *danger_seg = NULL;
1213 bool waited = FALSE;
1214 struct pf_danger_node *node = pfdm->lattice + tile_index(ptile);
1215 int length = 1;
1216 struct tile *iter_tile = ptile;
1217 const struct pf_parameter *params = pf_map_parameter(PF_MAP(pfdm));
1218 struct pf_position *pos;
1219 int i;
1220
1221 #ifdef PF_DEBUG
1222 fc_assert_ret_val_msg(NS_PROCESSED == node->status
1223 || NS_WAITING == node->status, NULL,
1224 "Unreached destination (%d, %d).",
1225 TILE_XY(ptile));
1226 #endif /* PF_DEBUG */
1227
1228 /* First iterate to find path length. */
1229 while (iter_tile != params->start_tile) {
1230 if (!node->is_dangerous && node->waited) {
1231 length += 2;
1232 } else {
1233 length++;
1234 }
1235
1236 if (!node->is_dangerous || !danger_seg) {
1237 /* We are in the normal node and dir_to_here field is valid */
1238 dir_next = node->dir_to_here;
1239 /* d_node->danger_segment is the indicator of what lies ahead
1240 * if it's non-NULL, we are entering a danger segment,
1241 * if it's NULL, we are not on one so danger_seg should be NULL. */
1242 danger_seg = node->danger_segment;
1243 } else {
1244 /* We are in a danger segment. */
1245 dir_next = danger_seg->dir_to_here;
1246 danger_seg++;
1247 }
1248
1249 /* Step backward. */
1250 iter_tile = mapstep(iter_tile, DIR_REVERSE(dir_next));
1251 node = pfdm->lattice + tile_index(iter_tile);
1252 }
1253
1254 /* Allocate memory for path. */
1255 path->positions = fc_malloc(length * sizeof(struct pf_position));
1256 path->length = length;
1257
1258 /* Reset variables for main iteration. */
1259 iter_tile = ptile;
1260 node = pfdm->lattice + tile_index(ptile);
1261 danger_seg = NULL;
1262 waited = FALSE;
1263
1264 for (i = length - 1; i >= 0; i--) {
1265 bool old_waited = FALSE;
1266
1267 /* 1: Deal with waiting. */
1268 if (!node->is_dangerous) {
1269 if (waited) {
1270 /* Waited at _this_ tile, need to record it twice in the
1271 * path. Here we record our state _after_ waiting (e.g.
1272 * full move points). */
1273 pos = path->positions + i;
1274 pos->tile = iter_tile;
1275 pos->total_EC = node->extra_cost;
1276 pos->turn = pf_turns(params,
1277 pf_danger_map_fill_cost_for_full_moves(params, node->cost));
1278 pos->moves_left = params->move_rate;
1279 pos->fuel_left = params->fuel;
1280 pos->total_MC = ((pos->turn - 1) * params->move_rate
1281 + params->moves_left_initially);
1282 pos->dir_to_next_pos = dir_next;
1283 pf_finalize_position(params, pos);
1284 /* Set old_waited so that we record direction8_invalid() as a direction at
1285 * the step we were going to wait. */
1286 old_waited = TRUE;
1287 i--;
1288 }
1289 /* Update "waited" (node->waited means "waited to get here"). */
1290 waited = node->waited;
1291 }
1292
1293 /* 2: Fill the current position. */
1294 pos = path->positions + i;
1295 pos->tile = iter_tile;
1296 if (!node->is_dangerous || !danger_seg) {
1297 pos->total_MC = node->cost;
1298 pos->total_EC = node->extra_cost;
1299 } else {
1300 /* When on dangerous tiles, must have a valid danger segment. */
1301 fc_assert_ret_val(danger_seg != NULL, NULL);
1302 pos->total_MC = danger_seg->cost;
1303 pos->total_EC = danger_seg->extra_cost;
1304 }
1305 pos->turn = pf_turns(params, pos->total_MC);
1306 pos->moves_left = pf_moves_left(params, pos->total_MC);
1307 #ifdef PF_DEBUG
1308 fc_assert(params->fuel == 1);
1309 fc_assert(params->fuel_left_initially == 1);
1310 #endif /* PF_DEBUG */
1311 pos->fuel_left = 1;
1312 pos->total_MC -= (pf_move_rate(params)
1313 - pf_moves_left_initially(params));
1314 pos->dir_to_next_pos = (old_waited ? direction8_invalid() : dir_next);
1315 if (node->cost > 0) {
1316 pf_finalize_position(params, pos);
1317 }
1318
1319 /* 3: Check if we finished. */
1320 if (i == 0) {
1321 /* We should be back at the start now! */
1322 fc_assert_ret_val(iter_tile == params->start_tile, NULL);
1323 return path;
1324 }
1325
1326 /* 4: Calculate the next direction. */
1327 if (!node->is_dangerous || !danger_seg) {
1328 /* We are in the normal node and dir_to_here field is valid. */
1329 dir_next = node->dir_to_here;
1330 /* d_node->danger_segment is the indicator of what lies ahead.
1331 * If it's non-NULL, we are entering a danger segment,
1332 * If it's NULL, we are not on one so danger_seg should be NULL. */
1333 danger_seg = node->danger_segment;
1334 } else {
1335 /* We are in a danger segment. */
1336 dir_next = danger_seg->dir_to_here;
1337 danger_seg++;
1338 }
1339
1340 /* 5: Step further back. */
1341 iter_tile = mapstep(iter_tile, DIR_REVERSE(dir_next));
1342 node = pfdm->lattice + tile_index(iter_tile);
1343 }
1344
1345 fc_assert_msg(FALSE, "Cannot get to the starting point!");
1346 return NULL;
1347 }
1348
1349 /****************************************************************************
1350 Creating path segment going back from node1 to a safe tile. We need to
1351 remember the whole segment because any node can be crossed by many danger
1352 segments.
1353
1354 Example: be A, B, C and D points safe positions, E a dangerous one.
1355 A B
1356 E
1357 C D
1358 We have found dangerous path from A to D, and later one from C to B:
1359 A B A B
1360 \ /
1361 C D C D
1362 If we didn't save the segment from A to D when a new segment passing by E
1363 is found, then finding the path from A to D will produce an error. (The
1364 path is always done in reverse order.) D->dir_to_here will point to E,
1365 which is correct, but E->dir_to_here will point to C.
1366 ****************************************************************************/
pf_danger_map_create_segment(struct pf_danger_map * pfdm,struct pf_danger_node * node1)1367 static void pf_danger_map_create_segment(struct pf_danger_map *pfdm,
1368 struct pf_danger_node *node1)
1369 {
1370 struct tile *ptile = PF_MAP(pfdm)->tile;
1371 struct pf_danger_node *node = pfdm->lattice + tile_index(ptile);
1372 struct pf_danger_pos *pos;
1373 int length = 0, i;
1374
1375 #ifdef PF_DEBUG
1376 if (NULL != node1->danger_segment) {
1377 log_error("Possible memory leak in pf_danger_map_create_segment().");
1378 }
1379 #endif /* PF_DEBUG */
1380
1381 /* First iteration for determining segment length */
1382 while (node->is_dangerous && direction8_is_valid(node->dir_to_here)) {
1383 length++;
1384 ptile = mapstep(ptile, DIR_REVERSE(node->dir_to_here));
1385 node = pfdm->lattice + tile_index(ptile);
1386 }
1387
1388 /* Allocate memory for segment */
1389 node1->danger_segment = fc_malloc(length * sizeof(struct pf_danger_pos));
1390
1391 /* Reset tile and node pointers for main iteration */
1392 ptile = PF_MAP(pfdm)->tile;
1393 node = pfdm->lattice + tile_index(ptile);
1394
1395 /* Now fill the positions */
1396 for (i = 0, pos = node1->danger_segment; i < length; i++, pos++) {
1397 /* Record the direction */
1398 pos->dir_to_here = node->dir_to_here;
1399 pos->cost = node->cost;
1400 pos->extra_cost = node->extra_cost;
1401 if (i == length - 1) {
1402 /* The last dangerous node contains "waiting" info */
1403 node1->waited = node->waited;
1404 }
1405
1406 /* Step further down the tree */
1407 ptile = mapstep(ptile, DIR_REVERSE(node->dir_to_here));
1408 node = pfdm->lattice + tile_index(ptile);
1409 }
1410
1411 #ifdef PF_DEBUG
1412 /* Make sure we reached a safe node or the start point */
1413 fc_assert_ret(!node->is_dangerous || !direction8_is_valid(node->dir_to_here));
1414 #endif
1415 }
1416
1417 /****************************************************************************
1418 Adjust cost taking into account possibility of making the move.
1419 ****************************************************************************/
1420 static inline int
pf_danger_map_adjust_cost(const struct pf_parameter * params,int cost,bool to_danger,int moves_left)1421 pf_danger_map_adjust_cost(const struct pf_parameter *params,
1422 int cost, bool to_danger, int moves_left)
1423 {
1424 if (cost == PF_IMPOSSIBLE_MC) {
1425 return PF_IMPOSSIBLE_MC;
1426 }
1427
1428 cost = MIN(cost, pf_move_rate(params));
1429
1430 if (to_danger && cost >= moves_left) {
1431 /* We would have to end the turn on a dangerous tile! */
1432 return PF_IMPOSSIBLE_MC;
1433 } else {
1434 return MIN(cost, moves_left);
1435 }
1436 }
1437
1438 /****************************************************************************
1439 Primary method for iterative path-finding in presence of danger
1440 Notes:
1441 1. Whenever the path-finding stumbles upon a dangerous location, it goes
1442 into a sub-Dijkstra which processes _only_ dangerous locations, by
1443 means of a separate queue. When this sub-Dijkstra reaches a safe
1444 location, it records the segment of the path going across the dangerous
1445 tiles. Hence danger_segment is an extended (and reversed) version of
1446 the dir_to_here field (see comment for pf_danger_map_create_segment()).
1447 It can be re-recorded multiple times as we find shorter and shorter
1448 routes.
1449 2. Waiting is realised by inserting the (safe) tile back into the queue
1450 with a lower priority P. This tile might pop back sooner than P,
1451 because there might be several copies of it in the queue already. But
1452 that does not seem to present any problems.
1453 3. For some purposes, NS_WAITING is just another flavour of NS_PROCESSED,
1454 since the path to a NS_WAITING tile has already been found.
1455 4. This algorithm cannot guarantee the best safe segments across dangerous
1456 region. However it will find a safe segment if there is one. To
1457 gurantee the best (in terms of total_CC) safe segments across danger,
1458 supply 'get_EC' which returns small extra on dangerous tiles.
1459
1460 During the iteration, the node status will be changed:
1461 A. NS_UNINIT: The node is not initialized, we didn't reach it at all.
1462 B. NS_INIT: We have initialized the cached values, however, we failed to
1463 reach this node.
1464 C. NS_NEW: We have reached this node, but we are not sure it was the best
1465 path. Dangerous tiles never get upper status.
1466 D. NS_PROCESSED: Now, we are sure we have the best path.
1467 E. NS_WAITING: The safe node (never the dangerous ones) is re-inserted in
1468 the priority queue, as explained above (2.). We need to consider if
1469 waiting for full moves open or not new possibilities for moving across
1470 dangerous areas.
1471 F. NS_PROCESSED: When finished to consider waiting at the node, revert the
1472 status to NS_PROCESSED.
1473 In points D., E., and F., the best path to the node can be considered as
1474 found (only safe nodes).
1475 ****************************************************************************/
pf_danger_map_iterate(struct pf_map * pfm)1476 static bool pf_danger_map_iterate(struct pf_map *pfm)
1477 {
1478 struct pf_danger_map *const pfdm = PF_DANGER_MAP(pfm);
1479 const struct pf_parameter *const params = pf_map_parameter(pfm);
1480 struct tile *tile = pfm->tile;
1481 int tindex = tile_index(tile);
1482 struct pf_danger_node *node = pfdm->lattice + tindex;
1483 enum pf_move_scope scope = node->move_scope;
1484
1485 /* The previous position is defined by 'tile' (tile pointer), 'node'
1486 * (the data of the tile for the pf_map), and index (the index of the
1487 * position in the Freeciv map). */
1488
1489 if (!direction8_is_valid(node->dir_to_here)
1490 && NULL != params->transported_by_initially) {
1491 #ifdef PF_DEBUG
1492 fc_assert(tile == params->start_tile);
1493 #endif
1494 scope |= PF_MS_TRANSPORT;
1495 if (!utype_can_freely_unload(params->utype,
1496 params->transported_by_initially)
1497 && NULL == tile_city(tile)
1498 && !tile_has_native_base(tile, params->transported_by_initially)) {
1499 /* Cannot disembark, don't leave transporter. */
1500 node->behavior = TB_DONT_LEAVE;
1501 }
1502 }
1503
1504 for (;;) {
1505 /* There is no exit from DONT_LEAVE tiles! */
1506 if (node->behavior != TB_DONT_LEAVE
1507 && scope != PF_MS_NONE
1508 && (params->move_rate > 0 || node->cost < 0)) {
1509 /* Cost at tile but taking into account waiting. */
1510 int loc_cost;
1511 if (node->status != NS_WAITING) {
1512 loc_cost = node->cost;
1513 } else {
1514 /* We have waited, so we have full moves. */
1515 loc_cost = pf_danger_map_fill_cost_for_full_moves(params,
1516 node->cost);
1517 }
1518
1519 adjc_dir_iterate(tile, tile1, dir) {
1520 /* Calculate the cost of every adjacent position and set them in
1521 * the priority queues for next call to pf_danger_map_iterate(). */
1522 int tindex1 = tile_index(tile1);
1523 struct pf_danger_node *node1 = pfdm->lattice + tindex1;
1524 int cost;
1525 int extra = 0;
1526
1527 /* As for the previous position, 'tile1', 'node1' and 'tindex1' are
1528 * defining the adjacent position. */
1529
1530 if (node1->status == NS_PROCESSED || node1->status == NS_WAITING) {
1531 /* This gives 15% speedup. Node status already at step D., E.
1532 * or F. */
1533 continue;
1534 }
1535
1536 /* Initialise target tile if necessary. */
1537 if (node1->status == NS_UNINIT) {
1538 /* Only initialize once. See comment for pf_danger_node_init().
1539 * Node status step A. to B. */
1540 if (!pf_danger_node_init(pfdm, node1, tile1, scope)) {
1541 continue;
1542 }
1543 } else if (TB_IGNORE == node1->behavior) {
1544 /* We cannot enter this tile at all! */
1545 continue;
1546 }
1547
1548 /* Is the move ZOC-ok? */
1549 if (node->zoc_number != ZOC_MINE && node1->zoc_number == ZOC_NO) {
1550 continue;
1551 }
1552
1553 /* Evaluate the cost of the move. */
1554 if (PF_ACTION_NONE != node1->action) {
1555 if (NULL != params->is_action_possible
1556 && !params->is_action_possible(tile, scope, tile1,
1557 node1->action, params)) {
1558 continue;
1559 }
1560 /* action move cost depends on action and unit type. */
1561 if (node1->action == PF_ACTION_ATTACK
1562 && (utype_has_flag(params->utype, UTYF_ONEATTACK)
1563 || uclass_has_flag(utype_class(params->utype),
1564 UCF_MISSILE))) {
1565 cost = params->move_rate;
1566 } else {
1567 cost = SINGLE_MOVE;
1568 }
1569 } else if (node1->node_known_type == TILE_UNKNOWN) {
1570 cost = params->utype->unknown_move_cost;
1571 } else {
1572 cost = params->get_MC(tile, scope, tile1, node1->move_scope,
1573 params);
1574 }
1575 if (cost == PF_IMPOSSIBLE_MC) {
1576 continue;
1577 }
1578 cost = pf_danger_map_adjust_cost(params, cost, node1->is_dangerous,
1579 pf_moves_left(params, loc_cost));
1580
1581 if (cost == PF_IMPOSSIBLE_MC) {
1582 /* This move is deemed impossible. */
1583 continue;
1584 }
1585
1586 /* Total cost at 'tile1'. */
1587 cost += loc_cost;
1588
1589 /* Evaluate the extra cost of the destination, if it's relevant. */
1590 if (NULL != params->get_EC) {
1591 extra = node1->extra_tile + node->extra_cost;
1592 }
1593
1594 /* Update costs and add to queue, if this is a better route
1595 * to 'tile1'. */
1596 if (!node1->is_dangerous) {
1597 int cost_of_path = pf_total_CC(params, cost, extra);
1598
1599 if (NS_INIT == node1->status
1600 || (cost_of_path < pf_total_CC(params, node1->cost,
1601 node1->extra_cost))) {
1602 /* We are reaching this node for the first time, or we found a
1603 * better route to 'tile1'. Let's register 'tindex1' to the
1604 * priority queue. Node status step B. to C. */
1605 node1->extra_cost = extra;
1606 node1->cost = cost;
1607 node1->dir_to_here = dir;
1608 if (NULL != node1->danger_segment) {
1609 /* Clear the previously recorded path back. */
1610 free(node1->danger_segment);
1611 node1->danger_segment = NULL;
1612 }
1613 if (node->is_dangerous) {
1614 /* We came from a dangerous tile. So we need to record the
1615 * path we came from until the previous safe position is
1616 * found. See comment for pf_danger_map_create_segment(). */
1617 pf_danger_map_create_segment(pfdm, node1);
1618 } else {
1619 /* Maybe clear previously "waited" status of the node. */
1620 node1->waited = FALSE;
1621 }
1622 if (NS_INIT == node1->status) {
1623 node1->status = NS_NEW;
1624 map_index_pq_insert(pfdm->queue, tindex1, -cost_of_path);
1625 } else {
1626 #ifdef PF_DEBUG
1627 fc_assert(NS_NEW == node1->status);
1628 #endif
1629 map_index_pq_replace(pfdm->queue, tindex1, -cost_of_path);
1630 }
1631 }
1632 } else {
1633 /* The procedure is slightly different for dangerous nodes.
1634 * We will update costs if:
1635 * 1. we are here for the first time;
1636 * 2. we can possibly go further across dangerous area; or
1637 * 3. we can have lower extra and will not overwrite anything
1638 * useful. Node status step B. to C. */
1639 if (node1->status == NS_INIT) {
1640 /* case 1. */
1641 node1->extra_cost = extra;
1642 node1->cost = cost;
1643 node1->dir_to_here = dir;
1644 node1->status = NS_NEW;
1645 node1->waited = (node->status == NS_WAITING);
1646 /* Extra costs of all nodes in danger_queue are equal! */
1647 map_index_pq_insert(pfdm->danger_queue, tindex1, -cost);
1648 } else if ((pf_moves_left(params, cost)
1649 > pf_moves_left(params, node1->cost))
1650 || (node1->status == NS_PROCESSED
1651 && (pf_total_CC(params, cost, extra)
1652 < pf_total_CC(params, node1->cost,
1653 node1->extra_cost)))) {
1654 /* case 2 or 3. */
1655 node1->extra_cost = extra;
1656 node1->cost = cost;
1657 node1->dir_to_here = dir;
1658 node1->status = NS_NEW;
1659 node1->waited = (node->status == NS_WAITING);
1660 /* Extra costs of all nodes in danger_queue are equal! */
1661 map_index_pq_replace(pfdm->danger_queue, tindex1, -cost);
1662 }
1663 }
1664 } adjc_dir_iterate_end;
1665 }
1666
1667 if (NS_WAITING == node->status) {
1668 /* Node status final step E. to F. */
1669 #ifdef PF_DEBUG
1670 fc_assert(!node->is_dangerous);
1671 #endif
1672 node->status = NS_PROCESSED;
1673 } else if (!node->is_dangerous
1674 && (pf_moves_left(params, node->cost)
1675 < pf_move_rate(params))) {
1676 int fc, cc;
1677 /* Consider waiting at this node. To do it, put it back into queue.
1678 * Node status final step D. to E. */
1679 fc = pf_danger_map_fill_cost_for_full_moves(params, node->cost);
1680 cc = pf_total_CC(params, fc, node->extra_cost);
1681 node->status = NS_WAITING;
1682 map_index_pq_insert(pfdm->queue, tindex, -cc);
1683 }
1684
1685 /* Get the next node (the index with the highest priority). First try
1686 * to get it from danger_queue. */
1687 if (map_index_pq_remove(pfdm->danger_queue, &tindex)) {
1688 /* Change the pf_map iterator and reset data. */
1689 tile = index_to_tile(tindex);
1690 pfm->tile = tile;
1691 node = pfdm->lattice + tindex;
1692 } else {
1693 /* No dangerous nodes to process, go for a safe one. */
1694 if (!map_index_pq_remove(pfdm->queue, &tindex)) {
1695 /* No more indexes in the priority queue, iteration end. */
1696 return FALSE;
1697 }
1698
1699 #ifdef PF_DEBUG
1700 fc_assert(NS_PROCESSED != pfdm->lattice[tindex].status);
1701 #endif
1702
1703 /* Change the pf_map iterator and reset data. */
1704 tile = index_to_tile(tindex);
1705 pfm->tile = tile;
1706 node = pfdm->lattice + tindex;
1707 if (NS_WAITING != node->status) {
1708 /* Node status step C. and D. */
1709 #ifdef PF_DEBUG
1710 fc_assert(!node->is_dangerous);
1711 #endif
1712 node->status = NS_PROCESSED;
1713 return TRUE;
1714 }
1715 }
1716
1717 #ifdef PF_DEBUG
1718 fc_assert(NS_INIT < node->status);
1719
1720 if (NS_WAITING == node->status) {
1721 /* We've already returned this node once, skip it. */
1722 log_debug("Considering waiting at (%d, %d)", TILE_XY(tile));
1723 } else if (node->is_dangerous) {
1724 /* We don't return dangerous tiles. */
1725 log_debug("Reached dangerous tile (%d, %d)", TILE_XY(tile));
1726 }
1727 #endif
1728
1729 scope = node->move_scope;
1730 }
1731
1732 log_error("%s(): internal error.", __FUNCTION__);
1733 return FALSE;
1734 }
1735
1736 /****************************************************************************
1737 Iterate the map until 'ptile' is reached.
1738 ****************************************************************************/
pf_danger_map_iterate_until(struct pf_danger_map * pfdm,struct tile * ptile)1739 static inline bool pf_danger_map_iterate_until(struct pf_danger_map *pfdm,
1740 struct tile *ptile)
1741 {
1742 struct pf_map *pfm = PF_MAP(pfdm);
1743 struct pf_danger_node *node = pfdm->lattice + tile_index(ptile);
1744
1745 /* Start position is handled in every function calling this function. */
1746
1747 if (NS_UNINIT == node->status) {
1748 /* Initialize the node, for doing the following tests. */
1749 if (!pf_danger_node_init(pfdm, node, ptile, PF_MS_NONE)
1750 || node->is_dangerous) {
1751 return FALSE;
1752 }
1753 } else if (TB_IGNORE == node->behavior || node->is_dangerous) {
1754 /* Simpliciation: if we cannot enter this node at all, or we cannot
1755 * stay at this position, don't iterate the whole map. */
1756 return FALSE;
1757 }
1758
1759 while (NS_PROCESSED != node->status && NS_WAITING != node->status) {
1760 if (!pf_map_iterate(pfm)) {
1761 /* All reachable destination have been iterated, 'ptile' is
1762 * unreachable. */
1763 return FALSE;
1764 }
1765 }
1766
1767 return TRUE;
1768 }
1769
1770 /****************************************************************************
1771 Return the move cost at ptile. If ptile has not been reached yet, iterate
1772 the map until we reach it or run out of map. This function returns
1773 PF_IMPOSSIBLE_MC on unreachable positions.
1774 ****************************************************************************/
pf_danger_map_move_cost(struct pf_map * pfm,struct tile * ptile)1775 static int pf_danger_map_move_cost(struct pf_map *pfm, struct tile *ptile)
1776 {
1777 struct pf_danger_map *pfdm = PF_DANGER_MAP(pfm);
1778
1779 if (ptile == pfm->params.start_tile) {
1780 return 0;
1781 } else if (pf_danger_map_iterate_until(pfdm, ptile)) {
1782 return (pfdm->lattice[tile_index(ptile)].cost
1783 - pf_move_rate(pf_map_parameter(pfm))
1784 + pf_moves_left_initially(pf_map_parameter(pfm)));
1785 } else {
1786 return PF_IMPOSSIBLE_MC;
1787 }
1788 }
1789
1790 /****************************************************************************
1791 Return the path to ptile. If ptile has not been reached yet, iterate the
1792 map until we reach it or run out of map.
1793 ****************************************************************************/
pf_danger_map_path(struct pf_map * pfm,struct tile * ptile)1794 static struct pf_path *pf_danger_map_path(struct pf_map *pfm,
1795 struct tile *ptile)
1796 {
1797 struct pf_danger_map *pfdm = PF_DANGER_MAP(pfm);
1798
1799 if (ptile == pfm->params.start_tile) {
1800 return pf_path_new_to_start_tile(pf_map_parameter(pfm));
1801 } else if (pf_danger_map_iterate_until(pfdm, ptile)) {
1802 return pf_danger_map_construct_path(pfdm, ptile);
1803 } else {
1804 return NULL;
1805 }
1806 }
1807
1808 /***************************************************************************
1809 Get info about position at ptile and put it in pos . If ptile has not been
1810 reached yet, iterate the map until we reach it. Should _always_ check the
1811 return value, for the position might be unreachable.
1812 ***************************************************************************/
pf_danger_map_position(struct pf_map * pfm,struct tile * ptile,struct pf_position * pos)1813 static bool pf_danger_map_position(struct pf_map *pfm, struct tile *ptile,
1814 struct pf_position *pos)
1815 {
1816 struct pf_danger_map *pfdm = PF_DANGER_MAP(pfm);
1817
1818 if (ptile == pfm->params.start_tile) {
1819 pf_position_fill_start_tile(pos, pf_map_parameter(pfm));
1820 return TRUE;
1821 } else if (pf_danger_map_iterate_until(pfdm, ptile)) {
1822 pf_danger_map_fill_position(pfdm, ptile, pos);
1823 return TRUE;
1824 } else {
1825 return FALSE;
1826 }
1827 }
1828
1829 /****************************************************************************
1830 'pf_danger_map' destructor.
1831 ****************************************************************************/
pf_danger_map_destroy(struct pf_map * pfm)1832 static void pf_danger_map_destroy(struct pf_map *pfm)
1833 {
1834 struct pf_danger_map *pfdm = PF_DANGER_MAP(pfm);
1835 struct pf_danger_node *node;
1836 int i;
1837
1838 /* Need to clean up the dangling danger segments. */
1839 for (i = 0, node = pfdm->lattice; i < MAP_INDEX_SIZE; i++, node++) {
1840 if (node->danger_segment) {
1841 free(node->danger_segment);
1842 }
1843 }
1844 free(pfdm->lattice);
1845 map_index_pq_destroy(pfdm->queue);
1846 map_index_pq_destroy(pfdm->danger_queue);
1847 free(pfdm);
1848 }
1849
1850 /****************************************************************************
1851 'pf_danger_map' constructor.
1852 ****************************************************************************/
pf_danger_map_new(const struct pf_parameter * parameter)1853 static struct pf_map *pf_danger_map_new(const struct pf_parameter *parameter)
1854 {
1855 struct pf_danger_map *pfdm;
1856 struct pf_map *base_map;
1857 struct pf_parameter *params;
1858 struct pf_danger_node *node;
1859
1860 pfdm = fc_malloc(sizeof(*pfdm));
1861 base_map = &pfdm->base_map;
1862 params = &base_map->params;
1863 #ifdef PF_DEBUG
1864 /* Set the mode, used for cast check. */
1865 base_map->mode = PF_DANGER;
1866 #endif /* PF_DEBUG */
1867
1868 /* Allocate the map. */
1869 pfdm->lattice = fc_calloc(MAP_INDEX_SIZE, sizeof(struct pf_danger_node));
1870 pfdm->queue = map_index_pq_new(INITIAL_QUEUE_SIZE);
1871 pfdm->danger_queue = map_index_pq_new(INITIAL_QUEUE_SIZE);
1872
1873 /* 'get_MC' callback must be set. */
1874 fc_assert_ret_val(parameter->get_MC != NULL, NULL);
1875
1876 /* 'is_pos_dangerous' callback must be set. */
1877 fc_assert_ret_val(parameter->is_pos_dangerous != NULL, NULL);
1878
1879 /* 'get_move_scope' callback must be set. */
1880 fc_assert_ret_val(parameter->get_move_scope != NULL, NULL);
1881
1882 /* Copy parameters */
1883 *params = *parameter;
1884
1885 /* Initialize virtual function table. */
1886 base_map->destroy = pf_danger_map_destroy;
1887 base_map->get_move_cost = pf_danger_map_move_cost;
1888 base_map->get_path = pf_danger_map_path;
1889 base_map->get_position = pf_danger_map_position;
1890 base_map->iterate = pf_danger_map_iterate;
1891
1892 /* Initialise starting node. */
1893 node = pfdm->lattice + tile_index(params->start_tile);
1894 if (!pf_danger_node_init(pfdm, node, params->start_tile, PF_MS_NONE)) {
1895 /* Always fails. */
1896 fc_assert(TRUE == pf_danger_node_init(pfdm, node, params->start_tile,
1897 PF_MS_NONE));
1898 }
1899
1900 /* NB: do not handle params->transported_by_initially because we want to
1901 * handle only at start, not when crossing over the start tile for a
1902 * second time. See pf_danger_map_iterate(). */
1903
1904 /* Initialise the iterator. */
1905 base_map->tile = params->start_tile;
1906
1907 /* This makes calculations of turn/moves_left more convenient, but we
1908 * need to subtract this value before we return cost to the user. Note
1909 * that cost may be negative if moves_left_initially > move_rate
1910 * (see pf_turns()). */
1911 node->cost = pf_move_rate(params) - pf_moves_left_initially(params);
1912 node->extra_cost = 0;
1913 node->dir_to_here = direction8_invalid();
1914 node->status = (node->is_dangerous ? NS_NEW : NS_PROCESSED);
1915
1916 return PF_MAP(pfdm);
1917 }
1918
1919
1920 /* ================= Specific pf_fuel_* mode structures ================== */
1921
1922 /* Fuel path-finding maps are used for units which need to refuel. Usually
1923 * for air units such as planes or missiles.
1924 *
1925 * A big difference with the danger path-finding maps is that the tiles
1926 * which are not refuel points are not considered as dangerous because the
1927 * server uses to move the units at the end of the turn to refuels points. */
1928
1929 struct pf_fuel_pos;
1930
1931 /* Node definition. Note we try to have the smallest data as possible. */
1932 struct pf_fuel_node {
1933 signed short cost; /* total_MC. 'cost' may be negative, see comment in
1934 * pf_turns(). */
1935 unsigned extra_cost; /* total_EC. Can be huge, (higher than 'cost'). */
1936 unsigned moves_left : 12; /* Moves left at this position. */
1937 unsigned dir_to_here : 4; /* Direction from which we came. It's
1938 * an 'enum direction8' including
1939 * possibility of direction8_invalid (so we need
1940 * 4 bits) */
1941 unsigned status : 3; /* 'enum pf_node_status' really. */
1942
1943 /* Cached values */
1944 unsigned move_scope : 3; /* 'enum pf_move_scope really. */
1945 unsigned action : 2; /* 'enum pf_action really. */
1946 unsigned node_known_type : 2; /* 'enum known_type' really. */
1947 unsigned behavior : 2; /* 'enum tile_behavior' really. */
1948 unsigned zoc_number : 2; /* 'enum pf_zoc_type' really. */
1949 signed moves_left_req : 13; /* The minimum required moves left to reach
1950 * this tile. It the number of moves we need
1951 * to reach the nearest refuel point. A
1952 * value of 0 means this is a refuel point.
1953 * FIXME: this is right only for units with
1954 * constant move costs! */
1955 unsigned short extra_tile; /* EC */
1956 unsigned short cost_to_here[DIR8_MAGIC_MAX]; /* Step cost[dir to here] */
1957
1958 /* Segment leading across the danger area back to the nearest safe node:
1959 * need to remember costs and stuff. */
1960 struct pf_fuel_pos *pos;
1961 /* Optimal segment to follow to get there (when node is processed). */
1962 struct pf_fuel_pos *segment;
1963 };
1964
1965 /* We need to remember how we could get to there (until the previous refuel
1966 * point, or start position), because we could re-process the nodes after
1967 * having waiting somewhere. */
1968 struct pf_fuel_pos {
1969 signed short cost;
1970 unsigned extra_cost;
1971 unsigned moves_left : 12;
1972 unsigned dir_to_here : 4;
1973 unsigned ref_count : 4;
1974 struct pf_fuel_pos *prev;
1975 };
1976
1977 /* Derived structure of struct pf_map. */
1978 struct pf_fuel_map {
1979 struct pf_map base_map; /* Base structure, must be the first! */
1980
1981 struct map_index_pq *queue; /* Queue of nodes we have reached but not
1982 * processed yet (NS_NEW), sorted by their
1983 * total_CC */
1984 struct map_index_pq *waited_queue; /* Queue of nodes to reach farer
1985 * positions after having refueled. */
1986 struct pf_fuel_node *lattice; /* Lattice of nodes */
1987 };
1988
1989 /* Up-cast macro. */
1990 #ifdef PF_DEBUG
1991 static inline struct pf_fuel_map *
pf_fuel_map_check(struct pf_map * pfm,const char * file,const char * function,int line)1992 pf_fuel_map_check(struct pf_map *pfm, const char *file,
1993 const char *function, int line)
1994 {
1995 fc_assert_full(file, function, line,
1996 NULL != pfm && PF_FUEL == pfm->mode,
1997 return NULL, "Wrong pf_map to pf_fuel_map conversion.");
1998 return (struct pf_fuel_map *) pfm;
1999 }
2000 #define PF_FUEL_MAP(pfm) \
2001 pf_fuel_map_check(pfm, __FILE__, __FUNCTION__, __FC_LINE__)
2002 #else
2003 #define PF_FUEL_MAP(pfm) ((struct pf_fuel_map *) (pfm))
2004 #endif /* PF_DEBUG */
2005
2006 /* ================= Specific pf_fuel_* mode functions ================== */
2007
2008 /****************************************************************************
2009 Obtain cost-of-path from pure cost, extra cost and safety.
2010 ****************************************************************************/
pf_fuel_total_CC(const struct pf_parameter * param,int cost,int extra,int safety)2011 static inline int pf_fuel_total_CC(const struct pf_parameter *param,
2012 int cost, int extra, int safety)
2013 {
2014 return pf_total_CC(param, cost, extra) - safety;
2015 }
2016
2017 /****************************************************************************
2018 Obtain cost-of-path for constant extra cost (used for node after waited).
2019 ****************************************************************************/
pf_fuel_waited_total_CC(int cost,int safety)2020 static inline int pf_fuel_waited_total_CC(int cost, int safety)
2021 {
2022 return PF_TURN_FACTOR * (cost + 1) - safety - 1;
2023 }
2024
2025 /****************************************************************************
2026 Calculates cached values of the target node. Set the node status to
2027 NS_INIT to avoid recalculating all values. Returns FALSE if we cannot
2028 enter node (in this case, most of the cached values are not set).
2029 ****************************************************************************/
pf_fuel_node_init(struct pf_fuel_map * pffm,struct pf_fuel_node * node,struct tile * ptile,enum pf_move_scope previous_scope)2030 static inline bool pf_fuel_node_init(struct pf_fuel_map *pffm,
2031 struct pf_fuel_node *node,
2032 struct tile *ptile,
2033 enum pf_move_scope previous_scope)
2034 {
2035 const struct pf_parameter *params = pf_map_parameter(PF_MAP(pffm));
2036 enum known_type node_known_type;
2037 enum pf_action action;
2038
2039 #ifdef PF_DEBUG
2040 fc_assert(NS_UNINIT == node->status);
2041 /* Else, not a critical problem, but waste of time. */
2042 #endif
2043
2044 node->status = NS_INIT;
2045
2046 /* Establish the "known" status of node. */
2047 if (params->omniscience) {
2048 node_known_type = TILE_KNOWN_SEEN;
2049 } else {
2050 node_known_type = tile_get_known(ptile, params->owner);
2051 }
2052 node->node_known_type = node_known_type;
2053
2054 /* Establish the tile behavior. */
2055 if (NULL != params->get_TB) {
2056 node->behavior = params->get_TB(ptile, node_known_type, params);
2057 if (TB_IGNORE == node->behavior && params->start_tile != ptile) {
2058 return FALSE;
2059 }
2060 #ifdef ZERO_VARIABLES_FOR_SEARCHING
2061 } else {
2062 /* The default. */
2063 node->behavior = TB_NORMAL;
2064 #endif
2065 }
2066
2067 if (TILE_UNKNOWN != node_known_type) {
2068 bool can_disembark;
2069
2070 /* Test if we can invade tile. */
2071 if (!utype_has_flag(params->utype, UTYF_CIVILIAN)
2072 && !player_can_invade_tile(params->owner, ptile)) {
2073 /* Maybe overwrite node behavior. */
2074 if (params->start_tile != ptile) {
2075 node->behavior = TB_IGNORE;
2076 return FALSE;
2077 } else if (TB_NORMAL == node->behavior) {
2078 node->behavior = TB_IGNORE;
2079 }
2080 }
2081
2082 /* Test the possibility to perform an action. */
2083 if (NULL != params->get_action
2084 && PF_ACTION_NONE != (action =
2085 params->get_action(ptile, node_known_type,
2086 params))) {
2087 if (PF_ACTION_IMPOSSIBLE == action) {
2088 /* Maybe overwrite node behavior. */
2089 if (params->start_tile != ptile) {
2090 node->behavior = TB_IGNORE;
2091 return FALSE;
2092 } else if (TB_NORMAL == node->behavior) {
2093 node->behavior = TB_IGNORE;
2094 }
2095 action = PF_ACTION_NONE;
2096 } else if (TB_DONT_LEAVE != node->behavior) {
2097 /* Overwrite node behavior. */
2098 node->behavior = TB_DONT_LEAVE;
2099 }
2100 node->action = action;
2101 #ifdef ZERO_VARIABLES_FOR_SEARCHING
2102 node->moves_left_req = 0; /* Attack is always possible theorically. */
2103 #endif
2104 } else {
2105 #ifdef ZERO_VARIABLES_FOR_SEARCHING
2106 /* Nodes are allocated by fc_calloc(), so should be already set to
2107 * 0. */
2108 node->action = PF_ACTION_NONE;
2109 #endif
2110 node->moves_left_req =
2111 params->get_moves_left_req(ptile, node_known_type, params);
2112 if (PF_IMPOSSIBLE_MC == node->moves_left_req) {
2113 /* Overwrite node behavior. */
2114 if (params->start_tile == ptile) {
2115 node->behavior = TB_DONT_LEAVE;
2116 } else {
2117 node->behavior = TB_IGNORE;
2118 return FALSE;
2119 }
2120 }
2121 }
2122
2123 /* Test the possibility to move from/to 'ptile'. */
2124 node->move_scope = params->get_move_scope(ptile, &can_disembark,
2125 previous_scope, params);
2126 if (PF_MS_NONE == node->move_scope
2127 && PF_ACTION_NONE == node->action
2128 && params->ignore_none_scopes) {
2129 /* Maybe overwrite node behavior. */
2130 if (params->start_tile != ptile) {
2131 node->behavior = TB_IGNORE;
2132 return FALSE;
2133 } else if (TB_NORMAL == node->behavior) {
2134 node->behavior = TB_IGNORE;
2135 }
2136 } else if (PF_MS_TRANSPORT == node->move_scope
2137 && !can_disembark
2138 && (params->start_tile != ptile
2139 || NULL == params->transported_by_initially)) {
2140 /* Overwrite node behavior. */
2141 node->behavior = TB_DONT_LEAVE;
2142 }
2143
2144 /* ZOC_MINE means can move unrestricted from/into it, ZOC_ALLIED means
2145 * can move unrestricted into it, but not necessarily from it. */
2146 if (NULL != params->get_zoc
2147 && NULL == tile_city(ptile)
2148 && !terrain_has_flag(tile_terrain(ptile), TER_NO_ZOC)
2149 && !params->get_zoc(params->owner, ptile)) {
2150 node->zoc_number = (0 < unit_list_size(ptile->units)
2151 ? ZOC_ALLIED : ZOC_NO);
2152 #ifdef ZERO_VARIABLES_FOR_SEARCHING
2153 } else {
2154 /* Nodes are allocated by fc_calloc(), so should be already set to
2155 * 0. */
2156 node->zoc_number = ZOC_MINE;
2157 #endif
2158 }
2159 } else {
2160 node->moves_left_req =
2161 params->get_moves_left_req(ptile, node_known_type, params);
2162 if (PF_IMPOSSIBLE_MC == node->moves_left_req) {
2163 /* Overwrite node behavior. */
2164 if (params->start_tile == ptile) {
2165 node->behavior = TB_DONT_LEAVE;
2166 } else {
2167 node->behavior = TB_IGNORE;
2168 return FALSE;
2169 }
2170 }
2171
2172 node->move_scope = PF_MS_NATIVE;
2173 #ifdef ZERO_VARIABLES_FOR_SEARCHING
2174 /* Nodes are allocated by fc_calloc(), so should be already set to 0. */
2175 node->action = PF_ACTION_NONE;
2176 node->zoc_number = ZOC_MINE;
2177 #endif
2178 }
2179
2180 /* Evaluate the extra cost of the destination. */
2181 if (NULL != params->get_EC) {
2182 node->extra_tile = params->get_EC(ptile, node_known_type, params);
2183 #ifdef ZERO_VARIABLES_FOR_SEARCHING
2184 } else {
2185 /* Nodes are allocated by fc_calloc(), so should be already set to 0. */
2186 node->extra_tile = 0;
2187 #endif
2188 }
2189
2190 #ifdef ZERO_VARIABLES_FOR_SEARCHING
2191 /* Nodes are allocated by fc_calloc(), so should be already set to 0. */
2192 node->pos = NULL;
2193 node->segment = NULL;
2194 #endif
2195
2196 return TRUE;
2197 }
2198
2199 /****************************************************************************
2200 Returns whether this node is dangerous or not.
2201 ****************************************************************************/
pf_fuel_node_dangerous(const struct pf_fuel_node * node)2202 static inline bool pf_fuel_node_dangerous(const struct pf_fuel_node *node)
2203 {
2204 return (NULL == node->pos
2205 || (node->pos->moves_left < node->moves_left_req
2206 && PF_ACTION_NONE == node->action));
2207 }
2208
2209 /****************************************************************************
2210 Forget how we went to position. Maybe destroy the position, and previous
2211 ones.
2212 ****************************************************************************/
pf_fuel_pos_ref(struct pf_fuel_pos * pos)2213 static inline struct pf_fuel_pos *pf_fuel_pos_ref(struct pf_fuel_pos *pos)
2214 {
2215 #ifdef PF_DEBUG
2216 /* Unsure we have enough space to store the new count. Maximum is 10
2217 * (node->pos, node->segment, and 8 for other_pos->prev). */
2218 fc_assert(15 > pos->ref_count);
2219 #endif
2220 pos->ref_count++;
2221 return pos;
2222 }
2223
2224 /****************************************************************************
2225 Forget how we went to position. Maybe destroy the position, and previous
2226 ones.
2227 ****************************************************************************/
pf_fuel_pos_unref(struct pf_fuel_pos * pos)2228 static inline void pf_fuel_pos_unref(struct pf_fuel_pos *pos)
2229 {
2230 while (NULL != pos && 0 == --pos->ref_count) {
2231 struct pf_fuel_pos *prev = pos->prev;
2232
2233 free(pos);
2234 pos = prev;
2235 }
2236 }
2237
2238 /****************************************************************************
2239 Replace the position (unreferences it). Instead of destroying, re-use the
2240 memory, else return a newly allocated position.
2241 ****************************************************************************/
2242 static inline struct pf_fuel_pos *
pf_fuel_pos_replace(struct pf_fuel_pos * pos,const struct pf_fuel_node * node)2243 pf_fuel_pos_replace(struct pf_fuel_pos *pos, const struct pf_fuel_node *node)
2244 {
2245 if (NULL == pos) {
2246 pos = fc_malloc(sizeof(*pos));
2247 pos->ref_count = 1;
2248 } else if (1 < pos->ref_count) {
2249 pos->ref_count--;
2250 pos = fc_malloc(sizeof(*pos));
2251 pos->ref_count = 1;
2252 } else {
2253 #ifdef PF_DEBUG
2254 fc_assert(1 == pos->ref_count);
2255 #endif
2256 pf_fuel_pos_unref(pos->prev);
2257 }
2258 pos->cost = node->cost;
2259 pos->extra_cost = node->extra_cost;
2260 pos->moves_left = node->moves_left;
2261 pos->dir_to_here = node->dir_to_here;
2262 pos->prev = NULL;
2263
2264 return pos;
2265 }
2266
2267 /****************************************************************************
2268 Finalize the fuel position.
2269 ****************************************************************************/
2270 static inline void
pf_fuel_finalize_position_base(const struct pf_parameter * param,struct pf_position * pos,int cost,int moves_left)2271 pf_fuel_finalize_position_base(const struct pf_parameter *param,
2272 struct pf_position *pos,
2273 int cost, int moves_left)
2274 {
2275 int move_rate = param->move_rate;
2276
2277 pos->turn = pf_turns(param, cost);
2278 if (move_rate > 0 && param->start_tile != pos->tile) {
2279 pos->fuel_left = moves_left / move_rate;
2280 pos->moves_left = moves_left % move_rate;
2281 } else if (param->start_tile == pos->tile) {
2282 pos->fuel_left = param->fuel_left_initially;
2283 pos->moves_left = param->moves_left_initially;
2284 } else {
2285 pos->fuel_left = param->fuel_left_initially;
2286 pos->moves_left = moves_left;
2287 }
2288 }
2289
2290 /****************************************************************************
2291 Finalize the fuel position. If we have a fuel segment, then use it.
2292 ****************************************************************************/
2293 static inline void
pf_fuel_finalize_position(struct pf_position * pos,const struct pf_parameter * params,const struct pf_fuel_node * node,const struct pf_fuel_pos * head)2294 pf_fuel_finalize_position(struct pf_position *pos,
2295 const struct pf_parameter *params,
2296 const struct pf_fuel_node *node,
2297 const struct pf_fuel_pos *head)
2298 {
2299 if (head) {
2300 pf_fuel_finalize_position_base(params, pos,
2301 head->cost, head->moves_left);
2302 } else {
2303 pf_fuel_finalize_position_base(params, pos,
2304 node->cost, node->moves_left);
2305 }
2306 }
2307
2308 /****************************************************************************
2309 Fill in the position which must be discovered already. A helper
2310 for pf_fuel_map_position(). This also "finalizes" the position.
2311 ****************************************************************************/
pf_fuel_map_fill_position(const struct pf_fuel_map * pffm,struct tile * ptile,struct pf_position * pos)2312 static void pf_fuel_map_fill_position(const struct pf_fuel_map *pffm,
2313 struct tile *ptile,
2314 struct pf_position *pos)
2315 {
2316 int tindex = tile_index(ptile);
2317 struct pf_fuel_node *node = pffm->lattice + tindex;
2318 struct pf_fuel_pos *head = node->segment;
2319 const struct pf_parameter *params = pf_map_parameter(PF_MAP(pffm));
2320
2321 #ifdef PF_DEBUG
2322 fc_assert_ret_msg(NULL != head,
2323 "Unreached destination (%d, %d).", TILE_XY(ptile));
2324 #endif /* PF_DEBUG */
2325
2326 pos->tile = ptile;
2327 pos->total_EC = head->extra_cost;
2328 pos->total_MC = (head->cost - pf_move_rate(params)
2329 + pf_moves_left_initially(params));
2330 pos->dir_to_here = head->dir_to_here;
2331 pos->dir_to_next_pos = direction8_invalid(); /* This field does not apply. */
2332 pf_fuel_finalize_position(pos, params, node, head);
2333 }
2334
2335 /****************************************************************************
2336 This function returns the fill cost needed for a position, to get full
2337 moves at the next turn. This would be called only when the status is
2338 NS_WAITING.
2339 ****************************************************************************/
2340 static inline int
pf_fuel_map_fill_cost_for_full_moves(const struct pf_parameter * param,int cost,int moves_left)2341 pf_fuel_map_fill_cost_for_full_moves(const struct pf_parameter *param,
2342 int cost, int moves_left)
2343 {
2344 #ifdef PF_DEBUG
2345 fc_assert(0 < param->move_rate);
2346 #endif /* PF_DEBUG */
2347 return cost + moves_left % param->move_rate;
2348 }
2349
2350 /****************************************************************************
2351 Read off the path to the node 'ptile', but with fuel danger.
2352 ****************************************************************************/
2353 static struct pf_path *
pf_fuel_map_construct_path(const struct pf_fuel_map * pffm,struct tile * ptile)2354 pf_fuel_map_construct_path(const struct pf_fuel_map *pffm,
2355 struct tile *ptile)
2356 {
2357 struct pf_path *path = fc_malloc(sizeof(*path));
2358 enum direction8 dir_next = direction8_invalid();
2359 struct pf_fuel_node *node = pffm->lattice + tile_index(ptile);
2360 struct pf_fuel_pos *segment = node->segment;
2361 int length = 1;
2362 struct tile *iter_tile = ptile;
2363 const struct pf_parameter *params = pf_map_parameter(PF_MAP(pffm));
2364 struct pf_position *pos;
2365 int i;
2366
2367 #ifdef PF_DEBUG
2368 fc_assert_ret_val_msg(NULL != segment, NULL,
2369 "Unreached destination (%d, %d).",
2370 TILE_XY(ptile));
2371 #endif /* PF_DEBUG */
2372
2373 /* First iterate to find path length. */
2374 /* NB: the start point could be reached in the middle of a segment.
2375 * See comment for pf_fuel_map_create_segment(). */
2376 while (direction8_is_valid(segment->dir_to_here)) {
2377 if (node->moves_left_req == 0) {
2378 /* A refuel point. */
2379 if (segment != node->segment) {
2380 length += 2;
2381 segment = node->segment;
2382 } else {
2383 length++;
2384 }
2385 } else {
2386 length++;
2387 }
2388
2389 /* Step backward. */
2390 iter_tile = mapstep(iter_tile, DIR_REVERSE(segment->dir_to_here));
2391 node = pffm->lattice + tile_index(iter_tile);
2392 segment = segment->prev;
2393 #ifdef PF_DEBUG
2394 fc_assert(NULL != segment);
2395 #endif /* PF_DEBUG */
2396 }
2397 if (node->moves_left_req == 0 && segment != node->segment) {
2398 /* We wait at the start point */
2399 length++;
2400 }
2401
2402 /* Allocate memory for path. */
2403 path->positions = fc_malloc(length * sizeof(struct pf_position));
2404 path->length = length;
2405
2406 /* Reset variables for main iteration. */
2407 iter_tile = ptile;
2408 node = pffm->lattice + tile_index(ptile);
2409 segment = node->segment;
2410
2411 for (i = length - 1; i >= 0; i--) {
2412 /* 1: Deal with waiting. */
2413 if (node->moves_left_req == 0 && segment != node->segment) {
2414 /* Waited at _this_ tile, need to record it twice in the
2415 * path. Here we record our state _after_ waiting (e.g.
2416 * full move points). */
2417 pos = path->positions + i;
2418 pos->tile = iter_tile;
2419 pos->total_EC = segment->extra_cost;
2420 pos->turn = pf_turns(params, segment->cost);
2421 pos->total_MC = ((pos->turn - 1) * params->move_rate
2422 + params->moves_left_initially);
2423 pos->moves_left = params->move_rate;
2424 pos->fuel_left = params->fuel;
2425 pos->dir_to_next_pos = dir_next;
2426 dir_next = direction8_invalid();
2427 segment = node->segment;
2428 i--;
2429 if (NULL == segment) {
2430 /* We waited at start tile, then 'node->segment' is not set. */
2431 #ifdef PF_DEBUG
2432 fc_assert(iter_tile == params->start_tile);
2433 fc_assert(0 == i);
2434 #endif /* PF_DEBUG */
2435 pf_position_fill_start_tile(path->positions, params);
2436 return path;
2437 }
2438 }
2439
2440 /* 2: Fill the current position. */
2441 pos = path->positions + i;
2442 pos->tile = iter_tile;
2443 pos->total_MC = (pf_moves_left_initially(params)
2444 - pf_move_rate(params) + segment->cost);
2445 pos->total_EC = segment->extra_cost;
2446 pos->dir_to_next_pos = dir_next;
2447 pf_fuel_finalize_position(pos, params, node, segment);
2448
2449 /* 3: Check if we finished. */
2450 if (i == 0) {
2451 /* We should be back at the start now! */
2452 fc_assert_ret_val(iter_tile == params->start_tile, NULL);
2453 return path;
2454 }
2455
2456 /* 4: Calculate the next direction. */
2457 dir_next = segment->dir_to_here;
2458
2459 /* 5: Step further back. */
2460 iter_tile = mapstep(iter_tile, DIR_REVERSE(dir_next));
2461 node = pffm->lattice + tile_index(iter_tile);
2462 segment = segment->prev;
2463 #ifdef PF_DEBUG
2464 fc_assert(NULL != segment);
2465 #endif /* PF_DEBUG */
2466 }
2467
2468 fc_assert_msg(FALSE, "Cannot get to the starting point!");
2469 return NULL;
2470 }
2471
2472 /****************************************************************************
2473 Creating path segment going back from node1 to a safe tile. We need to
2474 remember the whole segment because any node can be crossed by many fuel
2475 segments.
2476
2477 Example: be A, a refuel point, B and C not. We start the path from B and
2478 have only (3 * SINGLE_MOVE) moves lefts:
2479 A B C
2480 B cannot move to C because we would have only (1 * SINGLE_MOVE) move left
2481 reaching it, and the refuel point is too far. So C->moves_left_req =
2482 (4 * SINGLE_MOVE).
2483 The path would be to return to A, wait the end of turn to get full moves,
2484 and go to C. In a single line: B A B C. So, the point B would be reached
2485 twice. but, it needs to stores different data for B->cost, B->extra_cost,
2486 B->moves_left, and B->dir_to_here. That's why we need to record every
2487 path to unsafe nodes (not for refuel points).
2488 ****************************************************************************/
pf_fuel_map_create_segment(struct pf_fuel_map * pffm,struct tile * ptile,struct pf_fuel_node * node)2489 static inline void pf_fuel_map_create_segment(struct pf_fuel_map *pffm,
2490 struct tile *ptile,
2491 struct pf_fuel_node *node)
2492 {
2493 struct pf_fuel_pos *pos, *next;
2494
2495 pos = pf_fuel_pos_replace(node->pos, node);
2496 node->pos = pos;
2497
2498 /* Iterate until we reach any built segment. */
2499 do {
2500 next = pos;
2501 ptile = mapstep(ptile, DIR_REVERSE(node->dir_to_here));
2502 node = pffm->lattice + tile_index(ptile);
2503 pos = node->pos;
2504 if (NULL != pos) {
2505 if (pos->cost == node->cost
2506 && pos->dir_to_here == node->dir_to_here
2507 && pos->extra_cost == node->extra_cost
2508 && pos->moves_left == node->moves_left) {
2509 /* Reached an usable segment. */
2510 next->prev = pf_fuel_pos_ref(pos);
2511 break;
2512 }
2513 }
2514 /* Update position. */
2515 pos = pf_fuel_pos_replace(pos, node);
2516 node->pos = pos;
2517 next->prev = pf_fuel_pos_ref(pos);
2518 } while (0 != node->moves_left_req && direction8_is_valid(node->dir_to_here));
2519 }
2520
2521 /****************************************************************************
2522 Adjust cost for move_rate and fuel usage.
2523 ****************************************************************************/
pf_fuel_map_adjust_cost(int cost,int moves_left,int move_rate)2524 static inline int pf_fuel_map_adjust_cost(int cost, int moves_left,
2525 int move_rate)
2526 {
2527 if (move_rate > 0) {
2528 int remaining_moves = moves_left % move_rate;
2529
2530 if (remaining_moves == 0) {
2531 remaining_moves = move_rate;
2532 }
2533
2534 return MIN(cost, remaining_moves);
2535 } else {
2536 return MIN(cost, moves_left);
2537 }
2538 }
2539
2540 /****************************************************************************
2541 This function returns whether a unit with or without fuel can attack.
2542
2543 moves_left: moves left before the attack.
2544 moves_left_req: required moves left to hold on the tile after attacking.
2545 ****************************************************************************/
2546 static inline bool
pf_fuel_map_attack_is_possible(const struct pf_parameter * param,int moves_left,int moves_left_req)2547 pf_fuel_map_attack_is_possible(const struct pf_parameter *param,
2548 int moves_left, int moves_left_req)
2549 {
2550 if (uclass_has_flag(utype_class(param->utype), UCF_MISSILE)) {
2551 /* Case missile */
2552 return TRUE;
2553 } else if (utype_has_flag(param->utype, UTYF_ONEATTACK)) {
2554 /* Case Bombers */
2555 if (moves_left <= param->move_rate) {
2556 /* We are in the last turn of fuel, don't attack */
2557 return FALSE;
2558 } else {
2559 return TRUE;
2560 }
2561 } else {
2562 /* Case fighters */
2563 if (moves_left - SINGLE_MOVE < moves_left_req) {
2564 return FALSE;
2565 } else {
2566 return TRUE;
2567 }
2568 }
2569 }
2570
2571 /****************************************************************************
2572 Primary method for iterative path-finding for fuel units.
2573 Notes:
2574 1. We process nodes in the main queue, like for normal maps. Because we
2575 process in a different queue common tiles (!= refuel points), we needed
2576 to register every path to any tile from a refuel point or the start tile
2577 (see comment for pf_fuel_map_create_segment()).
2578 2. Waiting is realised by inserting the refuel point back into the main
2579 queue with a lower priority P. Because this tile might pop back sooner
2580 than P, because there might be several copies of it in the queue already,
2581 we *must* delete all these copies, to preserve the priority of the
2582 process.
2583 3. For some purposes, NS_WAITING is just another flavour of NS_PROCESSED,
2584 since the path to a NS_WAITING tile has already been found.
2585 4. This algorithm cannot guarantee the best safe segments across dangerous
2586 region. However it will find a safe segment if there is one. To
2587 gurantee the best (in terms of total_CC) safe segments across danger,
2588 supply 'get_EC' which returns small extra on dangerous tiles.
2589
2590 During the iteration, the node status will be changed:
2591 A. NS_UNINIT: The node is not initialized, we didn't reach it at all.
2592 B. NS_INIT: We have initialized the cached values, however, we failed to
2593 reach this node.
2594 C. NS_NEW: We have reached this node, but we are not sure it was the best
2595 path.
2596 D. NS_PROCESSED: Now, we are sure we have the best path. Not refuel node
2597 can even be processed.
2598 E. NS_WAITING: The refuel node is re-inserted in the priority queue, as
2599 explained above (2.). We need to consider if waiting for full moves
2600 open or not new possibilities for moving.
2601 F. NS_PROCESSED: When finished to consider waiting at the node, revert the
2602 status to NS_PROCESSED.
2603 In points D., E., and F., the best path to the node can be considered as
2604 found.
2605 ****************************************************************************/
pf_fuel_map_iterate(struct pf_map * pfm)2606 static bool pf_fuel_map_iterate(struct pf_map *pfm)
2607 {
2608 struct pf_fuel_map *const pffm = PF_FUEL_MAP(pfm);
2609 const struct pf_parameter *const params = pf_map_parameter(pfm);
2610 struct tile *tile = pfm->tile;
2611 int tindex = tile_index(tile);
2612 struct pf_fuel_node *node = pffm->lattice + tindex;
2613 enum pf_move_scope scope = node->move_scope;
2614 int priority, waited_priority;
2615 bool waited = FALSE;
2616
2617 /* The previous position is defined by 'tile' (tile pointer), 'node'
2618 * (the data of the tile for the pf_map), and index (the index of the
2619 * position in the Freeciv map). */
2620
2621 if (!direction8_is_valid(node->dir_to_here)
2622 && NULL != params->transported_by_initially) {
2623 #ifdef PF_DEBUG
2624 fc_assert(tile == params->start_tile);
2625 #endif
2626 scope |= PF_MS_TRANSPORT;
2627 if (!utype_can_freely_unload(params->utype,
2628 params->transported_by_initially)
2629 && NULL == tile_city(tile)
2630 && !tile_has_native_base(tile, params->transported_by_initially)) {
2631 /* Cannot disembark, don't leave transporter. */
2632 node->behavior = TB_DONT_LEAVE;
2633 }
2634 }
2635
2636 for (;;) {
2637 /* There is no exit from DONT_LEAVE tiles! */
2638 if (node->behavior != TB_DONT_LEAVE
2639 && scope != PF_MS_NONE
2640 && (params->move_rate > 0 || node->cost < 0)) {
2641 int loc_cost = node->cost;
2642 int loc_moves_left = node->moves_left;
2643
2644 if (0 == node->moves_left_req
2645 && 0 < params->move_rate
2646 && 0 == loc_moves_left % params->move_rate
2647 && loc_cost >= params->moves_left_initially) {
2648 /* We have implicitly refueled at the end of the turn. Update also
2649 * 'node->moves_left' to ensure to wait there in paths. */
2650 loc_moves_left = pf_move_rate(params);
2651 node->moves_left = loc_moves_left;
2652 }
2653
2654 adjc_dir_iterate(tile, tile1, dir) {
2655 /* Calculate the cost of every adjacent position and set them in
2656 * the priority queues for next call to pf_fuel_map_iterate(). */
2657 int tindex1 = tile_index(tile1);
2658 struct pf_fuel_node *node1 = pffm->lattice + tindex1;
2659 int cost, extra = 0;
2660 int moves_left;
2661 int cost_of_path, old_cost_of_path;
2662 struct pf_fuel_pos *pos;
2663
2664 /* As for the previous position, 'tile1', 'node1' and 'tindex1' are
2665 * defining the adjacent position. */
2666
2667 /* Non-full fuel tiles can be updated even after being processed. */
2668 if ((NS_PROCESSED == node1->status || NS_WAITING == node1->status)
2669 && 0 == node1->moves_left_req) {
2670 /* This gives 15% speedup. */
2671 continue;
2672 }
2673
2674 /* Initialise target tile if necessary */
2675 if (node1->status == NS_UNINIT) {
2676 /* Only initialize once. See comment for pf_fuel_node_init().
2677 * Node status step A. to B. */
2678 if (!pf_fuel_node_init(pffm, node1, tile1, scope)) {
2679 continue;
2680 }
2681 } else if (TB_IGNORE == node1->behavior) {
2682 /* We cannot enter this tile at all! */
2683 continue;
2684 }
2685
2686 /* Is the move ZOC-ok? */
2687 if (node->zoc_number != ZOC_MINE && node1->zoc_number == ZOC_NO) {
2688 continue;
2689 }
2690
2691 cost = node1->cost_to_here[dir];
2692 if (0 == cost) {
2693 /* Evaluate the cost of the move. */
2694 if (PF_ACTION_NONE != node1->action) {
2695 if (NULL != params->is_action_possible
2696 && !params->is_action_possible(tile, scope, tile1,
2697 node1->action, params)) {
2698 node1->cost_to_here[dir] = PF_IMPOSSIBLE_MC + 2;
2699 continue;
2700 }
2701 /* action move cost depends on action and unit type. */
2702 if (node1->action == PF_ACTION_ATTACK
2703 && (utype_has_flag(params->utype, UTYF_ONEATTACK)
2704 || uclass_has_flag(utype_class(params->utype),
2705 UCF_MISSILE))) {
2706 cost = params->move_rate;
2707 } else {
2708 cost = SINGLE_MOVE;
2709 }
2710 } else if (node1->node_known_type == TILE_UNKNOWN) {
2711 cost = params->utype->unknown_move_cost;
2712 } else {
2713 cost = params->get_MC(tile, scope, tile1, node1->move_scope,
2714 params);
2715 }
2716
2717 if (cost == FC_INFINITY) {
2718 /* tile_move_cost_ptrs() uses FC_INFINITY to flag that all
2719 * movement is spent, e.g., when disembarking from transport. */
2720 cost = params->move_rate;
2721 }
2722
2723 #ifdef PF_DEBUG
2724 fc_assert(1 << (8 * sizeof(node1->cost_to_here[dir])) > cost + 2);
2725 fc_assert(0 < cost + 2);
2726 #endif /* PF_DEBUG */
2727
2728 node1->cost_to_here[dir] = cost + 2;
2729 if (cost == PF_IMPOSSIBLE_MC) {
2730 continue;
2731 }
2732 } else if (cost == PF_IMPOSSIBLE_MC + 2) {
2733 continue;
2734 } else {
2735 cost -= 2;
2736 }
2737
2738 cost = pf_fuel_map_adjust_cost(cost, loc_moves_left,
2739 params->move_rate);
2740
2741 moves_left = loc_moves_left - cost;
2742 if (moves_left < node1->moves_left_req
2743 && (!uclass_has_flag(utype_class(params->utype), UCF_MISSILE)
2744 || 0 > moves_left)) {
2745 /* We don't have enough moves left, but missiles
2746 * can do suicidal attacks. */
2747 continue;
2748 }
2749
2750 if (PF_ACTION_ATTACK == node1->action
2751 && !pf_fuel_map_attack_is_possible(params, loc_moves_left,
2752 node->moves_left_req)) {
2753 /* We wouldn't have enough moves left after attacking. */
2754 continue;
2755 }
2756
2757 /* Total cost at 'tile1' */
2758 cost += loc_cost;
2759
2760 /* Evaluate the extra cost of the destination, if it's relevant. */
2761 if (NULL != params->get_EC) {
2762 extra = node1->extra_tile + node->extra_cost;
2763 }
2764
2765 /* Update costs and add to queue, if this is a better route
2766 * to tile1. Case safe tiles or reached directly without waiting. */
2767 pos = node1->segment;
2768 cost_of_path = pf_fuel_total_CC(params, cost, extra,
2769 moves_left - node1->moves_left_req);
2770 if (node1->status == NS_INIT) {
2771 /* Not calculated yet. */
2772 old_cost_of_path = 0;
2773 } else if (pos) {
2774 /* We have a path to this tile. The default values could have been
2775 * overwritten if we had more moves left to deal with waiting.
2776 * Then, we have to get back the value of this node to calculate
2777 * the cost. */
2778 old_cost_of_path =
2779 pf_fuel_total_CC(params, pos->cost, pos->extra_cost,
2780 pos->moves_left - node1->moves_left_req);
2781 } else {
2782 /* Default cost */
2783 old_cost_of_path =
2784 pf_fuel_total_CC(params, node1->cost, node1->extra_cost,
2785 node1->moves_left - node1->moves_left_req);
2786 }
2787
2788 /* Step 1: We test if this route is the best to this tile, by a
2789 * direct way, not taking in account waiting. */
2790
2791 if (NS_INIT == node1->status
2792 || (node1->status == NS_NEW && cost_of_path < old_cost_of_path)) {
2793 /* We are reaching this node for the first time, or we found a
2794 * better route to 'tile1', or we would have more moves lefts
2795 * at previous position. Let's register 'tindex1' to the
2796 * priority queue. */
2797 node1->extra_cost = extra;
2798 node1->cost = cost;
2799 node1->moves_left = moves_left;
2800 node1->dir_to_here = dir;
2801 /* Always record the segment, including when it is not dangerous
2802 * to move there. */
2803 pf_fuel_map_create_segment(pffm, tile1, node1);
2804 if (NS_INIT == node1->status) {
2805 /* Node status B. to C. */
2806 node1->status = NS_NEW;
2807 map_index_pq_insert(pffm->queue, tindex1, -cost_of_path);
2808 } else {
2809 /* else staying at D. */
2810 #ifdef PF_DEBUG
2811 fc_assert(NS_NEW == node1->status);
2812 #endif
2813 if (cost_of_path < old_cost_of_path) {
2814 map_index_pq_replace(pffm->queue, tindex1, -cost_of_path);
2815 }
2816 }
2817 continue; /* adjc_dir_iterate() */
2818 }
2819
2820 /* Step 2: We test if this route could open better routes for other
2821 * tiles, if we waited somewhere. */
2822
2823 if (!waited
2824 || NS_NEW == node1->status
2825 || 0 == node1->moves_left_req) {
2826 /* Stops there if:
2827 * 1. we didn't wait to get there ;
2828 * 2. we didn't process yet the node ;
2829 * 3. this is a refuel point. */
2830 continue; /* adjc_dir_iterate() */
2831 }
2832
2833 #ifdef PF_DEBUG
2834 fc_assert(NS_PROCESSED == node1->status);
2835 #endif
2836
2837 if (moves_left > node1->moves_left
2838 || (moves_left == node1->moves_left
2839 && extra < node1->extra_cost)) {
2840 /* We will update costs if:
2841 * 1. we would have more moves left than previously on this node.
2842 * 2. we can have lower extra and will not overwrite anything
2843 * useful. */
2844 node1->extra_cost = extra;
2845 node1->cost = cost;
2846 node1->moves_left = moves_left;
2847 node1->dir_to_here = dir;
2848 map_index_pq_insert(pffm->waited_queue, tindex1,
2849 -pf_fuel_waited_total_CC(cost,
2850 moves_left - node1->moves_left_req));
2851 }
2852 } adjc_dir_iterate_end;
2853 }
2854
2855 if (NS_WAITING == node->status) {
2856 /* Node status final step E. to F. */
2857 #ifdef PF_DEBUG
2858 fc_assert(0 == node->moves_left_req);
2859 #endif
2860 node->status = NS_PROCESSED;
2861 } else if (0 == node->moves_left_req
2862 && PF_ACTION_NONE == node->action
2863 && node->moves_left < pf_move_rate(params)
2864 #ifdef PF_DEBUG
2865 && (fc_assert(0 < params->move_rate), 0 < params->move_rate)
2866 #endif
2867 && (0 != node->moves_left % params->move_rate
2868 || node->cost < params->moves_left_initially)) {
2869 /* Consider waiting at this node. To do it, put it back into queue.
2870 * Node status final step D. to E. */
2871 node->status = NS_WAITING;
2872 /* The values we use now to calculate waited total_CC
2873 * will be applied to the node after we get it back from the queue
2874 * to get passing-by segments before it without waiting */
2875 map_index_pq_insert(pffm->queue, tindex,
2876 -pf_fuel_waited_total_CC
2877 (pf_fuel_map_fill_cost_for_full_moves(params,
2878 node->cost,
2879 node->moves_left),
2880 pf_move_rate(params)));
2881 }
2882
2883 /* Get the next node (the index with the highest priority). First try
2884 * to get it from waited_queue. */
2885 if (!map_index_pq_priority(pffm->queue, &priority)
2886 || (map_index_pq_priority(pffm->waited_queue, &waited_priority)
2887 && priority < waited_priority)) {
2888 if (!map_index_pq_remove(pffm->waited_queue, &tindex)) {
2889 /* End of the iteration. */
2890 return FALSE;
2891 }
2892
2893 /* Change the pf_map iterator and reset data. */
2894 tile = index_to_tile(tindex);
2895 pfm->tile = tile;
2896 node = pffm->lattice + tindex;
2897 waited = TRUE;
2898 #ifdef PF_DEBUG
2899 fc_assert(0 < node->moves_left_req);
2900 fc_assert(NS_PROCESSED == node->status);
2901 #endif
2902 } else {
2903 #ifdef PF_DEBUG
2904 bool success = map_index_pq_remove(pffm->queue, &tindex);
2905
2906 fc_assert(TRUE == success);
2907 #else
2908 map_index_pq_remove(pffm->queue, &tindex);
2909 #endif
2910
2911 /* Change the pf_map iterator and reset data. */
2912 tile = index_to_tile(tindex);
2913 pfm->tile = tile;
2914 node = pffm->lattice + tindex;
2915
2916 #ifdef PF_DEBUG
2917 fc_assert(NS_PROCESSED != node->status);
2918 #endif /* PF_DEBUG */
2919
2920 waited = (NS_WAITING == node->status);
2921 if (waited) {
2922 /* Arrange waiting at the node */
2923 node->cost = pf_fuel_map_fill_cost_for_full_moves(params, node->cost,
2924 node->moves_left);
2925 node->moves_left = pf_move_rate(params);
2926 } else if (!pf_fuel_node_dangerous(node)) {
2927 /* Node status step C. and D. */
2928 node->status = NS_PROCESSED;
2929 node->segment = pf_fuel_pos_ref(node->pos);
2930 return TRUE;
2931 }
2932 }
2933
2934 #ifdef PF_DEBUG
2935 fc_assert(NS_INIT < node->status);
2936
2937 if (NS_WAITING == node->status) {
2938 /* We've already returned this node once, skip it. */
2939 log_debug("Considering waiting at (%d, %d)", TILE_XY(tile));
2940 } else if (NS_PROCESSED == node->status) {
2941 /* We've already returned this node once, skip it. */
2942 log_debug("Reprocessing tile (%d, %d)", TILE_XY(tile));
2943 } else if (pf_fuel_node_dangerous(node)) {
2944 /* We don't return dangerous tiles. */
2945 log_debug("Reached dangerous tile (%d, %d)", TILE_XY(tile));
2946 }
2947 #endif /* PF_DEBUG */
2948
2949 scope = node->move_scope;
2950 }
2951
2952 log_error("%s(): internal error.", __FUNCTION__);
2953 return FALSE;
2954 }
2955
2956 /****************************************************************************
2957 Iterate the map until 'ptile' is reached.
2958 ****************************************************************************/
pf_fuel_map_iterate_until(struct pf_fuel_map * pffm,struct tile * ptile)2959 static inline bool pf_fuel_map_iterate_until(struct pf_fuel_map *pffm,
2960 struct tile *ptile)
2961 {
2962 struct pf_map *pfm = PF_MAP(pffm);
2963 struct pf_fuel_node *node = pffm->lattice + tile_index(ptile);
2964
2965 /* Start position is handled in every function calling this function. */
2966
2967 if (NS_UNINIT == node->status) {
2968 /* Initialize the node, for doing the following tests. */
2969 if (!pf_fuel_node_init(pffm, node, ptile, PF_MS_NONE)) {
2970 return FALSE;
2971 }
2972 } else if (TB_IGNORE == node->behavior) {
2973 /* Simpliciation: if we cannot enter this node at all, don't iterate the
2974 * whole map. */
2975 return FALSE;
2976 }
2977
2978 while (NULL == node->segment) {
2979 if (!pf_map_iterate(pfm)) {
2980 /* All reachable destination have been iterated, 'ptile' is
2981 * unreachable. */
2982 return FALSE;
2983 }
2984 }
2985
2986 return TRUE;
2987 }
2988
2989 /****************************************************************************
2990 Return the move cost at ptile. If 'ptile' has not been reached yet,
2991 iterate the map until we reach it or run out of map. This function
2992 returns PF_IMPOSSIBLE_MC on unreachable positions.
2993 ****************************************************************************/
pf_fuel_map_move_cost(struct pf_map * pfm,struct tile * ptile)2994 static int pf_fuel_map_move_cost(struct pf_map *pfm, struct tile *ptile)
2995 {
2996 struct pf_fuel_map *pffm = PF_FUEL_MAP(pfm);
2997
2998 if (ptile == pfm->params.start_tile) {
2999 return 0;
3000 } else if (pf_fuel_map_iterate_until(pffm, ptile)) {
3001 const struct pf_fuel_node *node = pffm->lattice + tile_index(ptile);
3002
3003 return (node->segment->cost
3004 - pf_move_rate(pf_map_parameter(pfm))
3005 + pf_moves_left_initially(pf_map_parameter(pfm)));
3006 } else {
3007 return PF_IMPOSSIBLE_MC;
3008 }
3009 }
3010
3011 /****************************************************************************
3012 Return the path to ptile. If 'ptile' has not been reached yet, iterate
3013 the map until we reach it or run out of map.
3014 ****************************************************************************/
pf_fuel_map_path(struct pf_map * pfm,struct tile * ptile)3015 static struct pf_path *pf_fuel_map_path(struct pf_map *pfm,
3016 struct tile *ptile)
3017 {
3018 struct pf_fuel_map *pffm = PF_FUEL_MAP(pfm);
3019
3020 if (ptile == pfm->params.start_tile) {
3021 return pf_path_new_to_start_tile(pf_map_parameter(pfm));
3022 } else if (pf_fuel_map_iterate_until(pffm, ptile)) {
3023 return pf_fuel_map_construct_path(pffm, ptile);
3024 } else {
3025 return NULL;
3026 }
3027 }
3028
3029 /****************************************************************************
3030 Get info about position at ptile and put it in pos. If 'ptile' has not
3031 been reached yet, iterate the map until we reach it. Should _always_
3032 check the return value, forthe position might be unreachable.
3033 ****************************************************************************/
pf_fuel_map_position(struct pf_map * pfm,struct tile * ptile,struct pf_position * pos)3034 static bool pf_fuel_map_position(struct pf_map *pfm, struct tile *ptile,
3035 struct pf_position *pos)
3036 {
3037 struct pf_fuel_map *pffm = PF_FUEL_MAP(pfm);
3038
3039 if (ptile == pfm->params.start_tile) {
3040 pf_position_fill_start_tile(pos, pf_map_parameter(pfm));
3041 return TRUE;
3042 } else if (pf_fuel_map_iterate_until(pffm, ptile)) {
3043 pf_fuel_map_fill_position(pffm, ptile, pos);
3044 return TRUE;
3045 } else {
3046 return FALSE;
3047 }
3048 }
3049
3050 /****************************************************************************
3051 'pf_fuel_map' destructor.
3052 ****************************************************************************/
pf_fuel_map_destroy(struct pf_map * pfm)3053 static void pf_fuel_map_destroy(struct pf_map *pfm)
3054 {
3055 struct pf_fuel_map *pffm = PF_FUEL_MAP(pfm);
3056 struct pf_fuel_node *node;
3057 int i;
3058
3059 /* Need to clean up the dangling fuel segments. */
3060 for (i = 0, node = pffm->lattice; i < MAP_INDEX_SIZE; i++, node++) {
3061 pf_fuel_pos_unref(node->pos);
3062 pf_fuel_pos_unref(node->segment);
3063 }
3064 free(pffm->lattice);
3065 map_index_pq_destroy(pffm->queue);
3066 map_index_pq_destroy(pffm->waited_queue);
3067 free(pffm);
3068 }
3069
3070 /****************************************************************************
3071 'pf_fuel_map' constructor.
3072 ****************************************************************************/
pf_fuel_map_new(const struct pf_parameter * parameter)3073 static struct pf_map *pf_fuel_map_new(const struct pf_parameter *parameter)
3074 {
3075 struct pf_fuel_map *pffm;
3076 struct pf_map *base_map;
3077 struct pf_parameter *params;
3078 struct pf_fuel_node *node;
3079
3080 pffm = fc_malloc(sizeof(*pffm));
3081 base_map = &pffm->base_map;
3082 params = &base_map->params;
3083 #ifdef PF_DEBUG
3084 /* Set the mode, used for cast check. */
3085 base_map->mode = PF_FUEL;
3086 #endif /* PF_DEBUG */
3087
3088 /* Allocate the map. */
3089 pffm->lattice = fc_calloc(MAP_INDEX_SIZE, sizeof(struct pf_fuel_node));
3090 pffm->queue = map_index_pq_new(INITIAL_QUEUE_SIZE);
3091 pffm->waited_queue = map_index_pq_new(INITIAL_QUEUE_SIZE);
3092
3093 /* 'get_MC' callback must be set. */
3094 fc_assert_ret_val(parameter->get_MC != NULL, NULL);
3095
3096 /* 'get_moves_left_req' callback must be set. */
3097 fc_assert_ret_val(parameter->get_moves_left_req != NULL, NULL);
3098
3099 /* 'get_move_scope' callback must be set. */
3100 fc_assert_ret_val(parameter->get_move_scope != NULL, NULL);
3101
3102 /* Copy parameters. */
3103 *params = *parameter;
3104
3105 /* Initialize virtual function table. */
3106 base_map->destroy = pf_fuel_map_destroy;
3107 base_map->get_move_cost = pf_fuel_map_move_cost;
3108 base_map->get_path = pf_fuel_map_path;
3109 base_map->get_position = pf_fuel_map_position;
3110 base_map->iterate = pf_fuel_map_iterate;
3111
3112 /* Initialise starting node. */
3113 node = pffm->lattice + tile_index(params->start_tile);
3114 if (!pf_fuel_node_init(pffm, node, params->start_tile, PF_MS_NONE)) {
3115 /* Always fails. */
3116 fc_assert(TRUE == pf_fuel_node_init(pffm, node, params->start_tile,
3117 PF_MS_NONE));
3118 }
3119
3120 /* NB: do not handle params->transported_by_initially because we want to
3121 * handle only at start, not when crossing over the start tile for a
3122 * second time. See pf_danger_map_iterate(). */
3123
3124 /* Initialise the iterator. */
3125 base_map->tile = params->start_tile;
3126
3127 /* This makes calculations of turn/moves_left more convenient, but we
3128 * need to subtract this value before we return cost to the user. Note
3129 * that cost may be negative if moves_left_initially > move_rate
3130 * (see pf_turns()). */
3131 node->moves_left = pf_moves_left_initially(params);
3132 node->cost = pf_move_rate(params) - node->moves_left;
3133 node->extra_cost = 0;
3134 node->dir_to_here = direction8_invalid();
3135 /* Record a segment. We need it for correct paths. */
3136 node->segment
3137 = pf_fuel_pos_ref(node->pos = pf_fuel_pos_replace(NULL, node));
3138 node->status = NS_PROCESSED;
3139
3140 return PF_MAP(pffm);
3141 }
3142
3143
3144
3145 /* ====================== pf_map public functions ======================= */
3146
3147 /****************************************************************************
3148 Factory function to create a new map according to the parameter.
3149 Does not do any iterations.
3150 ****************************************************************************/
pf_map_new(const struct pf_parameter * parameter)3151 struct pf_map *pf_map_new(const struct pf_parameter *parameter)
3152 {
3153 if (parameter->is_pos_dangerous) {
3154 if (parameter->get_moves_left_req) {
3155 log_error("path finding code cannot deal with dangers "
3156 "and fuel together.");
3157 }
3158 if (parameter->get_costs) {
3159 log_error("jumbo callbacks for danger maps are not yet implemented.");
3160 }
3161 return pf_danger_map_new(parameter);
3162 } else if (parameter->get_moves_left_req) {
3163 if (parameter->get_costs) {
3164 log_error("jumbo callbacks for fuel maps are not yet implemented.");
3165 }
3166 return pf_fuel_map_new(parameter);
3167 }
3168
3169 return pf_normal_map_new(parameter);
3170 }
3171
3172 /****************************************************************************
3173 After usage the map must be destroyed.
3174 ****************************************************************************/
pf_map_destroy(struct pf_map * pfm)3175 void pf_map_destroy(struct pf_map *pfm)
3176 {
3177 #ifdef PF_DEBUG
3178 fc_assert_ret(NULL != pfm);
3179 #endif
3180 pfm->destroy(pfm);
3181 }
3182
3183 /****************************************************************************
3184 Tries to find the minimal move cost to reach ptile. Returns
3185 PF_IMPOSSIBLE_MC if not reachable. If ptile has not been reached yet,
3186 iterate the map until we reach it or run out of map.
3187 ****************************************************************************/
pf_map_move_cost(struct pf_map * pfm,struct tile * ptile)3188 int pf_map_move_cost(struct pf_map *pfm, struct tile *ptile)
3189 {
3190 #ifdef PF_DEBUG
3191 fc_assert_ret_val(NULL != pfm, PF_IMPOSSIBLE_MC);
3192 fc_assert_ret_val(NULL != ptile, PF_IMPOSSIBLE_MC);
3193 #endif
3194 return pfm->get_move_cost(pfm, ptile);
3195 }
3196
3197 /***************************************************************************
3198 Tries to find the best path in the given map to the position ptile.
3199 If NULL is returned no path could be found. The pf_path_last_position()
3200 of such path would be the same (almost) as the result of the call to
3201 pf_map_position(). If ptile has not been reached yet, iterate the map
3202 until we reach it or run out of map.
3203 ****************************************************************************/
pf_map_path(struct pf_map * pfm,struct tile * ptile)3204 struct pf_path *pf_map_path(struct pf_map *pfm, struct tile *ptile)
3205 {
3206 #ifdef PF_DEBUG
3207 struct pf_path *path;
3208
3209 fc_assert_ret_val(NULL != pfm, NULL);
3210 fc_assert_ret_val(NULL != ptile, NULL);
3211 path = pfm->get_path(pfm, ptile);
3212
3213 if (path != NULL) {
3214 const struct pf_parameter *param = pf_map_parameter(pfm);
3215 const struct pf_position *pos = &path->positions[0];
3216
3217 fc_assert(path->length >= 1);
3218 fc_assert(pos->tile == param->start_tile);
3219 fc_assert(pos->moves_left == param->moves_left_initially);
3220 fc_assert(pos->fuel_left == param->fuel_left_initially);
3221 }
3222
3223 return path;
3224 #else
3225 return pfm->get_path(pfm, ptile);
3226 #endif
3227 }
3228
3229 /****************************************************************************
3230 Get info about position at ptile and put it in pos. If ptile has not been
3231 reached yet, iterate the map until we reach it. Should _always_ check the
3232 return value, forthe position might be unreachable.
3233 ****************************************************************************/
pf_map_position(struct pf_map * pfm,struct tile * ptile,struct pf_position * pos)3234 bool pf_map_position(struct pf_map *pfm, struct tile *ptile,
3235 struct pf_position *pos)
3236 {
3237 #ifdef PF_DEBUG
3238 fc_assert_ret_val(NULL != pfm, FALSE);
3239 fc_assert_ret_val(NULL != ptile, FALSE);
3240 #endif
3241 return pfm->get_position(pfm, ptile, pos);
3242 }
3243
3244 /****************************************************************************
3245 Iterates the path-finding algorithm one step further, to the next nearest
3246 position. This full info on this position and the best path to it can be
3247 obtained using pf_map_iter_move_cost(), pf_map_iter_path(), and
3248 pf_map_iter_position() correspondingly. Returns FALSE if no further
3249 positions are available in this map.
3250
3251 NB: If pf_map_move_cost(pfm, ptile), pf_map_path(pfm, ptile), or
3252 pf_map_position(pfm, ptile) has been called before the call to
3253 pf_map_iterate(), the iteration will resume from 'ptile'.
3254 ****************************************************************************/
pf_map_iterate(struct pf_map * pfm)3255 bool pf_map_iterate(struct pf_map *pfm)
3256 {
3257 #ifdef PF_DEBUG
3258 fc_assert_ret_val(NULL != pfm, FALSE);
3259 #endif
3260
3261 if (NULL == pfm->tile) {
3262 /* The end of the iteration was already reached. Don't try to iterate
3263 * again. */
3264 return FALSE;
3265 }
3266
3267 if (!pfm->iterate(pfm)) {
3268 /* End of iteration. */
3269 pfm->tile = NULL;
3270 return FALSE;
3271 }
3272
3273 return TRUE;
3274 }
3275
3276 /****************************************************************************
3277 Return the current tile.
3278 ****************************************************************************/
pf_map_iter(struct pf_map * pfm)3279 struct tile *pf_map_iter(struct pf_map *pfm)
3280 {
3281 #ifdef PF_DEBUG
3282 fc_assert_ret_val(NULL != pfm, NULL);
3283 #endif
3284 return pfm->tile;
3285 }
3286
3287 /****************************************************************************
3288 Return the move cost at the current position. This is equivalent to
3289 pf_map_move_cost(pfm, pf_map_iter(pfm)).
3290 ****************************************************************************/
pf_map_iter_move_cost(struct pf_map * pfm)3291 int pf_map_iter_move_cost(struct pf_map *pfm)
3292 {
3293 #ifdef PF_DEBUG
3294 fc_assert_ret_val(NULL != pfm, PF_IMPOSSIBLE_MC);
3295 fc_assert_ret_val(NULL != pfm->tile, PF_IMPOSSIBLE_MC);
3296 #endif
3297 return pfm->get_move_cost(pfm, pfm->tile);
3298 }
3299
3300 /****************************************************************************
3301 Return the path to our current position.This is equivalent to
3302 pf_map_path(pfm, pf_map_iter(pfm)).
3303 ****************************************************************************/
pf_map_iter_path(struct pf_map * pfm)3304 struct pf_path *pf_map_iter_path(struct pf_map *pfm)
3305 {
3306 #ifdef PF_DEBUG
3307 fc_assert_ret_val(NULL != pfm, NULL);
3308 fc_assert_ret_val(NULL != pfm->tile, NULL);
3309 #endif
3310 return pfm->get_path(pfm, pfm->tile);
3311 }
3312
3313 /****************************************************************************
3314 Read all info about the current position into pos. This is equivalent to
3315 pf_map_position(pfm, pf_map_iter(pfm), &pos).
3316 ****************************************************************************/
pf_map_iter_position(struct pf_map * pfm,struct pf_position * pos)3317 void pf_map_iter_position(struct pf_map *pfm, struct pf_position *pos)
3318 {
3319 #ifdef PF_DEBUG
3320 fc_assert_ret(NULL != pfm);
3321 fc_assert_ret(NULL != pfm->tile);
3322 #endif
3323 if (!pfm->get_position(pfm, pfm->tile, pos)) {
3324 /* Always fails. */
3325 fc_assert(pfm->get_position(pfm, pfm->tile, pos));
3326 }
3327 }
3328
3329 /****************************************************************************
3330 Return the pf_parameter for given pf_map.
3331 ****************************************************************************/
pf_map_parameter(const struct pf_map * pfm)3332 const struct pf_parameter *pf_map_parameter(const struct pf_map *pfm)
3333 {
3334 #ifdef PF_DEBUG
3335 fc_assert_ret_val(NULL != pfm, NULL);
3336 #endif
3337 return &pfm->params;
3338 }
3339
3340
3341 /* ====================== pf_path public functions ======================= */
3342
3343 /****************************************************************************
3344 Fill the position for the start tile of a parameter.
3345 ****************************************************************************/
pf_position_fill_start_tile(struct pf_position * pos,const struct pf_parameter * param)3346 static void pf_position_fill_start_tile(struct pf_position *pos,
3347 const struct pf_parameter *param)
3348 {
3349 pos->tile = param->start_tile;
3350 pos->turn = 0;
3351 pos->moves_left = param->moves_left_initially;
3352 pos->fuel_left = param->fuel_left_initially;
3353 pos->total_MC = 0;
3354 pos->total_EC = 0;
3355 pos->dir_to_next_pos = direction8_invalid();
3356 pos->dir_to_here = direction8_invalid();
3357 }
3358
3359 /****************************************************************************
3360 Create a path to the start tile of a parameter.
3361 ****************************************************************************/
3362 static struct pf_path *
pf_path_new_to_start_tile(const struct pf_parameter * param)3363 pf_path_new_to_start_tile(const struct pf_parameter *param)
3364 {
3365 struct pf_path *path = fc_malloc(sizeof(*path));
3366 struct pf_position *pos = fc_malloc(sizeof(*pos));
3367
3368 path->length = 1;
3369 pf_position_fill_start_tile(pos, param);
3370 path->positions = pos;
3371 return path;
3372 }
3373
3374 /****************************************************************************
3375 After use, a path must be destroyed. Note this function accept NULL as
3376 argument.
3377 ****************************************************************************/
pf_path_destroy(struct pf_path * path)3378 void pf_path_destroy(struct pf_path *path)
3379 {
3380 if (NULL != path) {
3381 free(path->positions);
3382 free(path);
3383 }
3384 }
3385
3386 /****************************************************************************
3387 Concatenate two paths together. The additional segment 'src_path'
3388 should start where the initial segment 'dest_path' stops. The
3389 overlapping position is removed.
3390
3391 If 'dest_path' == NULL, we just copy the src_path and nothing else.
3392 ****************************************************************************/
pf_path_concat(struct pf_path * dest_path,const struct pf_path * src_path)3393 struct pf_path *pf_path_concat(struct pf_path *dest_path,
3394 const struct pf_path *src_path)
3395 {
3396 int dest_end;
3397
3398 fc_assert_ret_val(src_path != NULL, NULL);
3399
3400 if (dest_path == NULL) {
3401 /* Just copy path. */
3402 dest_path = fc_malloc(sizeof(*dest_path));
3403 dest_path->length = src_path->length;
3404 dest_path->positions = fc_malloc(sizeof(*dest_path->positions)
3405 * dest_path->length);
3406 memcpy(dest_path->positions, src_path->positions,
3407 sizeof(*dest_path->positions) * dest_path->length);
3408 return dest_path;
3409 }
3410
3411 dest_end = dest_path->length - 1;
3412 fc_assert(dest_path->positions[dest_end].tile
3413 == src_path->positions[0].tile);
3414 fc_assert(dest_path->positions[dest_end].moves_left
3415 == src_path->positions[0].moves_left);
3416 fc_assert(dest_path->positions[dest_end].fuel_left
3417 == src_path->positions[0].fuel_left);
3418
3419 if (src_path->length == 1) {
3420 return dest_path;
3421 }
3422
3423 dest_path->length = dest_end + src_path->length;
3424 dest_path->positions = fc_realloc(dest_path->positions,
3425 sizeof(*dest_path->positions)
3426 * dest_path->length);
3427 /* Be careful to include the first position of src_path, it contains
3428 * the direction (it is undefined in the last position of dest_path) */
3429 memcpy(dest_path->positions + dest_end, src_path->positions,
3430 sizeof(*dest_path->positions) * src_path->length);
3431
3432 return dest_path;
3433 }
3434
3435 /****************************************************************************
3436 Remove the part of a path leading up to a given tile.
3437 If given tile is on the path more than once then the first occurrence
3438 will be the one used.
3439 If tile is not on the path at all, returns FALSE and path is not changed
3440 at all.
3441 ****************************************************************************/
pf_path_advance(struct pf_path * path,struct tile * ptile)3442 bool pf_path_advance(struct pf_path *path, struct tile *ptile)
3443 {
3444 int i;
3445 struct pf_position *new_positions;
3446
3447 for (i = 0; path->positions[i].tile != ptile; i++) {
3448 if (i >= path->length) {
3449 return FALSE;
3450 }
3451 }
3452 fc_assert_ret_val(i < path->length, FALSE);
3453 path->length -= i;
3454 new_positions = fc_malloc(sizeof(*path->positions) * path->length);
3455 memcpy(new_positions, path->positions + i,
3456 path->length * sizeof(*path->positions));
3457 free(path->positions);
3458 path->positions = new_positions;
3459
3460 return TRUE;
3461 }
3462
3463 /****************************************************************************
3464 Get the last position of the path.
3465 ****************************************************************************/
pf_path_last_position(const struct pf_path * path)3466 const struct pf_position *pf_path_last_position(const struct pf_path *path)
3467 {
3468 return path->positions + (path->length - 1);
3469 }
3470
3471 /****************************************************************************
3472 Debug a path. This function shouldn't be called directly, see
3473 pf_path_print() defined in "path_finding.h".
3474 ****************************************************************************/
pf_path_print_real(const struct pf_path * path,enum log_level level,const char * file,const char * function,int line)3475 void pf_path_print_real(const struct pf_path *path, enum log_level level,
3476 const char *file, const char *function, int line)
3477 {
3478 struct pf_position *pos;
3479 int i;
3480
3481 if (path) {
3482 do_log(file, function, line, TRUE, level,
3483 "PF: path (at %p) consists of %d positions:",
3484 (void *) path, path->length);
3485 } else {
3486 do_log(file, function, line, TRUE, level, "PF: path is NULL");
3487 return;
3488 }
3489
3490 for (i = 0, pos = path->positions; i < path->length; i++, pos++) {
3491 do_log(file, function, line, FALSE, level,
3492 "PF: %2d/%2d: (%2d,%2d) dir=%-2s cost=%2d (%2d, %d) EC=%d",
3493 i + 1, path->length, TILE_XY(pos->tile),
3494 dir_get_name(pos->dir_to_next_pos), pos->total_MC,
3495 pos->turn, pos->moves_left, pos->total_EC);
3496 }
3497 }
3498
3499
3500 /* ===================== pf_reverse_map functions ======================== */
3501
3502 /* The path-finding reverse maps are used check the move costs that the
3503 * units needs to reach the start tile. It stores a pf_map for every unit
3504 * type. */
3505
3506 static genhash_val_t pf_pos_hash_val(const struct pf_parameter *parameter);
3507 static bool pf_pos_hash_cmp(const struct pf_parameter *parameter1,
3508 const struct pf_parameter *parameter2);
3509 static void pf_reverse_map_destroy_pos(struct pf_position *pos);
3510 static void pf_reverse_map_destroy_param(struct pf_parameter *param);
3511
3512 #define SPECHASH_TAG pf_pos
3513 #define SPECHASH_IKEY_TYPE struct pf_parameter *
3514 #define SPECHASH_IDATA_TYPE struct pf_position *
3515 #define SPECHASH_IKEY_VAL pf_pos_hash_val
3516 #define SPECHASH_IKEY_COMP pf_pos_hash_cmp
3517 #define SPECHASH_IKEY_FREE pf_reverse_map_destroy_param
3518 #define SPECHASH_IDATA_FREE pf_reverse_map_destroy_pos
3519 #include "spechash.h"
3520
3521 /* The reverse map structure. */
3522 struct pf_reverse_map {
3523 struct tile *target_tile; /* Where we want to go. */
3524 int max_turns; /* The maximum of turns. */
3525 struct pf_parameter template; /* Keep a parameter ready for usage. */
3526 struct pf_pos_hash *hash; /* A hash where pf_position are stored. */
3527 };
3528
3529 /* Here goes all unit type flags which affect the move rules handled by
3530 * the reverse map. */
3531 static const enum unit_type_flag_id signifiant_flags[] = {
3532 UTYF_IGTER, UTYF_CIVILIAN, UTYF_TRIREME
3533 };
3534 static const size_t signifiant_flags_num = ARRAY_SIZE(signifiant_flags);
3535
3536 /****************************************************************************
3537 Hash function for pf_parameter key.
3538 ****************************************************************************/
pf_pos_hash_val(const struct pf_parameter * parameter)3539 static genhash_val_t pf_pos_hash_val(const struct pf_parameter *parameter)
3540 {
3541 genhash_val_t result = 0;
3542 size_t b, i;
3543
3544 for (i = 0, b = sizeof(result) * 8 - 1; i < signifiant_flags_num;
3545 i++, b--) {
3546 if (utype_has_flag(parameter->utype, signifiant_flags[i])) {
3547 result |= (1u << b);
3548 }
3549 }
3550
3551 result += (uclass_number(utype_class(parameter->utype))
3552 + (parameter->move_rate << 5)
3553 + (tile_index(parameter->start_tile) << 11));
3554 if (!parameter->omniscience) {
3555 result += parameter->utype->unknown_move_cost << 23;
3556 }
3557
3558 return result;
3559 }
3560
3561 /****************************************************************************
3562 Comparison function for pf_parameter hash key.
3563 ****************************************************************************/
pf_pos_hash_cmp(const struct pf_parameter * parameter1,const struct pf_parameter * parameter2)3564 static bool pf_pos_hash_cmp(const struct pf_parameter *parameter1,
3565 const struct pf_parameter *parameter2)
3566 {
3567 size_t i;
3568
3569 if (parameter1->start_tile != parameter2->start_tile
3570 || parameter1->move_rate != parameter2->move_rate) {
3571 return FALSE;
3572 }
3573
3574 if (parameter1->utype == parameter2->utype) {
3575 /* Short test. */
3576 return TRUE;
3577 }
3578
3579 if (utype_class(parameter1->utype) != utype_class(parameter2->utype)) {
3580 return FALSE;
3581 }
3582
3583 if (!parameter1->omniscience) {
3584 #ifdef PF_DEBUG
3585 fc_assert(parameter2->omniscience == FALSE);
3586 #endif
3587 if (parameter1->utype->unknown_move_cost
3588 != parameter2->utype->unknown_move_cost) {
3589 return FALSE;
3590 }
3591 }
3592
3593 for (i = 0; i < signifiant_flags_num; i++) {
3594 if (utype_has_flag(parameter1->utype, signifiant_flags[i])
3595 != utype_has_flag(parameter2->utype, signifiant_flags[i])) {
3596 return FALSE;
3597 }
3598 }
3599
3600 return TRUE;
3601 }
3602
3603 /****************************************************************************
3604 Destroy the position if not NULL.
3605 ****************************************************************************/
pf_reverse_map_destroy_pos(struct pf_position * pos)3606 static void pf_reverse_map_destroy_pos(struct pf_position *pos)
3607 {
3608 free(pos);
3609 }
3610
3611 /****************************************************************************
3612 Destroy the parameter.
3613 ****************************************************************************/
pf_reverse_map_destroy_param(struct pf_parameter * param)3614 static void pf_reverse_map_destroy_param(struct pf_parameter *param)
3615 {
3616 free(param);
3617 }
3618
3619 /****************************************************************************
3620 'pf_reverse_map' constructor. If 'max_turns' is positive, then it won't
3621 try to iterate the maps beyond this number of turns.
3622 ****************************************************************************/
pf_reverse_map_new(const struct player * pplayer,struct tile * target_tile,int max_turns,bool omniscient)3623 struct pf_reverse_map *pf_reverse_map_new(const struct player *pplayer,
3624 struct tile *target_tile,
3625 int max_turns, bool omniscient)
3626 {
3627 struct pf_reverse_map *pfrm = fc_malloc(sizeof(struct pf_reverse_map));
3628 struct pf_parameter *param = &pfrm->template;
3629
3630 pfrm->target_tile = target_tile;
3631 pfrm->max_turns = max_turns;
3632
3633 /* Initialize the parameter. */
3634 pft_fill_reverse_parameter(param, target_tile);
3635 param->owner = pplayer;
3636 param->omniscience = omniscient;
3637
3638 /* Initialize the map hash. */
3639 pfrm->hash = pf_pos_hash_new();
3640
3641 return pfrm;
3642 }
3643
3644 /****************************************************************************
3645 'pf_reverse_map' constructor for city. If 'max_turns' is positive, then
3646 it won't try to iterate the maps beyond this number of turns.
3647 ****************************************************************************/
pf_reverse_map_new_for_city(const struct city * pcity,const struct player * attacker,int max_turns,bool omniscient)3648 struct pf_reverse_map *pf_reverse_map_new_for_city(const struct city *pcity,
3649 const struct player *attacker,
3650 int max_turns, bool omniscient)
3651 {
3652 return pf_reverse_map_new(attacker, city_tile(pcity), max_turns, omniscient);
3653 }
3654
3655 /****************************************************************************
3656 'pf_reverse_map' destructor.
3657 ****************************************************************************/
pf_reverse_map_destroy(struct pf_reverse_map * pfrm)3658 void pf_reverse_map_destroy(struct pf_reverse_map *pfrm)
3659 {
3660 fc_assert_ret(NULL != pfrm);
3661
3662 pf_pos_hash_destroy(pfrm->hash);
3663 free(pfrm);
3664 }
3665
3666 /****************************************************************************
3667 Returns the map for the unit type. Creates it if needed. Returns NULL if
3668 'target_tile' is unreachable.
3669 ****************************************************************************/
3670 static const struct pf_position *
pf_reverse_map_pos(struct pf_reverse_map * pfrm,const struct pf_parameter * param)3671 pf_reverse_map_pos(struct pf_reverse_map *pfrm,
3672 const struct pf_parameter *param)
3673 {
3674 struct pf_position *pos;
3675 struct pf_map *pfm;
3676 struct pf_parameter *copy;
3677 struct tile *target_tile;
3678 const struct pf_normal_node *lattice;
3679 int max_cost;
3680
3681 /* Check if we already processed something similar. */
3682 if (pf_pos_hash_lookup(pfrm->hash, param, &pos)) {
3683 return pos;
3684 }
3685
3686 /* We didn't. Build map and iterate. */
3687 pfm = pf_normal_map_new(param);
3688 lattice = PF_NORMAL_MAP(pfm)->lattice;
3689 target_tile = pfrm->target_tile;
3690 if (pfrm->max_turns >= 0) {
3691 max_cost = param->move_rate * (pfrm->max_turns + 1);
3692 do {
3693 if (lattice[tile_index(pfm->tile)].cost >= max_cost) {
3694 break;
3695 } else if (pfm->tile == target_tile) {
3696 /* Found our position. Insert in hash, destroy map, and return. */
3697 pos = fc_malloc(sizeof(*pos));
3698 pf_normal_map_fill_position(PF_NORMAL_MAP(pfm), target_tile, pos);
3699 copy = fc_malloc(sizeof(*copy));
3700 *copy = *param;
3701 pf_pos_hash_insert(pfrm->hash, copy, pos);
3702 pf_map_destroy(pfm);
3703 return pos;
3704 }
3705 } while (pfm->iterate(pfm));
3706 } else {
3707 /* No limit for iteration. */
3708 do {
3709 if (pfm->tile == target_tile) {
3710 /* Found our position. Insert in hash, destroy map, and return. */
3711 pos = fc_malloc(sizeof(*pos));
3712 pf_normal_map_fill_position(PF_NORMAL_MAP(pfm), target_tile, pos);
3713 copy = fc_malloc(sizeof(*copy));
3714 *copy = *param;
3715 pf_pos_hash_insert(pfrm->hash, copy, pos);
3716 pf_map_destroy(pfm);
3717 return pos;
3718 }
3719 } while (pfm->iterate(pfm));
3720 }
3721 pf_map_destroy(pfm);
3722
3723 /* Position not found. Let's insert NULL as position to avoid to iterate
3724 * the map again. */
3725 copy = fc_malloc(sizeof(*copy));
3726 *copy = *param;
3727 pf_pos_hash_insert(pfrm->hash, copy, NULL);
3728 return NULL;
3729 }
3730
3731 /****************************************************************************
3732 Returns the position for the unit. Creates it if needed. Returns NULL if
3733 'target_tile' is unreachable.
3734 ****************************************************************************/
3735 static inline const struct pf_position *
pf_reverse_map_unit_pos(struct pf_reverse_map * pfrm,const struct unit * punit)3736 pf_reverse_map_unit_pos(struct pf_reverse_map *pfrm,
3737 const struct unit *punit)
3738 {
3739 struct pf_parameter *param = &pfrm->template;
3740
3741 /* Fill parameter. */
3742 param->start_tile = unit_tile(punit);
3743 param->move_rate = unit_move_rate(punit);
3744 /* Do not consider punit->moves_left, because this value is usually
3745 * not restored when calling this function. Let's assume the unit will
3746 * have its whole move rate. */
3747 param->moves_left_initially = param->move_rate;
3748 param->utype = unit_type_get(punit);
3749 return pf_reverse_map_pos(pfrm, param);
3750 }
3751
3752 /****************************************************************************
3753 Returns the position for the unit type. Creates it if needed. Returns NULL
3754 if 'target_tile' is unreachable.
3755 ****************************************************************************/
3756 static inline const struct pf_position *
pf_reverse_map_utype_pos(struct pf_reverse_map * pfrm,const struct unit_type * punittype,struct tile * ptile)3757 pf_reverse_map_utype_pos(struct pf_reverse_map *pfrm,
3758 const struct unit_type *punittype,
3759 struct tile *ptile)
3760 {
3761 struct pf_parameter *param = &pfrm->template;
3762 const struct player *pplayer = param->owner;
3763 int veteran_level = get_unittype_bonus(pplayer, ptile, punittype,
3764 EFT_VETERAN_BUILD);
3765
3766 if (veteran_level >= utype_veteran_levels(punittype)) {
3767 veteran_level = utype_veteran_levels(punittype) - 1;
3768 }
3769
3770 /* Fill parameter. */
3771 param->start_tile = ptile;
3772 param->move_rate = utype_move_rate(punittype, ptile, pplayer,
3773 veteran_level, punittype->hp);
3774 param->moves_left_initially = param->move_rate;
3775 param->utype = punittype;
3776 return pf_reverse_map_pos(pfrm, param);
3777 }
3778
3779 /****************************************************************************
3780 Get the move costs that a unit type needs to reach the start tile. Returns
3781 PF_IMPOSSIBLE_MC if the tile is unreachable.
3782 ****************************************************************************/
pf_reverse_map_utype_move_cost(struct pf_reverse_map * pfrm,const struct unit_type * punittype,struct tile * ptile)3783 int pf_reverse_map_utype_move_cost(struct pf_reverse_map *pfrm,
3784 const struct unit_type *punittype,
3785 struct tile *ptile)
3786 {
3787 const struct pf_position *pos = pf_reverse_map_utype_pos(pfrm, punittype,
3788 ptile);
3789
3790 return (pos != NULL ? pos->total_MC : PF_IMPOSSIBLE_MC);
3791 }
3792
3793 /****************************************************************************
3794 Get the move costs that a unit needs to reach the start tile. Returns
3795 PF_IMPOSSIBLE_MC if the tile is unreachable.
3796 ****************************************************************************/
pf_reverse_map_unit_move_cost(struct pf_reverse_map * pfrm,const struct unit * punit)3797 int pf_reverse_map_unit_move_cost(struct pf_reverse_map *pfrm,
3798 const struct unit *punit)
3799 {
3800 const struct pf_position *pos = pf_reverse_map_unit_pos(pfrm, punit);
3801
3802 return (pos != NULL ? pos->total_MC : PF_IMPOSSIBLE_MC);
3803 }
3804
3805 /****************************************************************************
3806 Fill the position. Return TRUE if the tile is reachable.
3807 ****************************************************************************/
pf_reverse_map_utype_position(struct pf_reverse_map * pfrm,const struct unit_type * punittype,struct tile * ptile,struct pf_position * pos)3808 bool pf_reverse_map_utype_position(struct pf_reverse_map *pfrm,
3809 const struct unit_type *punittype,
3810 struct tile *ptile,
3811 struct pf_position *pos)
3812 {
3813 const struct pf_position *mypos = pf_reverse_map_utype_pos(pfrm, punittype,
3814 ptile);
3815
3816 if (mypos != NULL) {
3817 *pos = *mypos;
3818 return TRUE;
3819 } else {
3820 return FALSE;
3821 }
3822 }
3823
3824 /****************************************************************************
3825 Fill the position. Return TRUE if the tile is reachable.
3826 ****************************************************************************/
pf_reverse_map_unit_position(struct pf_reverse_map * pfrm,const struct unit * punit,struct pf_position * pos)3827 bool pf_reverse_map_unit_position(struct pf_reverse_map *pfrm,
3828 const struct unit *punit,
3829 struct pf_position *pos)
3830 {
3831 const struct pf_position *mypos = pf_reverse_map_unit_pos(pfrm, punit);
3832
3833 if (mypos != NULL) {
3834 *pos = *mypos;
3835 return TRUE;
3836 } else {
3837 return FALSE;
3838 }
3839 }
3840