Freeciv21
Develop your civilization from humble roots to a global empire
path_finding.cpp
Go to the documentation of this file.
1 /*
2  Copyright (c) 1996-2020 Freeciv21 and Freeciv contributors. This file is
3  __ __ part of Freeciv21. Freeciv21 is free software: you can
4 / \\..// \ redistribute it and/or modify it under the terms of the GNU
5  ( oo ) General Public License as published by the Free Software
6  \__/ Foundation, either version 3 of the License, or (at your
7  option) any later version. You should have received
8  a copy of the GNU General Public License along with Freeciv21. If not,
9  see https://www.gnu.org/licenses/.
10  */
11 // utility
12 #include "bitvector.h"
13 #include "genhash.h"
14 #include "log.h"
15 
16 // common
17 #include "game.h"
18 #include "map.h"
19 #include "movement.h"
20 
21 /* common/aicore */
22 #include "pf_tools.h"
23 
24 // Qt
25 #include <QDebug>
26 #include <QString>
27 
28 #include "path_finding.h"
29 
30 // For explanations on how to use this module, see "path_finding.h".
31 
32 #define SPECPQ_TAG map_index
33 #define SPECPQ_DATA_TYPE int
34 #define SPECPQ_PRIORITY_TYPE int
35 #include "specpq.h"
36 #define INITIAL_QUEUE_SIZE 100
37 
38 #ifdef FREECIV_DEBUG
39 // Extra checks for debugging.
40 #define PF_DEBUG
41 #endif
42 
43 // ======================== Internal structures ==========================
44 
45 #ifdef PF_DEBUG
46 // The mode we use the pf_map. Used for cast converion checks.
47 enum pf_mode {
48  PF_NORMAL = 1, // Usual goto
49  PF_DANGER, // Goto with dangerous positions
50  PF_FUEL // Goto for fueled units
51 };
52 #endif // PF_DEBUG
53 
55  NS_UNINIT = 0, /* memory is calloced, hence zero means
56  * uninitialised. */
57  NS_INIT, /* node initialized, but we didn't search a route
58  * yet. */
59  NS_NEW, // the optimal route isn't found yet.
60  NS_WAITING, /* the optimal route is found, considering waiting.
61  * Only used for pf_danger_map and pf_fuel_map, it
62  * means we are waiting on a safe place for full
63  * moves before crossing a dangerous area. */
64  NS_PROCESSED // the optimal route is found.
65 };
66 
68  ZOC_MINE = 0, // My ZoC.
69  ZOC_ALLIED, // Allied ZoC.
70  ZOC_NO // No ZoC.
71 };
72 
73 // Abstract base class for pf_normal_map, pf_danger_map, and pf_fuel_map.
74 struct pf_map {
75 #ifdef PF_DEBUG
76  enum pf_mode mode; // The mode of the map, for conversion checking.
77 #endif // PF_DEBUG
78 
79  // "Virtual" function table.
80  void (*destroy)(struct pf_map *pfm); // Destructor.
81  int (*get_move_cost)(struct pf_map *pfm, struct tile *ptile);
82  PFPath (*get_path)(struct pf_map *pfm, struct tile *ptile);
83  bool (*get_position)(struct pf_map *pfm, struct tile *ptile,
84  struct pf_position *pos);
85  bool (*iterate)(struct pf_map *pfm);
86 
87  // Private data.
88  struct tile *tile; // The current position (aka iterator).
89  struct pf_parameter params; // Initial parameters.
90 };
91 
97 pf_map *PF_MAP(void *x) { return reinterpret_cast<pf_map *>(x); }
98 
104 const pf_map *PF_MAP(const void *x)
105 {
106  return reinterpret_cast<const pf_map *>(x);
107 }
108 
109 // ========================== Common functions ===========================
110 
119 static inline int pf_moves_left_initially(const struct pf_parameter *param)
120 {
121  return (param->moves_left_initially
122  + (param->fuel_left_initially - 1) * param->move_rate);
123 }
124 
133 static inline int pf_move_rate(const struct pf_parameter *param)
134 {
135  return param->move_rate * param->fuel;
136 }
137 
143 static inline int pf_turns(const struct pf_parameter *param, int cost)
144 {
145  /* Negative cost can happen when a unit initially has more MP than its
146  * move-rate (due to wonders transfer etc). Although this may be a bug,
147  * we'd better be ready.
148  *
149  * Note that cost == 0 corresponds to the current turn with full MP. */
150  if (param->fuel_left_initially < param->fuel) {
151  cost -= (param->fuel - param->fuel_left_initially) * param->move_rate;
152  }
153  if (cost <= 0) {
154  return 0;
155  } else if (param->move_rate <= 0) {
156  return FC_INFINITY; // This unit cannot move by itself.
157  } else {
158  return cost / param->move_rate;
159  }
160 }
161 
165 static inline int pf_moves_left(const struct pf_parameter *param, int cost)
166 {
167  int move_rate = pf_move_rate(param);
168 
169  // Cost may be negative; see pf_turns().
170  if (cost <= 0) {
171  return move_rate - cost;
172  } else if (move_rate <= 0) {
173  return 0; // This unit never have moves left.
174  } else {
175  return move_rate - (cost % move_rate);
176  }
177 }
178 
182 static inline int pf_total_CC(const struct pf_parameter *param, int cost,
183  int extra)
184 {
185  return PF_TURN_FACTOR * cost + extra * pf_move_rate(param);
186 }
187 
194 static inline void pf_finalize_position(const struct pf_parameter *param,
195  struct pf_position *pos)
196 {
197  int move_rate = param->move_rate;
198 
199  if (0 < move_rate) {
200  pos->moves_left %= move_rate;
201  }
202 }
203 
204 static void pf_position_fill_start_tile(struct pf_position *pos,
205  const struct pf_parameter *param);
206 
207 // ================ Specific pf_normal_* mode structures =================
208 
209 /* Normal path-finding maps are used for most of units with standard rules.
210  * See what units make pf_map_new() to pick danger or fuel maps instead. */
211 // Node definition. Note we try to have the smallest data as possible.
213  signed short cost; /* total_MC. 'cost' may be negative, see comment in
214  * pf_turns(). */
215  unsigned extra_cost; // total_EC. Can be huge, (higher than 'cost').
216  unsigned dir_to_here : 4; /* Direction from which we came. It's
217  * an 'enum direction8' including
218  * possibility of direction8_invalid (so we need
219  * 4 bits) */
220  unsigned status : 3; // 'enum pf_node_status' really.
221 
222  // Cached values
223  unsigned move_scope : 3; // 'enum pf_move_scope really.
224  unsigned action : 2; // 'enum pf_action really.
225  unsigned node_known_type : 2; // 'enum known_type' really.
226  unsigned behavior : 2; // 'enum tile_behavior' really.
227  unsigned zoc_number : 2; // 'enum pf_zoc_type' really.
228  unsigned short extra_tile; // EC
229 };
230 
231 // Derived structure of struct pf_map.
233  struct pf_map base_map; // Base structure, must be the first!
234 
235  struct map_index_pq *queue; /* Queue of nodes we have reached but not
236  * processed yet (NS_NEW), sorted by their
237  * total_CC. */
238  struct pf_normal_node *lattice; // Lattice of nodes.
239 };
240 
241 // Up-cast macro.
242 #ifdef PF_DEBUG
243 static inline pf_normal_map *pf_normal_map_check(pf_map *pfm)
244 {
245  fc_assert_ret_val_msg(nullptr != pfm && PF_NORMAL == pfm->mode, nullptr,
246  "Wrong pf_map to pf_normal_map conversion.");
247  return reinterpret_cast<struct pf_normal_map *>(pfm);
248 }
249 #define PF_NORMAL_MAP(pfm) pf_normal_map_check(pfm)
250 #else
251 #define PF_NORMAL_MAP(pfm) ((struct pf_normal_map *) (pfm))
252 #endif // PF_DEBUG
253 
254 // ================ Specific pf_normal_* mode functions =================
255 
261 static inline bool pf_normal_node_init(struct pf_normal_map *pfnm,
262  struct pf_normal_node *node,
263  struct tile *ptile,
264  enum pf_move_scope previous_scope)
265 {
266  const struct pf_parameter *params = pf_map_parameter(PF_MAP(pfnm));
267  enum known_type node_known_type;
268  enum pf_action action;
269 
270 #ifdef PF_DEBUG
271  fc_assert(NS_UNINIT == node->status);
272  // Else, not a critical problem, but waste of time.
273 #endif
274 
275  node->status = NS_INIT;
276 
277  // Establish the "known" status of node.
278  if (params->omniscience) {
279  node_known_type = TILE_KNOWN_SEEN;
280  } else {
281  node_known_type = tile_get_known(ptile, params->owner);
282  }
283  node->node_known_type = node_known_type;
284 
285  // Establish the tile behavior.
286  if (nullptr != params->get_TB) {
287  node->behavior = params->get_TB(ptile, node_known_type, params);
288  if (TB_IGNORE == node->behavior && params->start_tile != ptile) {
289  return false;
290  }
291  }
292 
293  if (TILE_UNKNOWN != node_known_type) {
294  bool can_disembark;
295 
296  // Test if we can invade tile.
297  if (!utype_has_flag(params->utype, UTYF_CIVILIAN)
298  && !player_can_invade_tile(params->owner, ptile)) {
299  // Maybe overwrite node behavior.
300  if (params->start_tile != ptile) {
301  node->behavior = TB_IGNORE;
302  return false;
303  } else if (TB_NORMAL == node->behavior) {
304  node->behavior = TB_IGNORE;
305  }
306  }
307 
308  // Test the possibility to perform an action.
309  if (nullptr != params->get_action) {
310  action = params->get_action(ptile, node_known_type, params);
311  if (PF_ACTION_IMPOSSIBLE == action) {
312  // Maybe overwrite node behavior.
313  if (params->start_tile != ptile) {
314  node->behavior = TB_IGNORE;
315  return false;
316  } else if (TB_NORMAL == node->behavior) {
317  node->behavior = TB_IGNORE;
318  }
320  } else if (PF_ACTION_NONE != action
321  && TB_DONT_LEAVE != node->behavior) {
322  // Overwrite node behavior.
323  node->behavior = TB_DONT_LEAVE;
324  }
325  node->action = action;
326  }
327 
328  /* Test the possibility to move from/to 'ptile'. */
329  node->move_scope = params->get_move_scope(ptile, &can_disembark,
330  previous_scope, params);
331  if (PF_MS_NONE == node->move_scope && PF_ACTION_NONE == node->action
332  && params->ignore_none_scopes) {
333  // Maybe overwrite node behavior.
334  if (params->start_tile != ptile) {
335  node->behavior = TB_IGNORE;
336  return false;
337  } else if (TB_NORMAL == node->behavior) {
338  node->behavior = TB_IGNORE;
339  }
340  } else if (PF_MS_TRANSPORT == node->move_scope && !can_disembark
341  && (params->start_tile != ptile
342  || nullptr == params->transported_by_initially)) {
343  // Overwrite node behavior.
344  node->behavior = TB_DONT_LEAVE;
345  }
346 
347  /* ZOC_MINE means can move unrestricted from/into it, ZOC_ALLIED means
348  * can move unrestricted into it, but not necessarily from it. */
349  if (nullptr != params->get_zoc && nullptr == tile_city(ptile)
350  && !terrain_has_flag(tile_terrain(ptile), TER_NO_ZOC)
351  && !params->get_zoc(params->owner, ptile, params->map)) {
352  node->zoc_number =
353  (0 < unit_list_size(ptile->units) ? ZOC_ALLIED : ZOC_NO);
354  }
355  } else {
356  node->move_scope = PF_MS_NATIVE;
357  }
358 
359  // Evaluate the extra cost of the destination
360  if (nullptr != params->get_EC) {
361  node->extra_tile = params->get_EC(ptile, node_known_type, params);
362  }
363 
364  return true;
365 }
366 
371 static void pf_normal_map_fill_position(const struct pf_normal_map *pfnm,
372  struct tile *ptile,
373  struct pf_position *pos)
374 {
375  int tindex = tile_index(ptile);
376  struct pf_normal_node *node = pfnm->lattice + tindex;
377  const struct pf_parameter *params = pf_map_parameter(PF_MAP(pfnm));
378 
379 #ifdef PF_DEBUG
381  "Unreached destination (%d, %d).", TILE_XY(ptile));
382 #endif // PF_DEBUG
383 
384  pos->tile = ptile;
385  pos->total_EC = node->extra_cost;
386  pos->total_MC =
387  (node->cost - pf_move_rate(params) + pf_moves_left_initially(params));
388  pos->turn = pf_turns(params, node->cost);
389  pos->moves_left = pf_moves_left(params, node->cost);
390 #ifdef PF_DEBUG
391  fc_assert(params->fuel == 1);
392  fc_assert(params->fuel_left_initially == 1);
393 #endif // PF_DEBUG
394  pos->fuel_left = 1;
395  pos->dir_to_here = direction8(node->dir_to_here);
396  pos->dir_to_next_pos = direction8_invalid(); // This field does not apply.
397 
398  if (node->cost > 0) {
399  pf_finalize_position(params, pos);
400  }
401 }
402 
408  struct tile *dest_tile)
409 {
410  struct pf_normal_node *node = pfnm->lattice + tile_index(dest_tile);
411  const struct pf_parameter *params = pf_map_parameter(PF_MAP(pfnm));
412  enum direction8 dir_next = direction8_invalid();
413  struct tile *ptile;
414  int i;
415 
416 #ifdef PF_DEBUG
418  "Unreached destination (%d, %d).",
419  TILE_XY(dest_tile));
420 #endif // PF_DEBUG
421 
422  ptile = dest_tile;
423  /* 1: Count the number of steps to get here.
424  * To do it, backtrack until we hit the starting point */
425  for (i = 0;; i++) {
426  if (ptile == params->start_tile) {
427  // Ah-ha, reached the starting point!
428  break;
429  }
430 
431  ptile = mapstep(params->map, ptile, DIR_REVERSE(node->dir_to_here));
432  node = pfnm->lattice + tile_index(ptile);
433  }
434 
435  // 2: Allocate the memory
436  PFPath path(i + 1);
437 
438  // 3: Backtrack again and fill the positions this time
439  ptile = dest_tile;
440  node = pfnm->lattice + tile_index(ptile);
441 
442  for (; i >= 0; i--) {
443  pf_normal_map_fill_position(pfnm, ptile, &path[i]);
444  // fill_position doesn't set direction
445  path[i].dir_to_next_pos = dir_next;
446 
447  dir_next = direction8(node->dir_to_here);
448 
449  if (i > 0) {
450  // Step further back, if we haven't finished yet
451  ptile = mapstep(params->map, ptile, DIR_REVERSE(dir_next));
452  node = pfnm->lattice + tile_index(ptile);
453  }
454  }
455 
456  return path;
457 }
458 
462 static int pf_normal_map_adjust_cost(int cost, int moves_left)
463 {
465 
466  return MIN(cost, moves_left);
467 }
468 
486 static bool pf_jumbo_map_iterate(struct pf_map *pfm)
487 {
488  struct pf_normal_map *pfnm = PF_NORMAL_MAP(pfm);
489  struct tile *tile = pfm->tile;
490  int tindex = tile_index(tile);
491  struct pf_normal_node *node = pfnm->lattice + tindex;
492  const struct pf_parameter *params = pf_map_parameter(pfm);
493 
494  // Processing Stage
495 
496  /* The previous position is defined by 'tile' (tile pointer), 'node'
497  * (the data of the tile for the pf_map), and index (the index of the
498  * position in the Freeciv map). */
499 
500  adjc_dir_iterate(params->map, tile, tile1, dir)
501  {
502  /* Calculate the cost of every adjacent position and set them in the
503  * priority queue for next call to pf_jumbo_map_iterate(). */
504  int tindex1 = tile_index(tile1);
505  struct pf_normal_node *node1 = pfnm->lattice + tindex1;
506  int priority, cost1, extra_cost1;
507 
508  /* As for the previous position, 'tile1', 'node1' and 'tindex1' are
509  * defining the adjacent position. */
510 
511  if (node1->status == NS_PROCESSED) {
512  // This gives 15% speedup
513  continue;
514  }
515 
516  if (NS_UNINIT == node1->status) {
517  /* Set cost as impossible for initializing, params->get_costs(), will
518  * overwrite with the right value. */
519  cost1 = PF_IMPOSSIBLE_MC;
520  extra_cost1 = 0;
521  } else {
522  cost1 = node1->cost;
523  extra_cost1 = node1->extra_cost;
524  }
525 
526  /* User-supplied callback 'get_costs' takes care of everything (ZOC,
527  * known, costs etc). See explanations in "path_finding.h". */
528  priority =
529  params->get_costs(tile, dir, tile1, node->cost, node->extra_cost,
530  &cost1, &extra_cost1, params);
531  if (priority >= 0) {
532  /* We found a better route to 'tile1', record it (the costs are
533  * recorded already). Node status step A. to B. */
534  if (NS_NEW == node1->status) {
535  map_index_pq_replace(pfnm->queue, tindex1, -priority);
536  } else {
537  map_index_pq_insert(pfnm->queue, tindex1, -priority);
538  }
539  node1->cost = cost1;
540  node1->extra_cost = extra_cost1;
541  node1->status = NS_NEW;
542  node1->dir_to_here = dir;
543  }
544  }
546 
547  // Get the next node (the index with the highest priority).
548  if (!map_index_pq_remove(pfnm->queue, &tindex)) {
549  // No more indexes in the priority queue, iteration end.
550  return false;
551  }
552 
553 #ifdef PF_DEBUG
554  fc_assert(NS_NEW == pfnm->lattice[tindex].status);
555 #endif
556 
557  // Change the pf_map iterator. Node status step B. to C.
558  pfm->tile = index_to_tile(params->map, tindex);
559  pfnm->lattice[tindex].status = NS_PROCESSED;
560 
561  return true;
562 }
563 
580 static bool pf_normal_map_iterate(struct pf_map *pfm)
581 {
582  struct pf_normal_map *pfnm = PF_NORMAL_MAP(pfm);
583  struct tile *tile = pfm->tile;
584  int tindex = tile_index(tile);
585  struct pf_normal_node *node = pfnm->lattice + tindex;
586  const struct pf_parameter *params = pf_map_parameter(pfm);
587  int cost_of_path;
588  pf_move_scope scope = pf_move_scope(node->move_scope);
589 
590  // There is no exit from DONT_LEAVE tiles!
591  if (node->behavior != TB_DONT_LEAVE && scope != PF_MS_NONE
592  && (params->move_rate > 0 || node->cost < 0)) {
593  // Processing Stage
594 
595  /* The previous position is defined by 'tile' (tile pointer), 'node'
596  * (the data of the tile for the pf_map), and index (the index of the
597  * position in the Freeciv map). */
598 
599  adjc_dir_iterate(params->map, tile, tile1, dir)
600  {
601  /* Calculate the cost of every adjacent position and set them in the
602  * priority queue for next call to pf_normal_map_iterate(). */
603  int tindex1 = tile_index(tile1);
604  struct pf_normal_node *node1 = pfnm->lattice + tindex1;
605  int cost;
606  int extra = 0;
607 
608  /* As for the previous position, 'tile1', 'node1' and 'tindex1' are
609  * defining the adjacent position. */
610 
611  if (node1->status == NS_PROCESSED) {
612  // This gives 15% speedup. Node status already at step D.
613  continue;
614  }
615 
616  // Initialise target tile if necessary.
617  if (node1->status == NS_UNINIT) {
618  /* Only initialize once. See comment for pf_normal_node_init().
619  * Node status step A. to B. */
620  if (!pf_normal_node_init(pfnm, node1, tile1, scope)) {
621  continue;
622  }
623  } else if (TB_IGNORE == node1->behavior) {
624  // We cannot enter this tile at all!
625  continue;
626  }
627 
628  // Is the move ZOC-ok?
629  if (node->zoc_number != ZOC_MINE && node1->zoc_number == ZOC_NO) {
630  continue;
631  }
632 
633  // Evaluate the cost of the move.
634  if (PF_ACTION_NONE != node1->action) {
635  if (nullptr != params->is_action_possible
636  && !params->is_action_possible(
637  tile, scope, tile1, pf_action(node1->action), params)) {
638  continue;
639  }
640  // action move cost depends on action and unit type.
641  if (node1->action == PF_ACTION_ATTACK
642  && (utype_has_flag(params->utype, UTYF_ONEATTACK)
643  || utype_can_do_action(params->utype,
644  ACTION_SUICIDE_ATTACK))) {
645  /* Assume that the attack will be a suicide attack even if a
646  * regular attack may be legal. */
647  cost = params->move_rate;
648  } else {
649  cost = SINGLE_MOVE;
650  }
651  } else if (node1->node_known_type == TILE_UNKNOWN) {
652  cost = params->utype->unknown_move_cost;
653  } else {
654  cost = params->get_MC(tile, scope, tile1,
655  pf_move_scope(node1->move_scope), params);
656  }
657  if (cost == PF_IMPOSSIBLE_MC) {
658  continue;
659  }
660  cost =
662  if (cost == PF_IMPOSSIBLE_MC) {
663  continue;
664  }
665 
666  // Total cost at tile1. Cost may be negative; see pf_turns().
667  cost += node->cost;
668 
669  // Evaluate the extra cost if it's relevant
670  if (nullptr != params->get_EC) {
671  extra = node->extra_cost;
672  // Add the cached value
673  extra += node1->extra_tile;
674  }
675 
676  // Update costs.
677  cost_of_path = pf_total_CC(params, cost, extra);
678 
679  if (NS_INIT == node1->status) {
680  // We are reaching this node for the first time.
681  node1->status = NS_NEW;
682  node1->extra_cost = extra;
683  node1->cost = cost;
684  node1->dir_to_here = dir;
685  // As we prefer lower costs, let's reverse the cost of the path.
686  map_index_pq_insert(pfnm->queue, tindex1, -cost_of_path);
687  } else if (cost_of_path
688  < pf_total_CC(params, node1->cost, node1->extra_cost)) {
689  /* We found a better route to 'tile1'. Let's register 'tindex1' to
690  * the priority queue. Node status step B. to C. */
691  node1->status = NS_NEW;
692  node1->extra_cost = extra;
693  node1->cost = cost;
694  node1->dir_to_here = dir;
695  // As we prefer lower costs, let's reverse the cost of the path.
696  map_index_pq_replace(pfnm->queue, tindex1, -cost_of_path);
697  }
698  }
700  }
701 
702  // Get the next node (the index with the highest priority).
703  if (!map_index_pq_remove(pfnm->queue, &tindex)) {
704  // No more indexes in the priority queue, iteration end.
705  return false;
706  }
707 
708 #ifdef PF_DEBUG
709  fc_assert(NS_NEW == pfnm->lattice[tindex].status);
710 #endif
711 
712  // Change the pf_map iterator. Node status step C. to D.
713  pfm->tile = index_to_tile(params->map, tindex);
714  pfnm->lattice[tindex].status = NS_PROCESSED;
715 
716  return true;
717 }
718 
722 static inline bool pf_normal_map_iterate_until(struct pf_normal_map *pfnm,
723  struct tile *ptile)
724 {
725  struct pf_map *pfm = PF_MAP(pfnm);
726  struct pf_normal_node *node = pfnm->lattice + tile_index(ptile);
727 
728  if (nullptr == pf_map_parameter(pfm)->get_costs) {
729  // Start position is handled in every function calling this function.
730  if (NS_UNINIT == node->status) {
731  // Initialize the node, for doing the following tests.
732  if (!pf_normal_node_init(pfnm, node, ptile, PF_MS_NONE)) {
733  return false;
734  }
735  } else if (TB_IGNORE == node->behavior) {
736  /* Simpliciation: if we cannot enter this node at all, don't iterate
737  * the whole map. */
738  return false;
739  }
740  } // Else, this is a jumbo map, not dealing with normal nodes.
741 
742  while (NS_PROCESSED != node->status) {
743  if (!pf_map_iterate(pfm)) {
744  /* All reachable destination have been iterated, 'ptile' is
745  * unreachable. */
746  return false;
747  }
748  }
749 
750  return true;
751 }
752 
758 static int pf_normal_map_move_cost(struct pf_map *pfm, struct tile *ptile)
759 {
760  struct pf_normal_map *pfnm = PF_NORMAL_MAP(pfm);
761 
762  if (ptile == pfm->params.start_tile) {
763  return 0;
764  } else if (pf_normal_map_iterate_until(pfnm, ptile)) {
765  return (pfnm->lattice[tile_index(ptile)].cost
768  } else {
769  return PF_IMPOSSIBLE_MC;
770  }
771 }
772 
777 static PFPath pf_normal_map_path(struct pf_map *pfm, struct tile *ptile)
778 {
779  struct pf_normal_map *pfnm = PF_NORMAL_MAP(pfm);
780 
781  if (ptile == pfm->params.start_tile) {
782  return PFPath(pf_map_parameter(pfm));
783  } else if (pf_normal_map_iterate_until(pfnm, ptile)) {
784  return pf_normal_map_construct_path(pfnm, ptile);
785  } else {
786  return PFPath();
787  }
788 }
789 
795 static bool pf_normal_map_position(struct pf_map *pfm, struct tile *ptile,
796  struct pf_position *pos)
797 {
798  struct pf_normal_map *pfnm = PF_NORMAL_MAP(pfm);
799 
800  if (ptile == pfm->params.start_tile) {
802  return true;
803  } else if (pf_normal_map_iterate_until(pfnm, ptile)) {
804  pf_normal_map_fill_position(pfnm, ptile, pos);
805  return true;
806  } else {
807  return false;
808  }
809 }
810 
814 static void pf_normal_map_destroy(struct pf_map *pfm)
815 {
816  struct pf_normal_map *pfnm = PF_NORMAL_MAP(pfm);
817 
818  delete[] pfnm->lattice;
819  map_index_pq_destroy(pfnm->queue);
820  delete pfnm;
821 }
822 
826 static struct pf_map *pf_normal_map_new(const struct pf_parameter *parameter)
827 {
828  struct pf_normal_map *pfnm;
829  struct pf_map *base_map;
830  struct pf_parameter *params;
831  struct pf_normal_node *node;
832 
833  if (nullptr == parameter->get_costs) {
834  // 'get_MC' callback must be set.
835  fc_assert_ret_val(nullptr != parameter->get_MC, nullptr);
836 
837  // 'get_move_scope' callback must be set.
838  fc_assert_ret_val(parameter->get_move_scope != nullptr, nullptr);
839  }
840 
841  pfnm = new pf_normal_map;
842  base_map = &pfnm->base_map;
843  params = &base_map->params;
844 #ifdef PF_DEBUG
845  // Set the mode, used for cast check.
846  base_map->mode = PF_NORMAL;
847 #endif // PF_DEBUG
848 
849  // Allocate the map.
850  pfnm->lattice = new pf_normal_node[MAP_INDEX_SIZE]();
851  pfnm->queue = map_index_pq_new(INITIAL_QUEUE_SIZE);
852 
853  // Copy parameters.
854  *params = *parameter;
855 
856  // Initialize virtual function table.
857  base_map->destroy = pf_normal_map_destroy;
859  base_map->get_path = pf_normal_map_path;
861  if (nullptr != params->get_costs) {
862  base_map->iterate = pf_jumbo_map_iterate;
863  } else {
864  base_map->iterate = pf_normal_map_iterate;
865  }
866 
867  // Initialise starting node.
868  node = pfnm->lattice + tile_index(params->start_tile);
869  if (nullptr == params->get_costs) {
870  if (!pf_normal_node_init(pfnm, node, params->start_tile, PF_MS_NONE)) {
871  // Always fails.
872  fc_assert(true
873  == pf_normal_node_init(pfnm, node, params->start_tile,
874  PF_MS_NONE));
875  }
876 
877  if (nullptr != params->transported_by_initially) {
878  /* Overwrite. It is safe because we cannot return to start tile with
879  * pf_normal_map. */
880  node->move_scope |= PF_MS_TRANSPORT;
881  if (!utype_can_freely_unload(params->utype,
882  params->transported_by_initially)
883  && nullptr == tile_city(params->start_tile)
884  && !tile_has_native_base(params->start_tile,
885  params->transported_by_initially)) {
886  // Cannot disembark, don't leave transporter.
887  node->behavior = TB_DONT_LEAVE;
888  }
889  }
890  }
891 
892  // Initialise the iterator.
893  base_map->tile = params->start_tile;
894 
895  /* This makes calculations of turn/moves_left more convenient, but we
896  * need to subtract this value before we return cost to the user. Note
897  * that cost may be negative if moves_left_initially > move_rate
898  * (see pf_turns()). */
899  node->cost = pf_move_rate(params) - pf_moves_left_initially(params);
900  node->extra_cost = 0;
901  node->dir_to_here = direction8_invalid();
902  node->status = NS_PROCESSED;
903 
904  return PF_MAP(pfnm);
905 }
906 
907 // ================ Specific pf_danger_* mode structures =================
908 
909 /* Danger path-finding maps are used for units which can cross some areas
910  * but not ending their turn there. It used to be used for triremes notably.
911  * But since Freeciv 2.2, units with the "Trireme" flag just have
912  * restricted moves, then it is not use anymore. */
913 
914 // Node definition. Note we try to have the smallest data as possible.
916  signed short cost; /* total_MC. 'cost' may be negative, see comment in
917  * pf_turns(). */
918  unsigned extra_cost; // total_EC. Can be huge, (higher than 'cost').
919  unsigned dir_to_here : 4; /* Direction from which we came. It's
920  * an 'enum direction8' including
921  * possibility of direction8_invalid (so we need
922  * 4 bits) */
923  unsigned status : 3; // 'enum pf_node_status' really.
924 
925  // Cached values
926  unsigned move_scope : 3; // 'enum pf_move_scope really.
927  unsigned action : 2; // 'enum pf_action really.
928  unsigned node_known_type : 2; // 'enum known_type' really.
929  unsigned behavior : 2; // 'enum tile_behavior' really.
930  unsigned zoc_number : 2; // 'enum pf_zoc_type' really.
931  bool is_dangerous : 1; // Whether we cannot end the turn there.
932  bool waited : 1; // TRUE if waited to get there.
933  unsigned short extra_tile; // EC
934 
935  /* Segment leading across the danger area back to the nearest safe node:
936  * need to remeber costs and stuff. */
937  struct pf_danger_pos {
938  signed short cost; // See comment above.
939  unsigned extra_cost; // See comment above.
940  signed dir_to_here : 4; // See comment above.
942 };
943 
944 // Derived structure of struct pf_map.
946  struct pf_map base_map; // Base structure, must be the first!
947 
948  struct map_index_pq *queue; /* Queue of nodes we have reached but not
949  * processed yet (NS_NEW and NS_WAITING),
950  * sorted by their total_CC. */
951  struct map_index_pq *danger_queue; // Dangerous positions.
952  struct pf_danger_node *lattice; // Lattice of nodes.
953 };
954 
955 // Up-cast macro.
956 #ifdef PF_DEBUG
957 static inline pf_danger_map *pf_danger_map_check(pf_map *pfm)
958 {
959  fc_assert_ret_val_msg(nullptr != pfm && PF_DANGER == pfm->mode, nullptr,
960  "Wrong pf_map to pf_danger_map conversion.");
961  return reinterpret_cast<struct pf_danger_map *>(pfm);
962 }
963 #define PF_DANGER_MAP(pfm) pf_danger_map_check(pfm)
964 #else
965 #define PF_DANGER_MAP(pfm) ((struct pf_danger_map *) (pfm))
966 #endif // PF_DEBUG
967 
968 // =============== Specific pf_danger_* mode functions ==================
969 
975 static inline bool pf_danger_node_init(struct pf_danger_map *pfdm,
976  struct pf_danger_node *node,
977  struct tile *ptile,
978  enum pf_move_scope previous_scope)
979 {
980  const struct pf_parameter *params = pf_map_parameter(PF_MAP(pfdm));
981  enum known_type node_known_type;
982  enum pf_action action;
983 
984 #ifdef PF_DEBUG
985  fc_assert(NS_UNINIT == node->status);
986  // Else, not a critical problem, but waste of time.
987 #endif
988 
989  node->status = NS_INIT;
990 
991  // Establish the "known" status of node.
992  if (params->omniscience) {
993  node_known_type = TILE_KNOWN_SEEN;
994  } else {
995  node_known_type = tile_get_known(ptile, params->owner);
996  }
997  node->node_known_type = node_known_type;
998 
999  // Establish the tile behavior.
1000  if (nullptr != params->get_TB) {
1001  node->behavior = params->get_TB(ptile, node_known_type, params);
1002  if (TB_IGNORE == node->behavior && params->start_tile != ptile) {
1003  return false;
1004  }
1005  }
1006 
1007  if (TILE_UNKNOWN != node_known_type) {
1008  bool can_disembark;
1009 
1010  // Test if we can invade tile.
1011  if (!utype_has_flag(params->utype, UTYF_CIVILIAN)
1012  && !player_can_invade_tile(params->owner, ptile)) {
1013  // Maybe overwrite node behavior.
1014  if (params->start_tile != ptile) {
1015  node->behavior = TB_IGNORE;
1016  return false;
1017  } else if (TB_NORMAL == node->behavior) {
1018  node->behavior = TB_IGNORE;
1019  }
1020  }
1021 
1022  // Test the possibility to perform an action.
1023  if (nullptr != params->get_action) {
1024  action = params->get_action(ptile, node_known_type, params);
1025  if (PF_ACTION_IMPOSSIBLE == action) {
1026  // Maybe overwrite node behavior.
1027  if (params->start_tile != ptile) {
1028  node->behavior = TB_IGNORE;
1029  return false;
1030  } else if (TB_NORMAL == node->behavior) {
1031  node->behavior = TB_IGNORE;
1032  }
1034  } else if (PF_ACTION_NONE != action
1035  && TB_DONT_LEAVE != node->behavior) {
1036  // Overwrite node behavior.
1037  node->behavior = TB_DONT_LEAVE;
1038  }
1039  node->action = action;
1040  }
1041 
1042  /* Test the possibility to move from/to 'ptile'. */
1043  node->move_scope = params->get_move_scope(ptile, &can_disembark,
1044  previous_scope, params);
1045  if (PF_MS_NONE == node->move_scope && PF_ACTION_NONE == node->action
1046  && params->ignore_none_scopes) {
1047  // Maybe overwrite node behavior.
1048  if (params->start_tile != ptile) {
1049  node->behavior = TB_IGNORE;
1050  return false;
1051  } else if (TB_NORMAL == node->behavior) {
1052  node->behavior = TB_IGNORE;
1053  }
1054  } else if (PF_MS_TRANSPORT == node->move_scope && !can_disembark
1055  && (params->start_tile != ptile
1056  || nullptr == params->transported_by_initially)) {
1057  // Overwrite node behavior.
1058  node->behavior = TB_DONT_LEAVE;
1059  }
1060 
1061  /* ZOC_MINE means can move unrestricted from/into it, ZOC_ALLIED means
1062  * can move unrestricted into it, but not necessarily from it. */
1063  if (nullptr != params->get_zoc && nullptr == tile_city(ptile)
1064  && !terrain_has_flag(tile_terrain(ptile), TER_NO_ZOC)
1065  && !params->get_zoc(params->owner, ptile, params->map)) {
1066  node->zoc_number =
1067  (0 < unit_list_size(ptile->units) ? ZOC_ALLIED : ZOC_NO);
1068  }
1069  } else {
1070  node->move_scope = PF_MS_NATIVE;
1071  }
1072 
1073  // Evaluate the extra cost of the destination.
1074  if (nullptr != params->get_EC) {
1075  node->extra_tile = params->get_EC(ptile, node_known_type, params);
1076  }
1077 
1078  node->is_dangerous =
1079  params->is_pos_dangerous(ptile, node_known_type, params);
1080 
1081  return true;
1082 }
1083 
1088 static void pf_danger_map_fill_position(const struct pf_danger_map *pfdm,
1089  struct tile *ptile,
1090  struct pf_position *pos)
1091 {
1092  int tindex = tile_index(ptile);
1093  struct pf_danger_node *node = pfdm->lattice + tindex;
1094  const struct pf_parameter *params = pf_map_parameter(PF_MAP(pfdm));
1095 
1096 #ifdef PF_DEBUG
1098  || NS_WAITING == node->status,
1099  "Unreached destination (%d, %d).", TILE_XY(ptile));
1100 #endif // PF_DEBUG
1101 
1102  pos->tile = ptile;
1103  pos->total_EC = node->extra_cost;
1104  pos->total_MC =
1105  (node->cost - pf_move_rate(params) + pf_moves_left_initially(params));
1106  pos->turn = pf_turns(params, node->cost);
1107  pos->moves_left = pf_moves_left(params, node->cost);
1108 #ifdef PF_DEBUG
1109  fc_assert(params->fuel == 1);
1110  fc_assert(params->fuel_left_initially == 1);
1111 #endif // PF_DEBUG
1112  pos->fuel_left = 1;
1113  pos->dir_to_here = direction8(node->dir_to_here);
1114  pos->dir_to_next_pos = direction8_invalid(); // This field does not apply.
1115 
1116  if (node->cost > 0) {
1117  pf_finalize_position(params, pos);
1118  }
1119 }
1120 
1126 static inline int
1128  int cost)
1129 {
1130  int moves_left = pf_moves_left(param, cost);
1131 
1132  if (moves_left < pf_move_rate(param)) {
1133  return cost + moves_left;
1134  } else {
1135  return cost;
1136  }
1137 }
1138 
1144  struct tile *ptile)
1145 {
1146  enum direction8 dir_next = direction8_invalid();
1147  struct pf_danger_node::pf_danger_pos *danger_seg = nullptr;
1148  bool waited = false;
1149  struct pf_danger_node *node = pfdm->lattice + tile_index(ptile);
1150  int length = 1;
1151  struct tile *iter_tile = ptile;
1152  const struct pf_parameter *params = pf_map_parameter(PF_MAP(pfdm));
1153  int i;
1154 
1155 #ifdef PF_DEBUG
1157  || NS_WAITING == node->status,
1158  PFPath(), // Return empty path
1159  "Unreached destination (%d, %d).", TILE_XY(ptile));
1160 #endif // PF_DEBUG
1161 
1162  // First iterate to find path length.
1163  while (iter_tile != params->start_tile) {
1164  if (!node->is_dangerous && node->waited) {
1165  length += 2;
1166  } else {
1167  length++;
1168  }
1169 
1170  if (!node->is_dangerous || !danger_seg) {
1171  // We are in the normal node and dir_to_here field is valid
1172  dir_next = direction8(node->dir_to_here);
1173  /* d_node->danger_segment is the indicator of what lies ahead
1174  * if it's non-nullptr, we are entering a danger segment,
1175  * if it's nullptr, we are not on one so danger_seg should be nullptr.
1176  */
1177  danger_seg = node->danger_segment;
1178  } else {
1179  // We are in a danger segment.
1180  dir_next = direction8(danger_seg->dir_to_here);
1181  danger_seg++;
1182  }
1183 
1184  // Step backward.
1185  iter_tile = mapstep(params->map, iter_tile, DIR_REVERSE(dir_next));
1186  node = pfdm->lattice + tile_index(iter_tile);
1187  }
1188 
1189  // Allocate memory for path.
1190  auto path = PFPath(length);
1191 
1192  // Reset variables for main iteration.
1193  iter_tile = ptile;
1194  node = pfdm->lattice + tile_index(ptile);
1195  danger_seg = nullptr;
1196  waited = false;
1197 
1198  for (i = length - 1; i >= 0; i--) {
1199  bool old_waited = false;
1200 
1201  // 1: Deal with waiting.
1202  if (!node->is_dangerous) {
1203  if (waited) {
1204  /* Waited at _this_ tile, need to record it twice in the
1205  * path. Here we record our state _after_ waiting (e.g.
1206  * full move points). */
1207  path[i].tile = iter_tile;
1208  path[i].total_EC = node->extra_cost;
1209  path[i].turn = pf_turns(
1210  params,
1212  path[i].moves_left = params->move_rate;
1213  path[i].fuel_left = params->fuel;
1214  path[i].total_MC = ((path[i].turn - 1) * params->move_rate
1215  + params->moves_left_initially);
1216  path[i].dir_to_next_pos = dir_next;
1217  pf_finalize_position(params, &path[i]);
1218  /* Set old_waited so that we record direction8_invalid() as a
1219  * direction at the step we were going to wait. */
1220  old_waited = true;
1221  i--;
1222  }
1223  // Update "waited" (node->waited means "waited to get here").
1224  waited = node->waited;
1225  }
1226 
1227  // 2: Fill the current position.
1228  path[i].tile = iter_tile;
1229  if (!node->is_dangerous || !danger_seg) {
1230  path[i].total_MC = node->cost;
1231  path[i].total_EC = node->extra_cost;
1232  } else {
1233  // When on dangerous tiles, must have a valid danger segment.
1234  fc_assert_ret_val(danger_seg != nullptr, PFPath());
1235  path[i].total_MC = danger_seg->cost;
1236  path[i].total_EC = danger_seg->extra_cost;
1237  }
1238  path[i].turn = pf_turns(params, path[i].total_MC);
1239  path[i].moves_left = pf_moves_left(params, path[i].total_MC);
1240 #ifdef PF_DEBUG
1241  fc_assert(params->fuel == 1);
1242  fc_assert(params->fuel_left_initially == 1);
1243 #endif // PF_DEBUG
1244  path[i].fuel_left = 1;
1245  path[i].total_MC -=
1246  (pf_move_rate(params) - pf_moves_left_initially(params));
1247  path[i].dir_to_next_pos = (old_waited ? direction8_invalid() : dir_next);
1248  if (node->cost > 0) {
1249  pf_finalize_position(params, &path[i]);
1250  }
1251 
1252  // 3: Check if we finished.
1253  if (i == 0) {
1254  // We should be back at the start now!
1255  fc_assert_ret_val(iter_tile == params->start_tile, PFPath());
1256  return path;
1257  }
1258 
1259  // 4: Calculate the next direction.
1260  if (!node->is_dangerous || !danger_seg) {
1261  // We are in the normal node and dir_to_here field is valid.
1262  dir_next = direction8(node->dir_to_here);
1263  /* d_node->danger_segment is the indicator of what lies ahead.
1264  * If it's non-nullptr, we are entering a danger segment,
1265  * If it's nullptr, we are not on one so danger_seg should be nullptr.
1266  */
1267  danger_seg = node->danger_segment;
1268  } else {
1269  // We are in a danger segment.
1270  dir_next = direction8(danger_seg->dir_to_here);
1271  danger_seg++;
1272  }
1273 
1274  // 5: Step further back.
1275  iter_tile = mapstep(params->map, iter_tile, DIR_REVERSE(dir_next));
1276  node = pfdm->lattice + tile_index(iter_tile);
1277  }
1278 
1279  fc_assert_msg(false, "Cannot get to the starting point!");
1280  return PFPath();
1281 }
1282 
1302  struct pf_danger_node *node1)
1303 {
1304  struct tile *ptile = PF_MAP(pfdm)->tile;
1305  struct pf_danger_node *node = pfdm->lattice + tile_index(ptile);
1306  struct pf_danger_node::pf_danger_pos *pos;
1307  int length = 0, i;
1308  const struct pf_parameter *params = pf_map_parameter(PF_MAP(pfdm));
1309 
1310 #ifdef PF_DEBUG
1311  if (nullptr != node1->danger_segment) {
1312  qCritical("Possible memory leak in pf_danger_map_create_segment().");
1313  }
1314 #endif // PF_DEBUG
1315 
1316  // First iteration for determining segment length
1317  while (node->is_dangerous
1318  && direction8_is_valid(direction8(node->dir_to_here))) {
1319  length++;
1320  ptile = mapstep(params->map, ptile, DIR_REVERSE(node->dir_to_here));
1321  node = pfdm->lattice + tile_index(ptile);
1322  }
1323 
1324  // Allocate memory for segment
1325  node1->danger_segment = new pf_danger_node::pf_danger_pos[length];
1326 
1327  // Reset tile and node pointers for main iteration
1328  ptile = PF_MAP(pfdm)->tile;
1329  node = pfdm->lattice + tile_index(ptile);
1330 
1331  // Now fill the positions
1332  for (i = 0, pos = node1->danger_segment; i < length; i++, pos++) {
1333  // Record the direction
1334  pos->dir_to_here = direction8(node->dir_to_here);
1335  pos->cost = node->cost;
1336  pos->extra_cost = node->extra_cost;
1337  if (i == length - 1) {
1338  // The last dangerous node contains "waiting" info
1339  node1->waited = node->waited;
1340  }
1341 
1342  // Step further down the tree
1343  ptile = mapstep(params->map, ptile, DIR_REVERSE(node->dir_to_here));
1344  node = pfdm->lattice + tile_index(ptile);
1345  }
1346 
1347 #ifdef PF_DEBUG
1348  // Make sure we reached a safe node or the start point
1350  || !direction8_is_valid(direction8(node->dir_to_here)));
1351 #endif
1352 }
1353 
1357 static inline int
1358 pf_danger_map_adjust_cost(const struct pf_parameter *params, int cost,
1359  bool to_danger, int moves_left)
1360 {
1361  if (cost == PF_IMPOSSIBLE_MC) {
1362  return PF_IMPOSSIBLE_MC;
1363  }
1364 
1365  cost = MIN(cost, pf_move_rate(params));
1366 
1367  if (to_danger && cost >= moves_left) {
1368  // We would have to end the turn on a dangerous tile!
1369  return PF_IMPOSSIBLE_MC;
1370  } else {
1371  return MIN(cost, moves_left);
1372  }
1373 }
1374 
1413 static bool pf_danger_map_iterate(struct pf_map *pfm)
1414 {
1415  struct pf_danger_map *const pfdm = PF_DANGER_MAP(pfm);
1416  const struct pf_parameter *const params = pf_map_parameter(pfm);
1417  struct tile *tile = pfm->tile;
1418  int tindex = tile_index(tile);
1419  struct pf_danger_node *node = pfdm->lattice + tindex;
1420  pf_move_scope scope = pf_move_scope(node->move_scope);
1421 
1422  /* The previous position is defined by 'tile' (tile pointer), 'node'
1423  * (the data of the tile for the pf_map), and index (the index of the
1424  * position in the Freeciv map). */
1425 
1426  if (!direction8_is_valid(direction8(node->dir_to_here))
1427  && nullptr != params->transported_by_initially) {
1428 #ifdef PF_DEBUG
1429  fc_assert(tile == params->start_tile);
1430 #endif
1431  scope = pf_move_scope(scope | PF_MS_TRANSPORT);
1432  if (!utype_can_freely_unload(params->utype,
1433  params->transported_by_initially)
1434  && nullptr == tile_city(tile)
1436  // Cannot disembark, don't leave transporter.
1437  node->behavior = TB_DONT_LEAVE;
1438  }
1439  }
1440 
1441  for (;;) {
1442  // There is no exit from DONT_LEAVE tiles!
1443  if (node->behavior != TB_DONT_LEAVE && scope != PF_MS_NONE
1444  && (params->move_rate > 0 || node->cost < 0)) {
1445  // Cost at tile but taking into account waiting.
1446  int loc_cost;
1447  if (node->status != NS_WAITING) {
1448  loc_cost = node->cost;
1449  } else {
1450  // We have waited, so we have full moves.
1451  loc_cost =
1453  }
1454 
1455  adjc_dir_iterate(params->map, tile, tile1, dir)
1456  {
1457  /* Calculate the cost of every adjacent position and set them in
1458  * the priority queues for next call to pf_danger_map_iterate(). */
1459  int tindex1 = tile_index(tile1);
1460  struct pf_danger_node *node1 = pfdm->lattice + tindex1;
1461  int cost;
1462  int extra = 0;
1463 
1464  /* As for the previous position, 'tile1', 'node1' and 'tindex1' are
1465  * defining the adjacent position. */
1466 
1467  if (node1->status == NS_PROCESSED || node1->status == NS_WAITING) {
1468  /* This gives 15% speedup. Node status already at step D., E.
1469  * or F. */
1470  continue;
1471  }
1472 
1473  // Initialise target tile if necessary.
1474  if (node1->status == NS_UNINIT) {
1475  /* Only initialize once. See comment for pf_danger_node_init().
1476  * Node status step A. to B. */
1477  if (!pf_danger_node_init(pfdm, node1, tile1, scope)) {
1478  continue;
1479  }
1480  } else if (TB_IGNORE == node1->behavior) {
1481  // We cannot enter this tile at all!
1482  continue;
1483  }
1484 
1485  // Is the move ZOC-ok?
1486  if (node->zoc_number != ZOC_MINE && node1->zoc_number == ZOC_NO) {
1487  continue;
1488  }
1489 
1490  // Evaluate the cost of the move.
1491  if (PF_ACTION_NONE != node1->action) {
1492  if (nullptr != params->is_action_possible
1493  && !params->is_action_possible(
1494  tile, scope, tile1, pf_action(node1->action), params)) {
1495  continue;
1496  }
1497  // action move cost depends on action and unit type.
1498  if (node1->action == PF_ACTION_ATTACK
1499  && (utype_has_flag(params->utype, UTYF_ONEATTACK)
1500  || utype_can_do_action(params->utype,
1501  ACTION_SUICIDE_ATTACK))) {
1502  /* Assume that the attack will be a suicide attack even if a
1503  * regular attack may be legal. */
1504  cost = params->move_rate;
1505  } else {
1506  cost = SINGLE_MOVE;
1507  }
1508  } else if (node1->node_known_type == TILE_UNKNOWN) {
1509  cost = params->utype->unknown_move_cost;
1510  } else {
1511  cost = params->get_MC(tile, scope, tile1,
1512  pf_move_scope(node1->move_scope), params);
1513  }
1514  if (cost == PF_IMPOSSIBLE_MC) {
1515  continue;
1516  }
1517  cost = pf_danger_map_adjust_cost(params, cost, node1->is_dangerous,
1518  pf_moves_left(params, loc_cost));
1519 
1520  if (cost == PF_IMPOSSIBLE_MC) {
1521  // This move is deemed impossible.
1522  continue;
1523  }
1524 
1525  // Total cost at 'tile1'.
1526  cost += loc_cost;
1527 
1528  // Evaluate the extra cost of the destination, if it's relevant.
1529  if (nullptr != params->get_EC) {
1530  extra = node1->extra_tile + node->extra_cost;
1531  }
1532 
1533  /* Update costs and add to queue, if this is a better route
1534  * to 'tile1'. */
1535  if (!node1->is_dangerous) {
1536  int cost_of_path = pf_total_CC(params, cost, extra);
1537 
1538  if (NS_INIT == node1->status
1539  || (cost_of_path
1540  < pf_total_CC(params, node1->cost, node1->extra_cost))) {
1541  /* We are reaching this node for the first time, or we found a
1542  * better route to 'tile1'. Let's register 'tindex1' to the
1543  * priority queue. Node status step B. to C. */
1544  node1->extra_cost = extra;
1545  node1->cost = cost;
1546  node1->dir_to_here = dir;
1547  delete[] node1->danger_segment;
1548  node1->danger_segment = nullptr;
1549  if (node->is_dangerous) {
1550  /* We came from a dangerous tile. So we need to record the
1551  * path we came from until the previous safe position is
1552  * found. See comment for pf_danger_map_create_segment(). */
1553  pf_danger_map_create_segment(pfdm, node1);
1554  } else {
1555  // Maybe clear previously "waited" status of the node.
1556  node1->waited = false;
1557  }
1558  if (NS_INIT == node1->status) {
1559  node1->status = NS_NEW;
1560  map_index_pq_insert(pfdm->queue, tindex1, -cost_of_path);
1561  } else {
1562 #ifdef PF_DEBUG
1563  fc_assert(NS_NEW == node1->status);
1564 #endif
1565  map_index_pq_replace(pfdm->queue, tindex1, -cost_of_path);
1566  }
1567  }
1568  } else {
1569  /* The procedure is slightly different for dangerous nodes.
1570  * We will update costs if:
1571  * 1. we are here for the first time;
1572  * 2. we can possibly go further across dangerous area; or
1573  * 3. we can have lower extra and will not overwrite anything
1574  * useful. Node status step B. to C. */
1575  if (node1->status == NS_INIT) {
1576  // case 1.
1577  node1->extra_cost = extra;
1578  node1->cost = cost;
1579  node1->dir_to_here = dir;
1580  node1->status = NS_NEW;
1581  node1->waited = (node->status == NS_WAITING);
1582  // Extra costs of all nodes in danger_queue are equal!
1583  map_index_pq_insert(pfdm->danger_queue, tindex1, -cost);
1584  } else if ((pf_moves_left(params, cost)
1585  > pf_moves_left(params, node1->cost))
1586  || (node1->status == NS_PROCESSED
1587  && (pf_total_CC(params, cost, extra) < pf_total_CC(
1588  params, node1->cost, node1->extra_cost)))) {
1589  // case 2 or 3.
1590  node1->extra_cost = extra;
1591  node1->cost = cost;
1592  node1->dir_to_here = dir;
1593  node1->status = NS_NEW;
1594  node1->waited = (node->status == NS_WAITING);
1595  // Extra costs of all nodes in danger_queue are equal!
1596  map_index_pq_replace(pfdm->danger_queue, tindex1, -cost);
1597  }
1598  }
1599  }
1601  }
1602 
1603  if (NS_WAITING == node->status) {
1604  // Node status final step E. to F.
1605 #ifdef PF_DEBUG
1606  fc_assert(!node->is_dangerous);
1607 #endif
1608  node->status = NS_PROCESSED;
1609  } else if (!node->is_dangerous
1610  && (pf_moves_left(params, node->cost)
1611  < pf_move_rate(params))) {
1612  int fc, cc;
1613  /* Consider waiting at this node. To do it, put it back into queue.
1614  * Node status final step D. to E. */
1615  fc = pf_danger_map_fill_cost_for_full_moves(params, node->cost);
1616  cc = pf_total_CC(params, fc, node->extra_cost);
1617  node->status = NS_WAITING;
1618  map_index_pq_insert(pfdm->queue, tindex, -cc);
1619  }
1620 
1621  /* Get the next node (the index with the highest priority). First try
1622  * to get it from danger_queue. */
1623  if (map_index_pq_remove(pfdm->danger_queue, &tindex)) {
1624  // Change the pf_map iterator and reset data.
1625  tile = index_to_tile(params->map, tindex);
1626  pfm->tile = tile;
1627  node = pfdm->lattice + tindex;
1628  } else {
1629  // No dangerous nodes to process, go for a safe one.
1630  if (!map_index_pq_remove(pfdm->queue, &tindex)) {
1631  // No more indexes in the priority queue, iteration end.
1632  return false;
1633  }
1634 
1635 #ifdef PF_DEBUG
1636  fc_assert(NS_PROCESSED != pfdm->lattice[tindex].status);
1637 #endif
1638 
1639  // Change the pf_map iterator and reset data.
1640  tile = index_to_tile(params->map, tindex);
1641  pfm->tile = tile;
1642  node = pfdm->lattice + tindex;
1643  if (NS_WAITING != node->status) {
1644  // Node status step C. and D.
1645 #ifdef PF_DEBUG
1646  fc_assert(!node->is_dangerous);
1647 #endif
1648  node->status = NS_PROCESSED;
1649  return true;
1650  }
1651  }
1652 
1653 #ifdef PF_DEBUG
1654  fc_assert(NS_INIT < node->status);
1655 
1656  if (NS_WAITING == node->status) {
1657  // We've already returned this node once, skip it.
1658  log_debug("Considering waiting at (%d, %d)", TILE_XY(tile));
1659  } else if (node->is_dangerous) {
1660  // We don't return dangerous tiles.
1661  log_debug("Reached dangerous tile (%d, %d)", TILE_XY(tile));
1662  }
1663 #endif
1664 
1665  scope = pf_move_scope(node->move_scope);
1666  }
1667 
1668  qCritical("%s(): internal error.", __FUNCTION__);
1669  return false;
1670 }
1671 
1675 static inline bool pf_danger_map_iterate_until(struct pf_danger_map *pfdm,
1676  struct tile *ptile)
1677 {
1678  struct pf_map *pfm = PF_MAP(pfdm);
1679  struct pf_danger_node *node = pfdm->lattice + tile_index(ptile);
1680 
1681  // Start position is handled in every function calling this function.
1682 
1683  if (NS_UNINIT == node->status) {
1684  // Initialize the node, for doing the following tests.
1685  if (!pf_danger_node_init(pfdm, node, ptile, PF_MS_NONE)
1686  || node->is_dangerous) {
1687  return false;
1688  }
1689  } else if (TB_IGNORE == node->behavior || node->is_dangerous) {
1690  /* Simpliciation: if we cannot enter this node at all, or we cannot
1691  * stay at this position, don't iterate the whole map. */
1692  return false;
1693  }
1694 
1695  while (NS_PROCESSED != node->status && NS_WAITING != node->status) {
1696  if (!pf_map_iterate(pfm)) {
1697  /* All reachable destination have been iterated, 'ptile' is
1698  * unreachable. */
1699  return false;
1700  }
1701  }
1702 
1703  return true;
1704 }
1705 
1711 static int pf_danger_map_move_cost(struct pf_map *pfm, struct tile *ptile)
1712 {
1713  struct pf_danger_map *pfdm = PF_DANGER_MAP(pfm);
1714 
1715  if (ptile == pfm->params.start_tile) {
1716  return 0;
1717  } else if (pf_danger_map_iterate_until(pfdm, ptile)) {
1718  return (pfdm->lattice[tile_index(ptile)].cost
1721  } else {
1722  return PF_IMPOSSIBLE_MC;
1723  }
1724 }
1725 
1730 static PFPath pf_danger_map_path(struct pf_map *pfm, struct tile *ptile)
1731 {
1732  struct pf_danger_map *pfdm = PF_DANGER_MAP(pfm);
1733 
1734  if (ptile == pfm->params.start_tile) {
1735  return PFPath(pf_map_parameter(pfm));
1736  } else if (pf_danger_map_iterate_until(pfdm, ptile)) {
1737  return pf_danger_map_construct_path(pfdm, ptile);
1738  } else {
1739  return PFPath();
1740  }
1741 }
1742 
1748 static bool pf_danger_map_position(struct pf_map *pfm, struct tile *ptile,
1749  struct pf_position *pos)
1750 {
1751  struct pf_danger_map *pfdm = PF_DANGER_MAP(pfm);
1752 
1753  if (ptile == pfm->params.start_tile) {
1755  return true;
1756  } else if (pf_danger_map_iterate_until(pfdm, ptile)) {
1757  pf_danger_map_fill_position(pfdm, ptile, pos);
1758  return true;
1759  } else {
1760  return false;
1761  }
1762 }
1763 
1767 static void pf_danger_map_destroy(struct pf_map *pfm)
1768 {
1769  struct pf_danger_map *pfdm = PF_DANGER_MAP(pfm);
1770  struct pf_danger_node *node;
1771  int i;
1772 
1773  // Need to clean up the dangling danger segments.
1774  for (i = 0, node = pfdm->lattice; i < MAP_INDEX_SIZE; i++, node++) {
1775  delete[] node->danger_segment;
1776  node->danger_segment = nullptr;
1777  }
1778  delete[] pfdm->lattice;
1779  map_index_pq_destroy(pfdm->queue);
1780  map_index_pq_destroy(pfdm->danger_queue);
1781  delete pfdm;
1782 }
1783 
1787 static struct pf_map *pf_danger_map_new(const struct pf_parameter *parameter)
1788 {
1789  struct pf_danger_map *pfdm;
1790  struct pf_map *base_map;
1791  struct pf_parameter *params;
1792  struct pf_danger_node *node;
1793 
1794  pfdm = new pf_danger_map;
1795  base_map = &pfdm->base_map;
1796  params = &base_map->params;
1797 #ifdef PF_DEBUG
1798  // Set the mode, used for cast check.
1799  base_map->mode = PF_DANGER;
1800 #endif // PF_DEBUG
1801 
1802  // Allocate the map.
1803  pfdm->lattice = new pf_danger_node[MAP_INDEX_SIZE]();
1804  pfdm->queue = map_index_pq_new(INITIAL_QUEUE_SIZE);
1805  pfdm->danger_queue = map_index_pq_new(INITIAL_QUEUE_SIZE);
1806 
1807  // 'get_MC' callback must be set.
1808  fc_assert_ret_val(parameter->get_MC != nullptr, nullptr);
1809 
1810  // 'is_pos_dangerous' callback must be set.
1811  fc_assert_ret_val(parameter->is_pos_dangerous != nullptr, nullptr);
1812 
1813  // 'get_move_scope' callback must be set.
1814  fc_assert_ret_val(parameter->get_move_scope != nullptr, nullptr);
1815 
1816  // Copy parameters
1817  *params = *parameter;
1818 
1819  // Initialize virtual function table.
1820  base_map->destroy = pf_danger_map_destroy;
1822  base_map->get_path = pf_danger_map_path;
1824  base_map->iterate = pf_danger_map_iterate;
1825 
1826  // Initialise starting node.
1827  node = pfdm->lattice + tile_index(params->start_tile);
1828  if (!pf_danger_node_init(pfdm, node, params->start_tile, PF_MS_NONE)) {
1829  // Always fails.
1830  fc_assert(
1831  true
1832  == pf_danger_node_init(pfdm, node, params->start_tile, PF_MS_NONE));
1833  }
1834 
1835  /* NB: do not handle params->transported_by_initially because we want to
1836  * handle only at start, not when crossing over the start tile for a
1837  * second time. See pf_danger_map_iterate(). */
1838 
1839  // Initialise the iterator.
1840  base_map->tile = params->start_tile;
1841 
1842  /* This makes calculations of turn/moves_left more convenient, but we
1843  * need to subtract this value before we return cost to the user. Note
1844  * that cost may be negative if moves_left_initially > move_rate
1845  * (see pf_turns()). */
1846  node->cost = pf_move_rate(params) - pf_moves_left_initially(params);
1847  node->extra_cost = 0;
1848  node->dir_to_here = direction8_invalid();
1849  node->status = (node->is_dangerous ? NS_NEW : NS_PROCESSED);
1850 
1851  return PF_MAP(pfdm);
1852 }
1853 
1854 // ================= Specific pf_fuel_* mode structures ==================
1855 
1856 /* Fuel path-finding maps are used for units which need to refuel. Usually
1857  * for air units such as planes or missiles.
1858  *
1859  * A big difference with the danger path-finding maps is that the tiles
1860  * which are not refuel points are not considered as dangerous because the
1861  * server uses to move the units at the end of the turn to refuels points. */
1862 
1863 struct pf_fuel_pos;
1864 
1865 // Node definition. Note we try to have the smallest data as possible.
1867  signed short cost; /* total_MC. 'cost' may be negative, see comment in
1868  * pf_turns(). */
1869  unsigned extra_cost; // total_EC. Can be huge, (higher than 'cost').
1870  unsigned moves_left : 12; // Moves left at this position.
1871  unsigned dir_to_here : 4; /* Direction from which we came. It's
1872  * an 'enum direction8' including
1873  * possibility of direction8_invalid (so we need
1874  * 4 bits) */
1875  unsigned status : 3; // 'enum pf_node_status' really.
1876 
1877  // Cached values
1878  unsigned move_scope : 3; // 'enum pf_move_scope really.
1879  unsigned action : 2; // 'enum pf_action really.
1880  unsigned node_known_type : 2; // 'enum known_type' really.
1881  unsigned behavior : 2; // 'enum tile_behavior' really.
1882  unsigned zoc_number : 2; // 'enum pf_zoc_type' really.
1883  signed moves_left_req : 13; /* The minimum required moves left to reach
1884  * this tile. It the number of moves we need
1885  * to reach the nearest refuel point. A
1886  * value of 0 means this is a refuel point.
1887  * FIXME: this is right only for units with
1888  * constant move costs! */
1889  unsigned short extra_tile; // EC
1890  unsigned short cost_to_here[DIR8_MAGIC_MAX]; // Step cost[dir to here]
1891 
1892  /* Segment leading across the danger area back to the nearest safe node:
1893  * need to remember costs and stuff. */
1894  struct pf_fuel_pos *pos;
1895  // Optimal segment to follow to get there (when node is processed).
1897 };
1898 
1899 /* We need to remember how we could get to there (until the previous refuel
1900  * point, or start position), because we could re-process the nodes after
1901  * having waiting somewhere. */
1902 struct pf_fuel_pos {
1903  signed short cost;
1904  unsigned extra_cost;
1905  unsigned moves_left : 12;
1906  unsigned dir_to_here : 4;
1907  unsigned ref_count : 4;
1909 };
1910 
1911 // Derived structure of struct pf_map.
1912 struct pf_fuel_map {
1913  struct pf_map base_map; // Base structure, must be the first!
1914 
1915  struct map_index_pq *queue; /* Queue of nodes we have reached but not
1916  * processed yet (NS_NEW), sorted by their
1917  * total_CC */
1918  struct map_index_pq *waited_queue; /* Queue of nodes to reach farer
1919  * positions after having refueled. */
1920  struct pf_fuel_node *lattice; // Lattice of nodes
1921 };
1922 
1923 // Up-cast macro.
1924 #ifdef PF_DEBUG
1925 static inline pf_fuel_map *pf_fuel_map_check(pf_map *pfm)
1926 {
1927  fc_assert_ret_val_msg(nullptr != pfm && PF_FUEL == pfm->mode, nullptr,
1928  "Wrong pf_map to pf_fuel_map conversion.");
1929  return reinterpret_cast<struct pf_fuel_map *>(pfm);
1930 }
1931 #define PF_FUEL_MAP(pfm) pf_fuel_map_check(pfm)
1932 #else
1933 #define PF_FUEL_MAP(pfm) ((struct pf_fuel_map *) (pfm))
1934 #endif // PF_DEBUG
1935 
1936 // ================= Specific pf_fuel_* mode functions ==================
1937 
1941 static inline int pf_fuel_total_CC(const struct pf_parameter *param,
1942  int cost, int extra, int safety)
1943 {
1944  return pf_total_CC(param, cost, extra) - safety;
1945 }
1946 
1950 static inline int pf_fuel_waited_total_CC(int cost, int safety)
1951 {
1952  return PF_TURN_FACTOR * (cost + 1) - safety - 1;
1953 }
1954 
1960 static inline bool pf_fuel_node_init(struct pf_fuel_map *pffm,
1961  struct pf_fuel_node *node,
1962  struct tile *ptile,
1963  enum pf_move_scope previous_scope)
1964 {
1965  const struct pf_parameter *params = pf_map_parameter(PF_MAP(pffm));
1966  enum known_type node_known_type;
1967  enum pf_action action;
1968 
1969 #ifdef PF_DEBUG
1970  fc_assert(NS_UNINIT == node->status);
1971  // Else, not a critical problem, but waste of time.
1972 #endif
1973 
1974  node->status = NS_INIT;
1975 
1976  // Establish the "known" status of node.
1977  if (params->omniscience) {
1978  node_known_type = TILE_KNOWN_SEEN;
1979  } else {
1980  node_known_type = tile_get_known(ptile, params->owner);
1981  }
1982  node->node_known_type = node_known_type;
1983 
1984  // Establish the tile behavior.
1985  if (nullptr != params->get_TB) {
1986  node->behavior = params->get_TB(ptile, node_known_type, params);
1987  if (TB_IGNORE == node->behavior && params->start_tile != ptile) {
1988  return false;
1989  }
1990  }
1991 
1992  if (TILE_UNKNOWN != node_known_type) {
1993  bool can_disembark;
1994 
1995  // Test if we can invade tile.
1996  if (!utype_has_flag(params->utype, UTYF_CIVILIAN)
1997  && !player_can_invade_tile(params->owner, ptile)) {
1998  // Maybe overwrite node behavior.
1999  if (params->start_tile != ptile) {
2000  node->behavior = TB_IGNORE;
2001  return false;
2002  } else if (TB_NORMAL == node->behavior) {
2003  node->behavior = TB_IGNORE;
2004  }
2005  }
2006 
2007  // Test the possibility to perform an action.
2008  if (nullptr != params->get_action
2009  && PF_ACTION_NONE
2010  != (action =
2011  params->get_action(ptile, node_known_type, params))) {
2012  if (PF_ACTION_IMPOSSIBLE == action) {
2013  // Maybe overwrite node behavior.
2014  if (params->start_tile != ptile) {
2015  node->behavior = TB_IGNORE;
2016  return false;
2017  } else if (TB_NORMAL == node->behavior) {
2018  node->behavior = TB_IGNORE;
2019  }
2021  } else if (TB_DONT_LEAVE != node->behavior) {
2022  // Overwrite node behavior.
2023  node->behavior = TB_DONT_LEAVE;
2024  }
2025  node->action = action;
2026  } else {
2027  node->moves_left_req =
2028  params->get_moves_left_req(ptile, node_known_type, params);
2029  if (PF_IMPOSSIBLE_MC == node->moves_left_req) {
2030  // Overwrite node behavior.
2031  if (params->start_tile == ptile) {
2032  node->behavior = TB_DONT_LEAVE;
2033  } else {
2034  node->behavior = TB_IGNORE;
2035  return false;
2036  }
2037  }
2038  }
2039 
2040  /* Test the possibility to move from/to 'ptile'. */
2041  node->move_scope = params->get_move_scope(ptile, &can_disembark,
2042  previous_scope, params);
2043  if (PF_MS_NONE == node->move_scope && PF_ACTION_NONE == node->action
2044  && params->ignore_none_scopes) {
2045  // Maybe overwrite node behavior.
2046  if (params->start_tile != ptile) {
2047  node->behavior = TB_IGNORE;
2048  return false;
2049  } else if (TB_NORMAL == node->behavior) {
2050  node->behavior = TB_IGNORE;
2051  }
2052  } else if (PF_MS_TRANSPORT == node->move_scope && !can_disembark
2053  && (params->start_tile != ptile
2054  || nullptr == params->transported_by_initially)) {
2055  // Overwrite node behavior.
2056  node->behavior = TB_DONT_LEAVE;
2057  }
2058 
2059  /* ZOC_MINE means can move unrestricted from/into it, ZOC_ALLIED means
2060  * can move unrestricted into it, but not necessarily from it. */
2061  if (nullptr != params->get_zoc && nullptr == tile_city(ptile)
2062  && !terrain_has_flag(tile_terrain(ptile), TER_NO_ZOC)
2063  && !params->get_zoc(params->owner, ptile, params->map)) {
2064  node->zoc_number =
2065  (0 < unit_list_size(ptile->units) ? ZOC_ALLIED : ZOC_NO);
2066  }
2067  } else {
2068  node->moves_left_req =
2069  params->get_moves_left_req(ptile, node_known_type, params);
2070  if (PF_IMPOSSIBLE_MC == node->moves_left_req) {
2071  // Overwrite node behavior.
2072  if (params->start_tile == ptile) {
2073  node->behavior = TB_DONT_LEAVE;
2074  } else {
2075  node->behavior = TB_IGNORE;
2076  return false;
2077  }
2078  }
2079 
2080  node->move_scope = PF_MS_NATIVE;
2081  }
2082 
2083  // Evaluate the extra cost of the destination.
2084  if (nullptr != params->get_EC) {
2085  node->extra_tile = params->get_EC(ptile, node_known_type, params);
2086  }
2087 
2088  return true;
2089 }
2090 
2094 static inline bool pf_fuel_node_dangerous(const struct pf_fuel_node *node)
2095 {
2096  return (nullptr == node->pos
2097  || (node->pos->moves_left < node->moves_left_req
2098  && PF_ACTION_NONE == node->action));
2099 }
2100 
2105 static inline struct pf_fuel_pos *pf_fuel_pos_ref(struct pf_fuel_pos *pos)
2106 {
2107 #ifdef PF_DEBUG
2108  /* Unsure we have enough space to store the new count. Maximum is 10
2109  * (node->pos, node->segment, and 8 for other_pos->prev). */
2110  fc_assert(15 > pos->ref_count);
2111 #endif
2112  pos->ref_count++;
2113  return pos;
2114 }
2115 
2120 static inline void pf_fuel_pos_unref(struct pf_fuel_pos *pos)
2121 {
2122  while (nullptr != pos && 0 == --pos->ref_count) {
2123  struct pf_fuel_pos *prev = pos->prev;
2124 
2125  delete pos;
2126  pos = prev;
2127  }
2128 }
2129 
2134 static inline struct pf_fuel_pos *
2135 pf_fuel_pos_replace(struct pf_fuel_pos *pos, const struct pf_fuel_node *node)
2136 {
2137  if (nullptr == pos) {
2138  pos = new pf_fuel_pos;
2139  pos->ref_count = 1;
2140  } else if (1 < pos->ref_count) {
2141  pos->ref_count--;
2142  pos = new pf_fuel_pos;
2143  pos->ref_count = 1;
2144  } else {
2145 #ifdef PF_DEBUG
2146  fc_assert(1 == pos->ref_count);
2147 #endif
2148  pf_fuel_pos_unref(pos->prev);
2149  }
2150  pos->cost = node->cost;
2151  pos->extra_cost = node->extra_cost;
2152  pos->moves_left = node->moves_left;
2153  pos->dir_to_here = node->dir_to_here;
2154  pos->prev = nullptr;
2155 
2156  return pos;
2157 }
2158 
2162 static inline void
2164  struct pf_position *pos, int cost,
2165  int moves_left)
2166 {
2167  int move_rate = param->move_rate;
2168 
2169  pos->turn = pf_turns(param, cost);
2170  if (move_rate > 0 && param->start_tile != pos->tile) {
2171  pos->fuel_left = moves_left / move_rate;
2172  pos->moves_left = moves_left % move_rate;
2173  } else if (param->start_tile == pos->tile) {
2174  pos->fuel_left = param->fuel_left_initially;
2175  pos->moves_left = param->moves_left_initially;
2176  } else {
2177  pos->fuel_left = param->fuel_left_initially;
2178  pos->moves_left = moves_left;
2179  }
2180 }
2181 
2185 static inline void pf_fuel_finalize_position(
2186  struct pf_position *pos, const struct pf_parameter *params,
2187  const struct pf_fuel_node *node, const struct pf_fuel_pos *head)
2188 {
2189  if (head) {
2190  pf_fuel_finalize_position_base(params, pos, head->cost,
2191  head->moves_left);
2192  } else {
2193  pf_fuel_finalize_position_base(params, pos, node->cost,
2194  node->moves_left);
2195  }
2196 }
2197 
2202 static void pf_fuel_map_fill_position(const struct pf_fuel_map *pffm,
2203  struct tile *ptile,
2204  struct pf_position *pos)
2205 {
2206  int tindex = tile_index(ptile);
2207  struct pf_fuel_node *node = pffm->lattice + tindex;
2208  struct pf_fuel_pos *head = node->segment;
2209  const struct pf_parameter *params = pf_map_parameter(PF_MAP(pffm));
2210 
2211 #ifdef PF_DEBUG
2212  fc_assert_ret_msg(nullptr != head, "Unreached destination (%d, %d).",
2213  TILE_XY(ptile));
2214 #endif // PF_DEBUG
2215 
2216  pos->tile = ptile;
2217  pos->total_EC = head->extra_cost;
2218  pos->total_MC =
2219  (head->cost - pf_move_rate(params) + pf_moves_left_initially(params));
2220  pos->dir_to_here = direction8(head->dir_to_here);
2221  pos->dir_to_next_pos = direction8_invalid(); // This field does not apply.
2222  pf_fuel_finalize_position(pos, params, node, head);
2223 }
2224 
2230 static inline int
2232  int cost, int moves_left)
2233 {
2234 #ifdef PF_DEBUG
2235  fc_assert(0 < param->move_rate);
2236 #endif // PF_DEBUG
2237  return cost + moves_left % param->move_rate;
2238 }
2239 
2244  struct tile *ptile)
2245 {
2246  enum direction8 dir_next = direction8_invalid();
2247  struct pf_fuel_node *node = pffm->lattice + tile_index(ptile);
2248  struct pf_fuel_pos *segment = node->segment;
2249  int length = 1;
2250  struct tile *iter_tile = ptile;
2251  const struct pf_parameter *params = pf_map_parameter(PF_MAP(pffm));
2252  int i;
2253 
2254 #ifdef PF_DEBUG
2255  fc_assert_ret_val_msg(nullptr != segment, PFPath(),
2256  "Unreached destination (%d, %d).", TILE_XY(ptile));
2257 #endif // PF_DEBUG
2258 
2259  // First iterate to find path length.
2260  /* NB: the start point could be reached in the middle of a segment.
2261  * See comment for pf_fuel_map_create_segment(). */
2262  while (direction8_is_valid(direction8(segment->dir_to_here))) {
2263  if (node->moves_left_req == 0) {
2264  // A refuel point.
2265  if (segment != node->segment) {
2266  length += 2;
2267  segment = node->segment;
2268  } else {
2269  length++;
2270  }
2271  } else {
2272  length++;
2273  }
2274 
2275  // Step backward.
2276  iter_tile =
2277  mapstep(params->map, iter_tile, DIR_REVERSE(segment->dir_to_here));
2278  node = pffm->lattice + tile_index(iter_tile);
2279  segment = segment->prev;
2280 #ifdef PF_DEBUG
2281  fc_assert(nullptr != segment);
2282 #endif // PF_DEBUG
2283  }
2284  if (node->moves_left_req == 0 && segment != node->segment) {
2285  // We wait at the start point
2286  length++;
2287  }
2288 
2289  // Allocate memory for path.
2290  auto path = PFPath(length);
2291 
2292  // Reset variables for main iteration.
2293  iter_tile = ptile;
2294  node = pffm->lattice + tile_index(ptile);
2295  segment = node->segment;
2296 
2297  for (i = length - 1; i >= 0; i--) {
2298  // 1: Deal with waiting.
2299  if (node->moves_left_req == 0 && segment != node->segment) {
2300  /* Waited at _this_ tile, need to record it twice in the
2301  * path. Here we record our state _after_ waiting (e.g.
2302  * full move points). */
2303  // MAKE DOUBLY SURE THIS SECTION IS OK
2304  path[i].tile = iter_tile;
2305  path[i].total_EC = segment->extra_cost;
2306  path[i].turn = pf_turns(params, segment->cost);
2307  path[i].total_MC = ((path[i].turn - 1) * params->move_rate
2308  + params->moves_left_initially);
2309  path[i].moves_left = params->move_rate;
2310  path[i].fuel_left = params->fuel;
2311  path[i].dir_to_next_pos = dir_next;
2312 
2313  dir_next = direction8_invalid();
2314  segment = node->segment;
2315  i--;
2316  if (nullptr == segment) {
2317  // We waited at start tile, then 'node->segment' is not set.
2318 #ifdef PF_DEBUG
2319  fc_assert(iter_tile == params->start_tile);
2320  fc_assert(0 == i);
2321 #endif // PF_DEBUG
2322  pf_position_fill_start_tile(&path[i], params);
2323  return path;
2324  }
2325  }
2326 
2327  // 2: Fill the current position.
2328  path[i].tile = iter_tile;
2329  path[i].total_MC = (pf_moves_left_initially(params)
2330  - pf_move_rate(params) + segment->cost);
2331  path[i].total_EC = segment->extra_cost;
2332  path[i].dir_to_next_pos = dir_next;
2333  pf_fuel_finalize_position(&path[i], params, node, segment);
2334 
2335  // 3: Check if we finished.
2336  if (i == 0) {
2337  // We should be back at the start now!
2338  fc_assert_ret_val(iter_tile == params->start_tile, PFPath());
2339  return path;
2340  }
2341 
2342  // 4: Calculate the next direction.
2343  dir_next = direction8(segment->dir_to_here);
2344 
2345  // 5: Step further back.
2346  iter_tile = mapstep(params->map, iter_tile, DIR_REVERSE(dir_next));
2347  node = pffm->lattice + tile_index(iter_tile);
2348  segment = segment->prev;
2349 #ifdef PF_DEBUG
2350  fc_assert(nullptr != segment);
2351 #endif // PF_DEBUG
2352  }
2353 
2354  fc_assert_msg(false, "Cannot get to the starting point!");
2355  return PFPath();
2356 }
2357 
2375 static inline void pf_fuel_map_create_segment(struct pf_fuel_map *pffm,
2376  struct tile *ptile,
2377  struct pf_fuel_node *node)
2378 {
2379  struct pf_fuel_pos *pos, *next;
2380  const struct pf_parameter *params = pf_map_parameter(PF_MAP(pffm));
2381 
2382  pos = pf_fuel_pos_replace(node->pos, node);
2383  node->pos = pos;
2384 
2385  // Iterate until we reach any built segment.
2386  do {
2387  next = pos;
2388  ptile = mapstep(params->map, ptile, DIR_REVERSE(node->dir_to_here));
2389  node = pffm->lattice + tile_index(ptile);
2390  pos = node->pos;
2391  if (nullptr != pos) {
2392  if (pos->cost == node->cost && pos->dir_to_here == node->dir_to_here
2393  && pos->extra_cost == node->extra_cost
2394  && pos->moves_left == node->moves_left) {
2395  // Reached an usable segment.
2396  next->prev = pf_fuel_pos_ref(pos);
2397  break;
2398  }
2399  }
2400  // Update position.
2401  pos = pf_fuel_pos_replace(pos, node);
2402  node->pos = pos;
2403  next->prev = pf_fuel_pos_ref(pos);
2404  } while (0 != node->moves_left_req
2405  && direction8_is_valid(direction8(node->dir_to_here)));
2406 }
2407 
2411 static inline int pf_fuel_map_adjust_cost(int cost, int moves_left,
2412  int move_rate)
2413 {
2414  if (move_rate > 0) {
2415  int remaining_moves = moves_left % move_rate;
2416 
2417  if (remaining_moves == 0) {
2418  remaining_moves = move_rate;
2419  }
2420 
2421  return MIN(cost, remaining_moves);
2422  } else {
2423  return MIN(cost, moves_left);
2424  }
2425 }
2426 
2433 static inline bool
2435  int moves_left, int moves_left_req)
2436 {
2437  if (utype_can_do_action(param->utype, ACTION_SUICIDE_ATTACK)) {
2438  // Case missile
2439  return true;
2440  } else if (utype_has_flag(param->utype, UTYF_ONEATTACK)) {
2441  // Case Bombers
2442  if (moves_left <= param->move_rate) {
2443  // We are in the last turn of fuel, don't attack
2444  return false;
2445  } else {
2446  return true;
2447  }
2448  } else {
2449  // Case fighters
2450  return moves_left - SINGLE_MOVE >= moves_left_req;
2451  }
2452 }
2453 
2489 static bool pf_fuel_map_iterate(struct pf_map *pfm)
2490 {
2491  struct pf_fuel_map *const pffm = PF_FUEL_MAP(pfm);
2492  const struct pf_parameter *const params = pf_map_parameter(pfm);
2493  struct tile *tile = pfm->tile;
2494  int tindex = tile_index(tile);
2495  struct pf_fuel_node *node = pffm->lattice + tindex;
2496  enum pf_move_scope scope = pf_move_scope(node->move_scope);
2497  int priority, waited_priority;
2498  bool waited = false;
2499 
2500  /* The previous position is defined by 'tile' (tile pointer), 'node'
2501  * (the data of the tile for the pf_map), and index (the index of the
2502  * position in the Freeciv map). */
2503 
2504  if (!direction8_is_valid(direction8(node->dir_to_here))
2505  && nullptr != params->transported_by_initially) {
2506 #ifdef PF_DEBUG
2507  fc_assert(tile == params->start_tile);
2508 #endif
2509  scope = pf_move_scope(scope | PF_MS_TRANSPORT);
2510  if (!utype_can_freely_unload(params->utype,
2511  params->transported_by_initially)
2512  && nullptr == tile_city(tile)
2514  // Cannot disembark, don't leave transporter.
2515  node->behavior = TB_DONT_LEAVE;
2516  }
2517  }
2518 
2519  for (;;) {
2520  // There is no exit from DONT_LEAVE tiles!
2521  if (node->behavior != TB_DONT_LEAVE && scope != PF_MS_NONE
2522  && (params->move_rate > 0 || node->cost < 0)) {
2523  int loc_cost = node->cost;
2524  int loc_moves_left = node->moves_left;
2525 
2526  if (0 == node->moves_left_req && 0 < params->move_rate
2527  && 0 == loc_moves_left % params->move_rate
2528  && loc_cost >= params->moves_left_initially) {
2529  /* We have implicitly refueled at the end of the turn. Update also
2530  * 'node->moves_left' to ensure to wait there in paths. */
2531  loc_moves_left = pf_move_rate(params);
2532  node->moves_left = loc_moves_left;
2533  }
2534 
2535  adjc_dir_iterate(params->map, tile, tile1, dir)
2536  {
2537  /* Calculate the cost of every adjacent position and set them in
2538  * the priority queues for next call to pf_fuel_map_iterate(). */
2539  int tindex1 = tile_index(tile1);
2540  struct pf_fuel_node *node1 = pffm->lattice + tindex1;
2541  int cost, extra = 0;
2542  int moves_left;
2543  int cost_of_path, old_cost_of_path;
2544  struct pf_fuel_pos *pos;
2545 
2546  /* As for the previous position, 'tile1', 'node1' and 'tindex1' are
2547  * defining the adjacent position. */
2548 
2549  // Non-full fuel tiles can be updated even after being processed.
2550  if ((NS_PROCESSED == node1->status || NS_WAITING == node1->status)
2551  && 0 == node1->moves_left_req) {
2552  // This gives 15% speedup.
2553  continue;
2554  }
2555 
2556  // Initialise target tile if necessary
2557  if (node1->status == NS_UNINIT) {
2558  /* Only initialize once. See comment for pf_fuel_node_init().
2559  * Node status step A. to B. */
2560  if (!pf_fuel_node_init(pffm, node1, tile1, scope)) {
2561  continue;
2562  }
2563  } else if (TB_IGNORE == node1->behavior) {
2564  // We cannot enter this tile at all!
2565  continue;
2566  }
2567 
2568  // Is the move ZOC-ok?
2569  if (node->zoc_number != ZOC_MINE && node1->zoc_number == ZOC_NO) {
2570  continue;
2571  }
2572 
2573  cost = node1->cost_to_here[dir];
2574  if (0 == cost) {
2575  // Evaluate the cost of the move.
2576  if (PF_ACTION_NONE != node1->action) {
2577  if (nullptr != params->is_action_possible
2578  && !params->is_action_possible(
2579  tile, scope, tile1, pf_action(node1->action), params)) {
2580  node1->cost_to_here[dir] = PF_IMPOSSIBLE_MC + 2;
2581  continue;
2582  }
2583  // action move cost depends on action and unit type.
2584  if (node1->action == PF_ACTION_ATTACK
2585  && (utype_has_flag(params->utype, UTYF_ONEATTACK)
2586  || utype_can_do_action(params->utype,
2587  ACTION_SUICIDE_ATTACK))) {
2588  /* Assume that the attack will be a suicide attack even if a
2589  * regular attack may be legal. */
2590  cost = params->move_rate;
2591  } else {
2592  cost = SINGLE_MOVE;
2593  }
2594  } else if (node1->node_known_type == TILE_UNKNOWN) {
2595  cost = params->utype->unknown_move_cost;
2596  } else {
2597  cost = params->get_MC(tile, scope, tile1,
2598  pf_move_scope(node1->move_scope), params);
2599  }
2600 
2601  if (cost == FC_INFINITY) {
2602  /* tile_move_cost_ptrs() uses FC_INFINITY to flag that all
2603  * movement is spent, e.g., when disembarking from transport. */
2604  cost = params->move_rate;
2605  }
2606 
2607 #ifdef PF_DEBUG
2608  fc_assert(1 << (8 * sizeof(node1->cost_to_here[dir])) > cost + 2);
2609  fc_assert(0 < cost + 2);
2610 #endif // PF_DEBUG
2611 
2612  node1->cost_to_here[dir] = cost + 2;
2613  if (cost == PF_IMPOSSIBLE_MC) {
2614  continue;
2615  }
2616  } else if (cost == PF_IMPOSSIBLE_MC + 2) {
2617  continue;
2618  } else {
2619  cost -= 2;
2620  }
2621 
2622  cost =
2623  pf_fuel_map_adjust_cost(cost, loc_moves_left, params->move_rate);
2624 
2625  moves_left = loc_moves_left - cost;
2626  if (moves_left < node1->moves_left_req
2627  && (!utype_can_do_action(params->utype, ACTION_SUICIDE_ATTACK)
2628  || 0 > moves_left)) {
2629  /* We don't have enough moves left, but missiles
2630  * can do suicidal attacks. */
2631  continue;
2632  }
2633 
2634  if (PF_ACTION_ATTACK == node1->action
2635  && !pf_fuel_map_attack_is_possible(params, loc_moves_left,
2636  node->moves_left_req)) {
2637  // We wouldn't have enough moves left after attacking.
2638  continue;
2639  }
2640 
2641  // Total cost at 'tile1'
2642  cost += loc_cost;
2643 
2644  // Evaluate the extra cost of the destination, if it's relevant.
2645  if (nullptr != params->get_EC) {
2646  extra = node1->extra_tile + node->extra_cost;
2647  }
2648 
2649  /* Update costs and add to queue, if this is a better route
2650  * to tile1. Case safe tiles or reached directly without waiting. */
2651  pos = node1->segment;
2652  cost_of_path = pf_fuel_total_CC(params, cost, extra,
2653  moves_left - node1->moves_left_req);
2654  if (node1->status == NS_INIT) {
2655  // Not calculated yet.
2656  old_cost_of_path = 0;
2657  } else if (pos) {
2658  /* We have a path to this tile. The default values could have been
2659  * overwritten if we had more moves left to deal with waiting.
2660  * Then, we have to get back the value of this node to calculate
2661  * the cost. */
2662  old_cost_of_path =
2663  pf_fuel_total_CC(params, pos->cost, pos->extra_cost,
2664  pos->moves_left - node1->moves_left_req);
2665  } else {
2666  // Default cost
2667  old_cost_of_path =
2668  pf_fuel_total_CC(params, node1->cost, node1->extra_cost,
2669  node1->moves_left - node1->moves_left_req);
2670  }
2671 
2672  /* Step 1: We test if this route is the best to this tile, by a
2673  * direct way, not taking in account waiting. */
2674 
2675  if (NS_INIT == node1->status
2676  || (node1->status == NS_NEW
2677  && cost_of_path < old_cost_of_path)) {
2678  /* We are reaching this node for the first time, or we found a
2679  * better route to 'tile1', or we would have more moves lefts
2680  * at previous position. Let's register 'tindex1' to the
2681  * priority queue. */
2682  node1->extra_cost = extra;
2683  node1->cost = cost;
2684  node1->moves_left = moves_left;
2685  node1->dir_to_here = dir;
2686  /* Always record the segment, including when it is not dangerous
2687  * to move there. */
2688  pf_fuel_map_create_segment(pffm, tile1, node1);
2689  if (NS_INIT == node1->status) {
2690  // Node status B. to C.
2691  node1->status = NS_NEW;
2692  map_index_pq_insert(pffm->queue, tindex1, -cost_of_path);
2693  } else {
2694  // else staying at D.
2695 #ifdef PF_DEBUG
2696  fc_assert(NS_NEW == node1->status);
2697 #endif
2698  if (cost_of_path < old_cost_of_path) {
2699  map_index_pq_replace(pffm->queue, tindex1, -cost_of_path);
2700  }
2701  }
2702  continue; // adjc_dir_iterate()
2703  }
2704 
2705  /* Step 2: We test if this route could open better routes for other
2706  * tiles, if we waited somewhere. */
2707 
2708  if (!waited || NS_NEW == node1->status
2709  || 0 == node1->moves_left_req) {
2710  /* Stops there if:
2711  * 1. we didn't wait to get there ;
2712  * 2. we didn't process yet the node ;
2713  * 3. this is a refuel point. */
2714  continue; // adjc_dir_iterate()
2715  }
2716 
2717 #ifdef PF_DEBUG
2718  fc_assert(NS_PROCESSED == node1->status);
2719 #endif
2720 
2721  if (moves_left > node1->moves_left
2722  || (moves_left == node1->moves_left
2723  && extra < node1->extra_cost)) {
2724  /* We will update costs if:
2725  * 1. we would have more moves left than previously on this node.
2726  * 2. we can have lower extra and will not overwrite anything
2727  * useful. */
2728  node1->extra_cost = extra;
2729  node1->cost = cost;
2730  node1->moves_left = moves_left;
2731  node1->dir_to_here = dir;
2732  map_index_pq_insert(pffm->waited_queue, tindex1,
2734  cost, moves_left - node1->moves_left_req));
2735  }
2736  }
2738  }
2739 
2740  if (NS_WAITING == node->status) {
2741  // Node status final step E. to F.
2742 #ifdef PF_DEBUG
2743  fc_assert(0 == node->moves_left_req);
2744 #endif
2745  node->status = NS_PROCESSED;
2746  } else if (0 == node->moves_left_req && PF_ACTION_NONE == node->action
2747  && node->moves_left < pf_move_rate(params)
2748 #ifdef PF_DEBUG
2749  && (fc_assert(0 < params->move_rate), 0 < params->move_rate)
2750 #endif
2751  && (0 != node->moves_left % params->move_rate
2752  || node->cost < params->moves_left_initially)) {
2753  /* Consider waiting at this node. To do it, put it back into queue.
2754  * Node status final step D. to E. */
2755  node->status = NS_WAITING;
2756  /* The values we use now to calculate waited total_CC
2757  * will be applied to the node after we get it back from the queue
2758  * to get passing-by segments before it without waiting */
2759  map_index_pq_insert(
2760  pffm->queue, tindex,
2762  params, node->cost, node->moves_left),
2763  pf_move_rate(params)));
2764  }
2765 
2766  /* Get the next node (the index with the highest priority). First try
2767  * to get it from waited_queue. */
2768  if (!map_index_pq_priority(pffm->queue, &priority)
2769  || (map_index_pq_priority(pffm->waited_queue, &waited_priority)
2770  && priority < waited_priority)) {
2771  if (!map_index_pq_remove(pffm->waited_queue, &tindex)) {
2772  // End of the iteration.
2773  return false;
2774  }
2775 
2776  // Change the pf_map iterator and reset data.
2777  tile = index_to_tile(params->map, tindex);
2778  pfm->tile = tile;
2779  node = pffm->lattice + tindex;
2780  waited = true;
2781 #ifdef PF_DEBUG
2782  fc_assert(0 < node->moves_left_req);
2783  fc_assert(NS_PROCESSED == node->status);
2784 #endif
2785  } else {
2786 #ifdef PF_DEBUG
2787  bool success = map_index_pq_remove(pffm->queue, &tindex);
2788 
2789  fc_assert(true == success);
2790 #else
2791  map_index_pq_remove(pffm->queue, &tindex);
2792 #endif
2793 
2794  // Change the pf_map iterator and reset data.
2795  tile = index_to_tile(params->map, tindex);
2796  pfm->tile = tile;
2797  node = pffm->lattice + tindex;
2798 
2799 #ifdef PF_DEBUG
2800  fc_assert(NS_PROCESSED != node->status);
2801 #endif // PF_DEBUG
2802 
2803  waited = (NS_WAITING == node->status);
2804  if (waited) {
2805  // Arrange waiting at the node
2806  node->cost = pf_fuel_map_fill_cost_for_full_moves(params, node->cost,
2807  node->moves_left);
2808  node->moves_left = pf_move_rate(params);
2809  } else if (!pf_fuel_node_dangerous(node)) {
2810  // Node status step C. and D.
2811  node->status = NS_PROCESSED;
2812  node->segment = pf_fuel_pos_ref(node->pos);
2813  return true;
2814  }
2815  }
2816 
2817 #ifdef PF_DEBUG
2818  fc_assert(NS_INIT < node->status);
2819 
2820  if (NS_WAITING == node->status) {
2821  // We've already returned this node once, skip it.
2822  log_debug("Considering waiting at (%d, %d)", TILE_XY(tile));
2823  } else if (NS_PROCESSED == node->status) {
2824  // We've already returned this node once, skip it.
2825  log_debug("Reprocessing tile (%d, %d)", TILE_XY(tile));
2826  } else if (pf_fuel_node_dangerous(node)) {
2827  // We don't return dangerous tiles.
2828  log_debug("Reached dangerous tile (%d, %d)", TILE_XY(tile));
2829  }
2830 #endif // PF_DEBUG
2831 
2832  scope = pf_move_scope(node->move_scope);
2833  }
2834 
2835  qCritical("%s(): internal error.", __FUNCTION__);
2836  return false;
2837 }
2838 
2842 static inline bool pf_fuel_map_iterate_until(struct pf_fuel_map *pffm,
2843  struct tile *ptile)
2844 {
2845  struct pf_map *pfm = PF_MAP(pffm);
2846  struct pf_fuel_node *node = pffm->lattice + tile_index(ptile);
2847 
2848  // Start position is handled in every function calling this function.
2849 
2850  if (NS_UNINIT == node->status) {
2851  // Initialize the node, for doing the following tests.
2852  if (!pf_fuel_node_init(pffm, node, ptile, PF_MS_NONE)) {
2853  return false;
2854  }
2855  } else if (TB_IGNORE == node->behavior) {
2856  /* Simpliciation: if we cannot enter this node at all, don't iterate the
2857  * whole map. */
2858  return false;
2859  }
2860 
2861  while (nullptr == node->segment) {
2862  if (!pf_map_iterate(pfm)) {
2863  /* All reachable destination have been iterated, 'ptile' is
2864  * unreachable. */
2865  return false;
2866  }
2867  }
2868 
2869  return true;
2870 }
2871 
2877 static int pf_fuel_map_move_cost(struct pf_map *pfm, struct tile *ptile)
2878 {
2879  struct pf_fuel_map *pffm = PF_FUEL_MAP(pfm);
2880 
2881  if (ptile == pfm->params.start_tile) {
2882  return 0;
2883  } else if (pf_fuel_map_iterate_until(pffm, ptile)) {
2884  const struct pf_fuel_node *node = pffm->lattice + tile_index(ptile);
2885 
2886  return (node->segment->cost - pf_move_rate(pf_map_parameter(pfm))
2888  } else {
2889  return PF_IMPOSSIBLE_MC;
2890  }
2891 }
2892 
2897 static PFPath pf_fuel_map_path(struct pf_map *pfm, struct tile *ptile)
2898 {
2899  struct pf_fuel_map *pffm = PF_FUEL_MAP(pfm);
2900 
2901  if (ptile == pfm->params.start_tile) {
2902  return PFPath(pf_map_parameter(pfm));
2903  } else if (pf_fuel_map_iterate_until(pffm, ptile)) {
2904  return pf_fuel_map_construct_path(pffm, ptile);
2905  } else {
2906  return PFPath();
2907  }
2908 }
2909 
2915 static bool pf_fuel_map_position(struct pf_map *pfm, struct tile *ptile,
2916  struct pf_position *pos)
2917 {
2918  struct pf_fuel_map *pffm = PF_FUEL_MAP(pfm);
2919 
2920  if (ptile == pfm->params.start_tile) {
2922  return true;
2923  } else if (pf_fuel_map_iterate_until(pffm, ptile)) {
2924  pf_fuel_map_fill_position(pffm, ptile, pos);
2925  return true;
2926  } else {
2927  return false;
2928  }
2929 }
2930 
2934 static void pf_fuel_map_destroy(struct pf_map *pfm)
2935 {
2936  struct pf_fuel_map *pffm = PF_FUEL_MAP(pfm);
2937  struct pf_fuel_node *node;
2938  int i;
2939 
2940  // Need to clean up the dangling fuel segments.
2941  for (i = 0, node = pffm->lattice; i < MAP_INDEX_SIZE; i++, node++) {
2942  pf_fuel_pos_unref(node->pos);
2943  pf_fuel_pos_unref(node->segment);
2944  }
2945  delete pffm->lattice;
2946  map_index_pq_destroy(pffm->queue);
2947  map_index_pq_destroy(pffm->waited_queue);
2948  delete pffm;
2949 }
2950 
2954 static struct pf_map *pf_fuel_map_new(const struct pf_parameter *parameter)
2955 {
2956  struct pf_fuel_map *pffm;
2957  struct pf_map *base_map;
2958  struct pf_parameter *params;
2959  struct pf_fuel_node *node;
2960 
2961  // 'get_MC' callback must be set.
2962  fc_assert_ret_val(parameter->get_MC != nullptr, nullptr);
2963 
2964  // 'get_moves_left_req' callback must be set.
2965  fc_assert_ret_val(parameter->get_moves_left_req != nullptr, nullptr);
2966 
2967  // 'get_move_scope' callback must be set.
2968  fc_assert_ret_val(parameter->get_move_scope != nullptr, nullptr);
2969 
2970  pffm = new pf_fuel_map;
2971  base_map = &pffm->base_map;
2972  params = &base_map->params;
2973 #ifdef PF_DEBUG
2974  // Set the mode, used for cast check.
2975  base_map->mode = PF_FUEL;
2976 #endif // PF_DEBUG
2977 
2978  // Allocate the map.
2979  pffm->lattice = new pf_fuel_node[MAP_INDEX_SIZE]();
2980  pffm->queue = map_index_pq_new(INITIAL_QUEUE_SIZE);
2981  pffm->waited_queue = map_index_pq_new(INITIAL_QUEUE_SIZE);
2982 
2983  // Copy parameters.
2984  *params = *parameter;
2985 
2986  // Initialize virtual function table.
2987  base_map->destroy = pf_fuel_map_destroy;
2989  base_map->get_path = pf_fuel_map_path;
2990  base_map->get_position = pf_fuel_map_position;
2991  base_map->iterate = pf_fuel_map_iterate;
2992 
2993  // Initialise starting node.
2994  node = pffm->lattice + tile_index(params->start_tile);
2995  if (!pf_fuel_node_init(pffm, node, params->start_tile, PF_MS_NONE)) {
2996  // Always fails.
2997  fc_assert(
2998  true
2999  == pf_fuel_node_init(pffm, node, params->start_tile, PF_MS_NONE));
3000  }
3001 
3002  /* NB: do not handle params->transported_by_initially because we want to
3003  * handle only at start, not when crossing over the start tile for a
3004  * second time. See pf_danger_map_iterate(). */
3005 
3006  // Initialise the iterator.
3007  base_map->tile = params->start_tile;
3008 
3009  /* This makes calculations of turn/moves_left more convenient, but we
3010  * need to subtract this value before we return cost to the user. Note
3011  * that cost may be negative if moves_left_initially > move_rate
3012  * (see pf_turns()). */
3013  node->moves_left = pf_moves_left_initially(params);
3014  node->cost = pf_move_rate(params) - node->moves_left;
3015  node->extra_cost = 0;
3016  node->dir_to_here = direction8_invalid();
3017  // Record a segment. We need it for correct paths.
3018  node->segment =
3019  pf_fuel_pos_ref(node->pos = pf_fuel_pos_replace(nullptr, node));
3020  node->status = NS_PROCESSED;
3021 
3022  return PF_MAP(pffm);
3023 }
3024 
3025 // ====================== pf_map public functions =======================
3026 
3031 struct pf_map *pf_map_new(const struct pf_parameter *parameter)
3032 {
3033  if (parameter->is_pos_dangerous) {
3034  if (parameter->get_moves_left_req) {
3035  qCritical("path finding code cannot deal with dangers "
3036  "and fuel together.");
3037  }
3038  if (parameter->get_costs) {
3039  qCritical("jumbo callbacks for danger maps are not yet implemented.");
3040  }
3041  return pf_danger_map_new(parameter);
3042  } else if (parameter->get_moves_left_req) {
3043  if (parameter->get_costs) {
3044  qCritical("jumbo callbacks for fuel maps are not yet implemented.");
3045  }
3046  return pf_fuel_map_new(parameter);
3047  }
3048 
3049  return pf_normal_map_new(parameter);
3050 }
3051 
3055 void pf_map_destroy(struct pf_map *pfm)
3056 {
3057 #ifdef PF_DEBUG
3058  fc_assert_ret(nullptr != pfm);
3059 #endif
3060  pfm->destroy(pfm);
3061 }
3062 
3068 int pf_map_move_cost(struct pf_map *pfm, struct tile *ptile)
3069 {
3070 #ifdef PF_DEBUG
3071  fc_assert_ret_val(nullptr != pfm, PF_IMPOSSIBLE_MC);
3072  fc_assert_ret_val(nullptr != ptile, PF_IMPOSSIBLE_MC);
3073 #endif
3074  return pfm->get_move_cost(pfm, ptile);
3075 }
3076 
3085 PFPath pf_map_path(struct pf_map *pfm, struct tile *ptile)
3086 {
3087 #ifdef PF_DEBUG
3088  PFPath path;
3089 
3090  fc_assert_ret_val(nullptr != pfm, path);
3091  fc_assert_ret_val(nullptr != ptile, path);
3092  path = pfm->get_path(pfm, ptile);
3093 
3094  if (!path.empty()) {
3095  const struct pf_parameter *param = pf_map_parameter(pfm);
3096  const struct pf_position pos = path[0];
3097 
3098  fc_assert(path.length() >= 1);
3099  fc_assert(pos.tile == param->start_tile);
3100  fc_assert(pos.moves_left == param->moves_left_initially);
3101  fc_assert(pos.fuel_left == param->fuel_left_initially);
3102  }
3103 
3104  return path;
3105 #else
3106  return pfm->get_path(pfm, ptile);
3107 #endif
3108 }
3109 
3115 bool pf_map_position(struct pf_map *pfm, struct tile *ptile,
3116  struct pf_position *pos)
3117 {
3118 #ifdef PF_DEBUG
3119  fc_assert_ret_val(nullptr != pfm, false);
3120  fc_assert_ret_val(nullptr != ptile, false);
3121 #endif
3122  return pfm->get_position(pfm, ptile, pos);
3123 }
3124 
3136 bool pf_map_iterate(struct pf_map *pfm)
3137 {
3138 #ifdef PF_DEBUG
3139  fc_assert_ret_val(nullptr != pfm, false);
3140 #endif
3141 
3142  if (nullptr == pfm->tile) {
3143  /* The end of the iteration was already reached. Don't try to iterate
3144  * again. */
3145  return false;
3146  }
3147 
3148  if (!pfm->iterate(pfm)) {
3149  // End of iteration.
3150  pfm->tile = nullptr;
3151  return false;
3152  }
3153 
3154  return true;
3155 }
3156 
3160 struct tile *pf_map_iter(struct pf_map *pfm)
3161 {
3162 #ifdef PF_DEBUG
3163  fc_assert_ret_val(nullptr != pfm, nullptr);
3164 #endif
3165  return pfm->tile;
3166 }
3167 
3173 {
3174 #ifdef PF_DEBUG
3175  fc_assert_ret_val(nullptr != pfm, PF_IMPOSSIBLE_MC);
3176  fc_assert_ret_val(nullptr != pfm->tile, PF_IMPOSSIBLE_MC);
3177 #endif
3178  return pfm->get_move_cost(pfm, pfm->tile);
3179 }
3180 
3186 {
3187 #ifdef PF_DEBUG
3188  fc_assert_ret_val(nullptr != pfm, PFPath());
3189  fc_assert_ret_val(nullptr != pfm->tile, PFPath());
3190 #endif
3191  return pfm->get_path(pfm, pfm->tile);
3192 }
3193 
3198 void pf_map_iter_position(struct pf_map *pfm, struct pf_position *pos)
3199 {
3200 #ifdef PF_DEBUG
3201  fc_assert_ret(nullptr != pfm);
3202  fc_assert_ret(nullptr != pfm->tile);
3203 #endif
3204  if (!pfm->get_position(pfm, pfm->tile, pos)) {
3205  // Always fails.
3206  fc_assert(pfm->get_position(pfm, pfm->tile, pos));
3207  }
3208 }
3209 
3213 const struct pf_parameter *pf_map_parameter(const struct pf_map *pfm)
3214 {
3215 #ifdef PF_DEBUG
3216  fc_assert_ret_val(nullptr != pfm, nullptr);
3217 #endif
3218  return &pfm->params;
3219 }
3220 
3221 // ====================== PFPath public functions =======================
3222 
3227  const struct pf_parameter *param)
3228 {
3229  pos->tile = param->start_tile;
3230  pos->turn = 0;
3231  pos->moves_left = param->moves_left_initially;
3232  pos->fuel_left = param->fuel_left_initially;
3233  pos->total_MC = 0;
3234  pos->total_EC = 0;
3235  pos->dir_to_next_pos = direction8_invalid();
3236  pos->dir_to_here = direction8_invalid();
3237 }
3238 
3242 // Constructor to just initialize with size
3243 PFPath::PFPath(int size) : positions(std::vector<pf_position>(size)) {}
3247 PFPath::PFPath(const struct pf_parameter *param)
3248  : positions(std::vector<pf_position>(1))
3249 {
3251 }
3252 
3253 // Destructor
3255 // Check if path is empty
3256 bool PFPath::empty() const { return positions.empty(); }
3257 // Return Length of path
3258 int PFPath::length() const { return positions.size(); }
3266 bool PFPath::advance(struct tile *ptile)
3267 {
3268  int i;
3269  int length = positions.size();
3270  for (i = 0; positions[i].tile != ptile; i++) {
3271  if (i >= length) {
3272  return false;
3273  }
3274  }
3275  fc_assert_ret_val(i < length, false);
3276  length -= i;
3277  std::vector<pf_position> new_positions(length);
3278  for (int j = 0; j < length; j++) {
3279  new_positions[j] = positions[i + j];
3280  }
3281  positions = new_positions;
3282  return true;
3283 }
3284 
3286 {
3287  if (i < 0) {
3288  fc_assert_msg((-i <= positions.size()), "id %d/%zu", i,
3289  positions.size());
3290  return positions[positions.size() + i];
3291  }
3292  fc_assert_msg((i < positions.size()), "id %d/%zu", i, positions.size());
3293  return positions[i];
3294 }
3295 
3296 const pf_position &PFPath::operator[](int i) const
3297 {
3298  if (i < 0) {
3299  fc_assert_msg((-i <= positions.size()), "id %d/%zu", i,
3300  positions.size());
3301  return positions[positions.size() + i];
3302  }
3303  fc_assert_msg((i < positions.size()), "id %d/%zu", i, positions.size());
3304  return positions[i];
3305 }
3306 
3310 QDebug &operator<<(QDebug &logger, const PFPath &path)
3311 {
3312  struct pf_position pos;
3313  int i;
3314 
3315  if (!path.empty()) {
3316  logger << QString::asprintf(
3317  "PF: path (at %p) consists of %d positions:\n", (void *) &path,
3318  path.length());
3319  } else {
3320  logger << "PF: path is empty";
3321  return logger;
3322  }
3323 
3324  for (i = 0; i < path.length(); i++) {
3325  pos = path[i];
3326  logger << QString::asprintf(
3327  "PF: %2d/%2d: (%2d,%2d) dir=%-2s cost=%2d (%2d, %d) EC=%d\n",
3328  i + 1, path.length(), TILE_XY(pos.tile),
3329  dir_get_name(pos.dir_to_next_pos), pos.total_MC, pos.turn,
3330  pos.moves_left, pos.total_EC);
3331  }
3332  return logger;
3333 }
3334 
3335 // ===================== pf_reverse_map functions ========================
3336 
3337 /* The path-finding reverse maps are used check the move costs that the
3338  * units needs to reach the start tile. It stores a pf_map for every unit
3339  * type. */
3340 
3341 static const enum unit_type_flag_id signifiant_flags[3] = {
3342  UTYF_IGTER, UTYF_CIVILIAN, UTYF_COAST_STRICT};
3343 
3344 inline bool operator==(const pf_parameter &e1, const pf_parameter &e2)
3345 {
3346  size_t i;
3347  static const size_t signifiant_flags_num = ARRAY_SIZE(signifiant_flags);
3348 
3349  if (e1.start_tile != e2.start_tile || e1.move_rate != e2.move_rate) {
3350  return false;
3351  }
3352 
3353  if (e1.utype == e2.utype) {
3354  // Short test.
3355  return true;
3356  }
3357 
3358  if (utype_class(e1.utype) != utype_class(e2.utype)) {
3359  return false;
3360  }
3361 
3362  if (!e1.omniscience) {
3363 #ifdef PF_DEBUG
3364  fc_assert(e2.omniscience == false);
3365 #endif
3367  return false;
3368  }
3369  }
3370 
3371  for (i = 0; i < signifiant_flags_num; i++) {
3373  != utype_has_flag(e2.utype, signifiant_flags[i])) {
3374  return false;
3375  }
3376  }
3377 
3378  return true;
3379 }
3380 
3381 // The reverse map structure.
3383  struct tile *target_tile; // Where we want to go.
3384  int max_turns; // The maximum of turns.
3385  struct pf_parameter template_params; // Keep a parameter ready for usage.
3386  QHash<const pf_parameter *, struct pf_position *>
3387  *hash; // A hash where pf_position are stored.
3388 };
3389 
3394 struct pf_reverse_map *pf_reverse_map_new(const struct player *pplayer,
3395  struct tile *target_tile,
3396  int max_turns, bool omniscient,
3397  const struct civ_map *map)
3398 {
3399  auto *pfrm = new pf_reverse_map;
3400  struct pf_parameter *param = &pfrm->template_params;
3401 
3402  pfrm->target_tile = target_tile;
3403  pfrm->max_turns = max_turns;
3404 
3405  // Initialize the parameter.
3406  pft_fill_reverse_parameter(param, target_tile);
3407  param->owner = pplayer;
3408  param->omniscience = omniscient;
3409  param->map = map;
3410 
3411  // Initialize the map hash.
3412  pfrm->hash = new QHash<const pf_parameter *, struct pf_position *>;
3413 
3414  return pfrm;
3415 }
3416 
3421 struct pf_reverse_map *
3422 pf_reverse_map_new_for_city(const struct city *pcity,
3423  const struct player *attacker, int max_turns,
3424  bool omniscient, const struct civ_map *map)
3425 {
3426  return pf_reverse_map_new(attacker, city_tile(pcity), max_turns,
3427  omniscient, map);
3428 }
3429 
3434 {
3435  fc_assert_ret(nullptr != pfrm);
3436  QHash<const pf_parameter *, pf_position *>::const_iterator it =
3437  pfrm->hash->constBegin();
3438  while (it != pfrm->hash->constEnd()) {
3439  delete it.key();
3440  delete it.value();
3441  ++it;
3442  }
3443  delete pfrm->hash;
3444  delete pfrm;
3445 }
3446 
3451 static const struct pf_position *
3453  const struct pf_parameter *param)
3454 {
3455  struct pf_position *pos;
3456  struct pf_map *pfm;
3457  struct pf_parameter *copy;
3458  struct tile *target_tile;
3459  const struct pf_normal_node *lattice;
3460  int max_cost;
3461 
3462  // Check if we already processed something similar.
3463  if (pfrm->hash->contains(param)) {
3464  pos = pfrm->hash->value(param);
3465  return pos;
3466  }
3467 
3468  // We didn't. Build map and iterate.
3469  pfm = pf_normal_map_new(param);
3470  lattice = PF_NORMAL_MAP(pfm)->lattice;
3471  target_tile = pfrm->target_tile;
3472  if (pfrm->max_turns >= 0) {
3473  max_cost = param->move_rate * (pfrm->max_turns + 1);
3474  do {
3475  if (lattice[tile_index(pfm->tile)].cost >= max_cost) {
3476  break;
3477  } else if (pfm->tile == target_tile) {
3478  // Found our position. Insert in hash, destroy map, and return.
3479  pos = new pf_position;
3480  pf_normal_map_fill_position(PF_NORMAL_MAP(pfm), target_tile, pos);
3481  copy = new pf_parameter;
3482  *copy = *param;
3483  pfrm->hash->insert(copy, pos);
3484  pf_map_destroy(pfm);
3485  return pos;
3486  }
3487  } while (pfm->iterate(pfm));
3488  } else {
3489  // No limit for iteration.
3490  do {
3491  if (pfm->tile == target_tile) {
3492  // Found our position. Insert in hash, destroy map, and return.
3493  pos = new pf_position;
3494  pf_normal_map_fill_position(PF_NORMAL_MAP(pfm), target_tile, pos);
3495  copy = new pf_parameter;
3496  *copy = *param;
3497  pfrm->hash->insert(copy, pos);
3498  pf_map_destroy(pfm);
3499  return pos;
3500  }
3501  } while (pfm->iterate(pfm));
3502  }
3503  pf_map_destroy(pfm);
3504 
3505  /* Position not found. Let's insert nullptr as position to avoid to iterate
3506  * the map again. */
3507  copy = new pf_parameter;
3508  *copy = *param;
3509  pfrm->hash->insert(copy, nullptr);
3510  return nullptr;
3511 }
3512 
3517 static inline const struct pf_position *
3519  const struct unit *punit)
3520 {
3521  struct pf_parameter *param = &pfrm->template_params;
3522 
3523  // Fill parameter.
3524  param->start_tile = unit_tile(punit);
3525  param->move_rate = unit_move_rate(punit);
3526  /* Do not consider punit->moves_left, because this value is usually
3527  * not restored when calling this function. Let's assume the unit will
3528  * have its whole move rate. */
3529  param->moves_left_initially = param->move_rate;
3530  param->utype = unit_type_get(punit);
3531  return pf_reverse_map_pos(pfrm, param);
3532 }
3533 
3539  const struct unit *punit)
3540 {
3541  const struct pf_position *pos = pf_reverse_map_unit_pos(pfrm, punit);
3542 
3543  return (pos != nullptr ? pos->total_MC : PF_IMPOSSIBLE_MC);
3544 }
3545 
3550  const struct unit *punit,
3551  struct pf_position *pos)
3552 {
3553  const struct pf_position *mypos = pf_reverse_map_unit_pos(pfrm, punit);
3554 
3555  if (mypos != nullptr) {
3556  *pos = *mypos;
3557  return true;
3558  } else {
3559  return false;
3560  }
3561 }
struct tile * city_tile(const struct city *pcity)
Return the tile location of the city.
Definition: city.cpp:1095
bool advance(struct tile *ptile)
Remove the part of a path leading up to a given tile.
bool empty() const
pf_position & operator[](int i)
std::vector< pf_position > positions
Definition: path_finding.h:313
virtual ~PFPath()
PFPath()=default
int length() const
#define DIR8_MAGIC_MAX
Definition: fc_types.h:386
#define fc_assert_msg(condition, message,...)
Definition: log.h:96
#define fc_assert_ret(condition)
Definition: log.h:112
#define fc_assert(condition)
Definition: log.h:89
#define fc_assert_ret_msg(condition, message,...)
Definition: log.h:129
#define fc_assert_ret_val(condition, val)
Definition: log.h:114
#define log_debug(message,...)
Definition: log.h:65
#define fc_assert_ret_val_msg(condition, val, message,...)
Definition: log.h:132
const char * dir_get_name(enum direction8 dir)
Return the debugging name of the direction.
Definition: map.cpp:1084
struct tile * index_to_tile(const struct civ_map *imap, int mindex)
Return the tile for the given index position.
Definition: map.cpp:429
struct tile * mapstep(const struct civ_map *nmap, const struct tile *ptile, enum direction8 dir)
Step from the given tile in the given direction.
Definition: map.cpp:342
#define adjc_dir_iterate(nmap, center_tile, itr_tile, dir_itr)
Definition: map.h:364
#define MAP_INDEX_SIZE
Definition: map.h:91
#define DIR_REVERSE(dir)
Definition: map.h:487
#define adjc_dir_iterate_end
Definition: map.h:368
int unit_move_rate(const struct unit *punit)
This function calculates the move rate of the unit.
Definition: movement.cpp:78
#define SINGLE_MOVE
Definition: movement.h:17
bool pf_reverse_map_unit_position(struct pf_reverse_map *pfrm, const struct unit *punit, struct pf_position *pos)
Fill the position.
static enum unit_type_flag_id signifiant_flags[3]
static void pf_danger_map_fill_position(const struct pf_danger_map *pfdm, struct tile *ptile, struct pf_position *pos)
Fill in the position which must be discovered already.
static struct pf_map * pf_fuel_map_new(const struct pf_parameter *parameter)
'pf_fuel_map' constructor.
static bool pf_fuel_map_iterate(struct pf_map *pfm)
Primary method for iterative path-finding for fuel units.
static struct pf_map * pf_danger_map_new(const struct pf_parameter *parameter)
'pf_danger_map' constructor.
#define PF_DANGER_MAP(pfm)
static bool pf_normal_node_init(struct pf_normal_map *pfnm, struct pf_normal_node *node, struct tile *ptile, enum pf_move_scope previous_scope)
Calculates cached values of the target node.
static PFPath pf_danger_map_construct_path(const struct pf_danger_map *pfdm, struct tile *ptile)
Read off the path to the node 'ptile', but with dangers.
static struct pf_fuel_pos * pf_fuel_pos_ref(struct pf_fuel_pos *pos)
Forget how we went to position.
static bool pf_danger_node_init(struct pf_danger_map *pfdm, struct pf_danger_node *node, struct tile *ptile, enum pf_move_scope previous_scope)
Calculates cached values of the target node.
static void pf_fuel_finalize_position_base(const struct pf_parameter *param, struct pf_position *pos, int cost, int moves_left)
Finalize the fuel position.
static int pf_normal_map_move_cost(struct pf_map *pfm, struct tile *ptile)
Return the move cost at ptile.
static int pf_fuel_map_fill_cost_for_full_moves(const struct pf_parameter *param, int cost, int moves_left)
This function returns the fill cost needed for a position, to get full moves at the next turn.
const struct pf_parameter * pf_map_parameter(const struct pf_map *pfm)
Return the pf_parameter for given pf_map.
pf_map * PF_MAP(void *x)
Casts to pf_map
static bool pf_fuel_map_position(struct pf_map *pfm, struct tile *ptile, struct pf_position *pos)
Get info about position at ptile and put it in pos.
static void pf_fuel_map_fill_position(const struct pf_fuel_map *pffm, struct tile *ptile, struct pf_position *pos)
Fill in the position which must be discovered already.
bool operator==(const pf_parameter &e1, const pf_parameter &e2)
bool pf_map_iterate(struct pf_map *pfm)
Iterates the path-finding algorithm one step further, to the next nearest position.
static void pf_fuel_map_create_segment(struct pf_fuel_map *pffm, struct tile *ptile, struct pf_fuel_node *node)
Creating path segment going back from node1 to a safe tile.
bool pf_map_position(struct pf_map *pfm, struct tile *ptile, struct pf_position *pos)
Get info about position at ptile and put it in pos.
static int pf_move_rate(const struct pf_parameter *param)
Return the "move rate".
void pf_map_iter_position(struct pf_map *pfm, struct pf_position *pos)
Read all info about the current position into pos.
struct pf_map * pf_map_new(const struct pf_parameter *parameter)
Factory function to create a new map according to the parameter.
static PFPath pf_danger_map_path(struct pf_map *pfm, struct tile *ptile)
Return the path to ptile.
int pf_map_iter_move_cost(struct pf_map *pfm)
Return the move cost at the current position.
static struct pf_map * pf_normal_map_new(const struct pf_parameter *parameter)
'pf_normal_map' constructor.
static bool pf_jumbo_map_iterate(struct pf_map *pfm)
Bare-bones PF iterator.
static PFPath pf_normal_map_path(struct pf_map *pfm, struct tile *ptile)
Return the path to ptile.
QDebug & operator<<(QDebug &logger, const PFPath &path)
Debug a path.
static int pf_normal_map_adjust_cost(int cost, int moves_left)
Adjust MC to reflect the move_rate.
static bool pf_normal_map_iterate_until(struct pf_normal_map *pfnm, struct tile *ptile)
Iterate the map until 'ptile' is reached.
static bool pf_fuel_node_init(struct pf_fuel_map *pffm, struct pf_fuel_node *node, struct tile *ptile, enum pf_move_scope previous_scope)
Calculates cached values of the target node.
struct pf_reverse_map * pf_reverse_map_new_for_city(const struct city *pcity, const struct player *attacker, int max_turns, bool omniscient, const struct civ_map *map)
'pf_reverse_map' constructor for city.
pf_zoc_type
@ ZOC_MINE
@ ZOC_ALLIED
@ ZOC_NO
static bool pf_danger_map_position(struct pf_map *pfm, struct tile *ptile, struct pf_position *pos)
Get info about position at ptile and put it in pos .
static PFPath pf_fuel_map_path(struct pf_map *pfm, struct tile *ptile)
Return the path to ptile.
struct pf_reverse_map * pf_reverse_map_new(const struct player *pplayer, struct tile *target_tile, int max_turns, bool omniscient, const struct civ_map *map)
'pf_reverse_map' constructor.
PFPath pf_map_path(struct pf_map *pfm, struct tile *ptile)
CHECK DOCS AFTER FULL CONVERSTION OF pf_path to class PFPath Tries to find the best path in the given...
static const struct pf_position * pf_reverse_map_unit_pos(struct pf_reverse_map *pfrm, const struct unit *punit)
Returns the position for the unit.
static struct pf_fuel_pos * pf_fuel_pos_replace(struct pf_fuel_pos *pos, const struct pf_fuel_node *node)
Replace the position (unreferences it).
static int pf_moves_left_initially(const struct pf_parameter *param)
Return the number of "moves" started with.
static const struct pf_position * pf_reverse_map_pos(struct pf_reverse_map *pfrm, const struct pf_parameter *param)
Returns the map for the unit type.
static int pf_danger_map_move_cost(struct pf_map *pfm, struct tile *ptile)
Return the move cost at ptile.
static bool pf_fuel_map_attack_is_possible(const struct pf_parameter *param, int moves_left, int moves_left_req)
This function returns whether a unit with or without fuel can attack.
static void pf_finalize_position(const struct pf_parameter *param, struct pf_position *pos)
Take a position previously filled out (as by fill_position) and "finalize" it by reversing all fuel m...
void pf_reverse_map_destroy(struct pf_reverse_map *pfrm)
'pf_reverse_map' destructor.
static 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)
Finalize the fuel position.
static void pf_normal_map_fill_position(const struct pf_normal_map *pfnm, struct tile *ptile, struct pf_position *pos)
Fill in the position which must be discovered already.
#define PF_FUEL_MAP(pfm)
static int pf_fuel_map_adjust_cost(int cost, int moves_left, int move_rate)
Adjust cost for move_rate and fuel usage.
static bool pf_danger_map_iterate(struct pf_map *pfm)
Primary method for iterative path-finding in presence of danger Notes:
static int pf_fuel_map_move_cost(struct pf_map *pfm, struct tile *ptile)
Return the move cost at ptile.
static void pf_position_fill_start_tile(struct pf_position *pos, const struct pf_parameter *param)
Fill the position for the start tile of a parameter.
static void pf_fuel_pos_unref(struct pf_fuel_pos *pos)
Forget how we went to position.
int pf_reverse_map_unit_move_cost(struct pf_reverse_map *pfrm, const struct unit *punit)
Get the move costs that a unit needs to reach the start tile.
static bool pf_normal_map_position(struct pf_map *pfm, struct tile *ptile, struct pf_position *pos)
Get info about position at ptile and put it in pos.
static bool pf_fuel_node_dangerous(const struct pf_fuel_node *node)
Returns whether this node is dangerous or not.
static void pf_danger_map_destroy(struct pf_map *pfm)
'pf_danger_map' destructor.
pf_node_status
@ NS_INIT
@ NS_UNINIT
@ NS_PROCESSED
@ NS_WAITING
@ NS_NEW
static bool pf_normal_map_iterate(struct pf_map *pfm)
Primary method for iterative path-finding.
static PFPath pf_fuel_map_construct_path(const struct pf_fuel_map *pffm, struct tile *ptile)
Read off the path to the node 'ptile', but with fuel danger.
void pf_map_destroy(struct pf_map *pfm)
After usage the map must be destroyed.
static int pf_moves_left(const struct pf_parameter *param, int cost)
Moves left after node is reached.
static int pf_danger_map_adjust_cost(const struct pf_parameter *params, int cost, bool to_danger, int moves_left)
Adjust cost taking into account possibility of making the move.
static bool pf_fuel_map_iterate_until(struct pf_fuel_map *pffm, struct tile *ptile)
Iterate the map until 'ptile' is reached.
struct tile * pf_map_iter(struct pf_map *pfm)
Return the current tile.
static void pf_normal_map_destroy(struct pf_map *pfm)
'pf_normal_map' destructor.
int pf_map_move_cost(struct pf_map *pfm, struct tile *ptile)
Tries to find the minimal move cost to reach ptile.
static int pf_fuel_total_CC(const struct pf_parameter *param, int cost, int extra, int safety)
Obtain cost-of-path from pure cost, extra cost and safety.
static void pf_fuel_map_destroy(struct pf_map *pfm)
'pf_fuel_map' destructor.
PFPath pf_map_iter_path(struct pf_map *pfm)
Return the path to our current position.This is equivalent to pf_map_path(pfm, pf_map_iter(pfm)).
static bool pf_danger_map_iterate_until(struct pf_danger_map *pfdm, struct tile *ptile)
Iterate the map until 'ptile' is reached.
#define INITIAL_QUEUE_SIZE
static int pf_danger_map_fill_cost_for_full_moves(const struct pf_parameter *param, int cost)
This function returns the fills the cost needed for a position, to get full moves at the next turn.
#define PF_NORMAL_MAP(pfm)
static int pf_turns(const struct pf_parameter *param, int cost)
Number of turns required to reach node.
static int pf_total_CC(const struct pf_parameter *param, int cost, int extra)
Obtain cost-of-path from pure cost and extra cost.
static PFPath pf_normal_map_construct_path(const struct pf_normal_map *pfnm, struct tile *dest_tile)
Read off the path to the node dest_tile, which must already be discovered.
static int pf_fuel_waited_total_CC(int cost, int safety)
Obtain cost-of-path for constant extra cost (used for node after waited).
static void pf_danger_map_create_segment(struct pf_danger_map *pfdm, struct pf_danger_node *node1)
Creating path segment going back from node1 to a safe tile.
#define PF_IMPOSSIBLE_MC
Definition: path_finding.h:244
pf_action
Definition: path_finding.h:255
@ PF_ACTION_ATTACK
Definition: path_finding.h:257
@ PF_ACTION_IMPOSSIBLE
Definition: path_finding.h:260
@ PF_ACTION_NONE
Definition: path_finding.h:256
pf_move_scope
Definition: path_finding.h:287
@ PF_MS_TRANSPORT
Definition: path_finding.h:291
@ PF_MS_NATIVE
Definition: path_finding.h:289
@ PF_MS_NONE
Definition: path_finding.h:288
#define PF_TURN_FACTOR
Definition: path_finding.h:250
@ TB_NORMAL
Definition: path_finding.h:277
@ TB_DONT_LEAVE
Definition: path_finding.h:279
@ TB_IGNORE
Definition: path_finding.h:278
void pft_fill_reverse_parameter(struct pf_parameter *parameter, struct tile *target_tile)
Fill default parameters for reverse map.
Definition: pf_tools.cpp:923
bool player_can_invade_tile(const struct player *pplayer, const struct tile *ptile)
Return TRUE iff the player can invade a particular tile (linked with borders and diplomatic states).
Definition: player.cpp:236
#define ARRAY_SIZE(x)
Definition: shared.h:79
#define MIN(x, y)
Definition: shared.h:49
#define FC_INFINITY
Definition: shared.h:32
SPECPQ_PRIORITY_TYPE priority
Definition: specpq.h:76
size_t size
Definition: specvec.h:64
Definition: city.h:291
struct map_index_pq * danger_queue
struct pf_danger_node * lattice
struct map_index_pq * queue
struct pf_map base_map
struct pf_danger_node::pf_danger_pos * danger_segment
unsigned node_known_type
unsigned move_scope
unsigned zoc_number
unsigned short extra_tile
unsigned extra_cost
unsigned dir_to_here
signed short cost
struct map_index_pq * waited_queue
struct pf_map base_map
struct map_index_pq * queue
struct pf_fuel_node * lattice
struct pf_fuel_pos * segment
unsigned zoc_number
unsigned extra_cost
unsigned behavior
unsigned node_known_type
unsigned short cost_to_here[DIR8_MAGIC_MAX]
unsigned move_scope
struct pf_fuel_pos * pos
unsigned moves_left
unsigned dir_to_here
unsigned short extra_tile
signed moves_left_req
signed short cost
signed short cost
unsigned dir_to_here
unsigned extra_cost
struct pf_fuel_pos * prev
unsigned moves_left
unsigned ref_count
bool(* get_position)(struct pf_map *pfm, struct tile *ptile, struct pf_position *pos)
int(* get_move_cost)(struct pf_map *pfm, struct tile *ptile)
struct tile * tile
PFPath(* get_path)(struct pf_map *pfm, struct tile *ptile)
bool(* iterate)(struct pf_map *pfm)
void(* destroy)(struct pf_map *pfm)
struct pf_parameter params
struct pf_map base_map
struct pf_normal_node * lattice
struct map_index_pq * queue
unsigned dir_to_here
unsigned zoc_number
unsigned extra_cost
unsigned short extra_tile
unsigned node_known_type
unsigned move_scope
signed short cost
int fuel_left_initially
Definition: path_finding.h:344
const struct unit_type * transported_by_initially
Definition: path_finding.h:346
enum pf_action(* get_action)(const struct tile *ptile, enum known_type known, const struct pf_parameter *param)
Definition: path_finding.h:392
enum pf_move_scope(* get_move_scope)(const struct tile *ptile, bool *can_disembark, enum pf_move_scope previous_scope, const struct pf_parameter *param)
Definition: path_finding.h:371
bool ignore_none_scopes
Definition: path_finding.h:375
const struct civ_map * map
Definition: path_finding.h:340
enum tile_behavior(* get_TB)(const struct tile *ptile, enum known_type known, const struct pf_parameter *param)
Definition: path_finding.h:380
int(* get_EC)(const struct tile *ptile, enum known_type known, const struct pf_parameter *param)
Definition: path_finding.h:387
const struct player * owner
Definition: path_finding.h:356
bool(* is_pos_dangerous)(const struct tile *ptile, enum known_type, const struct pf_parameter *param)
Definition: path_finding.h:418
int(* get_moves_left_req)(const struct tile *ptile, enum known_type, const struct pf_parameter *param)
Definition: path_finding.h:423
int moves_left_initially
Definition: path_finding.h:343
bool(* get_zoc)(const struct player *pplayer, const struct tile *ptile, const struct civ_map *zmap)
Definition: path_finding.h:412
int(* get_MC)(const struct tile *from_tile, enum pf_move_scope src_move_scope, const struct tile *to_tile, enum pf_move_scope dst_move_scope, const struct pf_parameter *param)
Definition: path_finding.h:364
int(* get_costs)(const struct tile *from_tile, enum direction8 dir, const struct tile *to_tile, int from_cost, int from_extra, int *to_cost, int *to_extra, const struct pf_parameter *param)
Definition: path_finding.h:445
const struct unit_type * utype
Definition: path_finding.h:355
bool(* is_action_possible)(const struct tile *from_tile, enum pf_move_scope src_move_scope, const struct tile *to_tile, enum pf_action action, const struct pf_parameter *param)
Definition: path_finding.h:399
struct tile * start_tile
Definition: path_finding.h:341
enum direction8 dir_to_here
Definition: path_finding.h:308
enum direction8 dir_to_next_pos
Definition: path_finding.h:307
struct tile * tile
Definition: path_finding.h:296
struct pf_parameter template_params
struct tile * target_tile
QHash< const pf_parameter *, struct pf_position * > * hash
Definition: player.h:231
Definition: tile.h:42
struct unit_list * units
Definition: tile.h:50
int unknown_move_cost
Definition: unittype.h:482
Definition: unit.h:134
#define terrain_has_flag(terr, flag)
Definition: terrain.h:260
bool tile_has_native_base(const struct tile *ptile, const struct unit_type *punittype)
Check if tile contains base native for unit.
Definition: tile.cpp:327
enum known_type tile_get_known(const struct tile *ptile, const struct player *pplayer)
Return a known_type enumeration value for the tile.
Definition: tile.cpp:398
struct city * tile_city(const struct tile *ptile)
Return the city on this tile (or nullptr), checking for city center.
Definition: tile.cpp:72
#define tile_index(_pt_)
Definition: tile.h:70
known_type
Definition: tile.h:28
@ TILE_UNKNOWN
Definition: tile.h:29
@ TILE_KNOWN_SEEN
Definition: tile.h:31
#define tile_terrain(_tile)
Definition: tile.h:93
#define TILE_XY(ptile)
Definition: tile.h:36
#define unit_tile(_pu)
Definition: unit.h:371
const struct unit_type * unit_type_get(const struct unit *punit)
Return the unit type for this unit.
Definition: unittype.cpp:114
bool utype_can_freely_unload(const struct unit_type *pcargotype, const struct unit_type *ptranstype)
Return TRUE iff the given cargo type has no restrictions on when it can unload from the given transpo...
Definition: unittype.cpp:239
bool utype_can_do_action(const struct unit_type *putype, const action_id act_id)
Return TRUE iff units of the given type can do the specified generalized (ruleset defined) action ena...
Definition: unittype.cpp:386
#define utype_class(_t_)
Definition: unittype.h:691
static bool utype_has_flag(const struct unit_type *punittype, int flag)
Definition: unittype.h:584