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