The Battle for Wesnoth  1.13.4+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
pathfind.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003 by David White <[email protected]>
3  Copyright (C) 2005 - 2016 by Guillaume Melquiond <[email protected]>
4  Part of the Battle for Wesnoth Project http://www.wesnoth.org/
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY.
12 
13  See the COPYING file for more details.
14 */
15 
16 /**
17  * @file
18  * Various pathfinding functions and utilities.
19  */
20 
21 #include "global.hpp"
22 
23 #include "pathfind/pathfind.hpp"
24 #include "pathfind/teleport.hpp"
25 
26 #include "game_board.hpp"
27 #include "game_display.hpp"
28 #include "gettext.hpp"
29 #include "log.hpp"
30 #include "map/map.hpp"
31 #include "resources.hpp"
32 #include "team.hpp"
33 #include "units/unit.hpp"
34 #include "units/map.hpp"
35 #include "wml_exception.hpp"
36 
37 #include <iostream>
38 #include <vector>
39 #include <algorithm>
40 
41 static lg::log_domain log_engine("engine");
42 #define ERR_PF LOG_STREAM(err, log_engine)
43 
44 namespace pathfind {
45 
46 
47 /**
48  * Function that will find a location on the board that is as near
49  * to @a loc as possible, but which is unoccupied by any units.
50  * If no valid location can be found, it will return a null location.
51  * If @a pass_check is provided, the found location must have a terrain
52  * that this unit can enter.
53  * If @a shroud_check is provided, only locations not covered by this
54  * team's shroud will be considered.
55  */
57  const unit* pass_check, const team* shroud_check, const game_board* board)
58 {
59  if (!board) {
60  board = resources::gameboard;
61  assert(board);
62  }
63  const gamemap & map = board->map();
64  const unit_map & units = board->units();
65 
66  if (!map.on_board(loc)) return map_location();
67 
68  const bool do_shroud = shroud_check && shroud_check->uses_shroud();
69  std::set<map_location> pending_tiles_to_check, tiles_checked;
70  pending_tiles_to_check.insert(loc);
71  // Iterate out 50 hexes from loc
72  for (int distance = 0; distance < 50; ++distance) {
73  if (pending_tiles_to_check.empty())
74  return map_location();
75  //Copy over the hexes to check and clear the old set
76  std::set<map_location> tiles_checking;
77  tiles_checking.swap(pending_tiles_to_check);
78  //Iterate over all the hexes we need to check
79  for (const map_location &loc : tiles_checking)
80  {
81  // Skip shrouded locations.
82  if ( do_shroud && shroud_check->shrouded(loc) )
83  continue;
84  //If this area is not a castle but should, skip it.
85  if ( vacancy == VACANT_CASTLE && !map.is_castle(loc) ) continue;
86  const bool pass_check_and_unreachable = pass_check
87  && pass_check->movement_cost(map[loc]) == movetype::UNREACHABLE;
88  //If the unit can't reach the tile and we have searched
89  //an area of at least radius 10 (arbitrary), skip the tile.
90  //Neccessary for cases such as an unreachable
91  //starting hex surrounded by 6 other unreachable hexes, in which case
92  //the algorithm would not even search distance==1
93  //even if there's a reachable hex for distance==2.
94  if (pass_check_and_unreachable && distance > 10) continue;
95  //If the hex is empty and we do either no pass check or the hex is reachable, return it.
96  if (units.find(loc) == units.end() && !pass_check_and_unreachable) return loc;
97  map_location adjs[6];
98  get_adjacent_tiles(loc,adjs);
99  for (const map_location &loc : adjs)
100  {
101  if (!map.on_board(loc)) continue;
102  // Add the tile to be checked if it hasn't already been and
103  // isn't being checked.
104  if (tiles_checked.find(loc) == tiles_checked.end() &&
105  tiles_checking.find(loc) == tiles_checking.end())
106  {
107  pending_tiles_to_check.insert(loc);
108  }
109  }
110  }
111  tiles_checked.swap(tiles_checking);
112  }
113  return map_location();
114 }
115 
116 /**
117  * Wrapper for find_vacant_tile() when looking for a vacant castle tile
118  * near a leader.
119  * If no valid location can be found, it will return a null location.
120  */
122 {
124  nullptr, &(*resources::teams)[leader.side()-1]);
125 }
126 
127 
128 /**
129  * Determines if a given location is in an enemy zone of control.
130  *
131  * @param current_team The moving team (only ZoC of enemies of this team are considered).
132  * @param loc The location to check.
133  * @param viewing_team Only units visible to this team are considered.
134  * @param see_all If true, all units are considered (and viewing_team is ignored).
135  *
136  * @return true iff a visible enemy exerts zone of control over loc.
137  */
138 bool enemy_zoc(team const &current_team, map_location const &loc,
139  team const &viewing_team, bool see_all)
140 {
141  // Check the adjacent tiles.
142  map_location locs[6];
143  get_adjacent_tiles(loc,locs);
144  for (int i = 0; i != 6; ++i)
145  {
146  const unit *u = resources::gameboard->get_visible_unit(locs[i], viewing_team, see_all);
147  if ( u && current_team.is_enemy(u->side()) && u->emits_zoc() )
148  return true;
149  }
150 
151  // No adjacent tiles had an enemy exerting ZoC over loc.
152  return false;
153 }
154 
155 
156 namespace {
157  /**
158  * Nodes used by find_routes().
159  * These store the information necessary for extending the path
160  * and for tracing the route back to the source.
161  */
162  struct findroute_node {
165  // search_num is used to detect which nodes have been collected
166  // in the current search. (More than just a boolean value so
167  // that nodes can be stored between searches.)
168  unsigned search_num;
169 
170  // Constructors.
171  findroute_node(int moves, int turns, const map_location &prev_loc, unsigned search_count)
172  : moves_left(moves)
173  , turns_left(turns)
174  , prev(prev_loc)
175  , search_num(search_count)
176  { }
177  findroute_node()
178  : moves_left(0)
179  , turns_left(0)
180  , prev()
181  , search_num(0)
182  { }
183 
184  // Compare these nodes based on movement consumed.
185  bool operator<(const findroute_node& o) const {
186  return turns_left > o.turns_left ||
187  (turns_left == o.turns_left && moves_left > o.moves_left);
188  }
189  };
190 
191  /**
192  * Converts map locations to and from integer indices.
193  */
194  struct findroute_indexer {
195  int w, h; // Width and height of the map.
196 
197  // Constructor:
198  findroute_indexer(int a, int b) : w(a), h(b) { }
199  // Convert to an index: (returns -1 on out of bounds)
200  int operator()(int x, int y) const {
201  if ( x < 0 || w <= x || y < 0 || h <= y )
202  return -1;
203  else
204  return x + y*w;
205  }
206  int operator()(const map_location& loc) const {
207  return (*this)(loc.x, loc.y);
208  }
209  // Convert from an index:
210  map_location operator()(int index) const {
211  return map_location(index%w, index/w);
212  }
213  };
214 
215  /**
216  * A function object for comparing indices.
217  */
218  struct findroute_comp {
219  const std::vector<findroute_node>& nodes;
220 
221  // Constructor:
222  findroute_comp(const std::vector<findroute_node>& n) : nodes(n) { }
223  // Binary predicate evaluating the order of its arguments:
224  bool operator()(int l, int r) const {
225  return nodes[r] < nodes[l];
226  }
227  };
228 }
229 
230 /**
231  * Creates a list of routes that a unit can traverse from the provided location.
232  * (This is called when creating pathfind::paths and descendant classes.)
233  *
234  * @param[in] origin The location at which to begin the routes.
235  * @param[in] costs The costs to use for route finding.
236  * @param[in] slowed Whether or not to use the slowed costs.
237  * @param[in] moves_left The number of movement points left for the current turn.
238  * @param[in] max_moves The number of movement points in each future turn.
239  * @param[in] turns_left The number of future turns of movement to calculate.
240  * @param[out] destinations The traversable routes.
241  * @param[out] edges The hexes (possibly off-map) adjacent to those in
242  * destinations. (It is permissible for this to contain
243  * some hexes that are also in destinations.)
244  *
245  * @param[in] teleporter If not nullptr, teleportaion will be considered, using
246  * this unit's abilities.
247  * @param[in] current_team If not nullptr, enemies of this team can obstruct routes
248  * both by occupying hexes and by exerting zones of control.
249  * In addition, the presence of units can affect
250  * teleportation options.
251  * @param[in] skirmisher If not nullptr, use this to determine where ZoC can and
252  * cannot be ignored (due to this unit having or not
253  * having the skirmisher ability).
254  * If nullptr, then ignore all zones of control.
255  * (No effect if current_team is nullptr).
256  * @param[in] viewing_team If not nullptr, use this team's vision when detecting
257  * enemy units and teleport destinations.
258  * If nullptr, then "see all".
259  * (No effect if teleporter and current_team are both nullptr.)
260  * @param[in] jamming_map The relevant "jamming" of the costs being used
261  * (currently only used with vision costs).
262  * @param[out] full_cost_map If not nullptr, build a cost_map instead of destinations.
263  * Destinations is ignored.
264  * full_cost_map is a vector of pairs. The first entry is the
265  * cost itself, the second how many units already visited this hex
266  */
267 static void find_routes(
268  const map_location & origin, const movetype::terrain_costs & costs,
269  bool slowed, int moves_left, int max_moves, int turns_left,
270  paths::dest_vect & destinations, std::set<map_location> * edges,
271  const unit * teleporter, const team * current_team,
272  const unit * skirmisher, const team * viewing_team,
273  const std::map<map_location, int> * jamming_map=nullptr,
274  std::vector<std::pair<int, int> > * full_cost_map=nullptr)
275 {
276  const gamemap& map = resources::gameboard->map();
277 
278  const bool see_all = viewing_team == nullptr;
279  // When see_all is true, the viewing team never matters, but we still
280  // need to supply one to some functions.
281  if ( viewing_team == nullptr )
282  viewing_team = &resources::teams->front();
283 
284  // Build a teleport map, if needed.
285  const teleport_map teleports = teleporter ?
286  get_teleport_locations(*teleporter, *viewing_team, see_all, current_team == nullptr) :
287  teleport_map();
288 
289  // Since this is called so often, keep memory reserved for the node list.
290  static std::vector<findroute_node> nodes;
291  static unsigned search_counter = 0;
292  // Incrementing search_counter means we ignore results from earlier searches.
293  ++search_counter;
294  // Whenever the counter cycles, trash the contents of nodes and restart at 1.
295  if ( search_counter == 0 ) {
296  nodes.resize(0);
297  search_counter = 1;
298  }
299  // Initialize the nodes for this search.
300  nodes.resize(map.w() * map.h());
301  findroute_comp node_comp(nodes);
302  findroute_indexer index(map.w(), map.h());
303 
304  // Check if full_cost_map has the correct size.
305  // If not, ignore it. If yes, initialize the start position.
306  if ( full_cost_map ) {
307  if ( full_cost_map->size() != static_cast<unsigned>(map.w() * map.h()) )
308  full_cost_map = nullptr;
309  else {
310  if ( (*full_cost_map)[index(origin)].second == 0 )
311  (*full_cost_map)[index(origin)].first = 0;
312  (*full_cost_map)[index(origin)].second += 1;
313  }
314  }
315 
316  // Used to optimize the final collection of routes.
317  int xmin = origin.x, xmax = origin.x, ymin = origin.y, ymax = origin.y;
318  int nb_dest = 1;
319 
320  // Record the starting location.
321  assert(index(origin) >= 0);
322  nodes[index(origin)] = findroute_node(moves_left, turns_left,
324  search_counter);
325  // Begin the search at the starting location.
326  std::vector<int> hexes_to_process(1, index(origin)); // Will be maintained as a heap.
327 
328  while ( !hexes_to_process.empty() ) {
329  // Process the hex closest to the origin.
330  const int cur_index = hexes_to_process.front();
331  const map_location cur_hex = index(cur_index);
332  const findroute_node& current = nodes[cur_index];
333  // Remove from the heap.
334  std::pop_heap(hexes_to_process.begin(), hexes_to_process.end(), node_comp);
335  hexes_to_process.pop_back();
336 
337  // Get the locations adjacent to current.
338  std::vector<map_location> adj_locs(6);
339  get_adjacent_tiles(cur_hex, &adj_locs[0]);
340  if ( teleporter ) {
341  std::set<map_location> allowed_teleports;
342  teleports.get_adjacents(allowed_teleports, cur_hex);
343  adj_locs.insert(adj_locs.end(), allowed_teleports.begin(), allowed_teleports.end());
344  }
345  for ( int i = adj_locs.size()-1; i >= 0; --i ) {
346  // Get the node associated with this location.
347  const map_location & next_hex = adj_locs[i];
348  const int next_index = index(next_hex);
349  if ( next_index < 0 ) {
350  // Off the map.
351  if ( edges != nullptr )
352  edges->insert(next_hex);
353  continue;
354  }
355  findroute_node & next = nodes[next_index];
356 
357  // Skip nodes we have already collected.
358  // (Since no previously checked routes were longer than
359  // the current one, the current route cannot be shorter.)
360  // (Significant difference from classic Dijkstra: we have
361  // vertex weights, not edge weights.)
362  if ( next.search_num == search_counter )
363  continue;
364 
365  // If we go to next, it will be from current.
366  next.prev = cur_hex;
367 
368  // Calculate the cost of entering next_hex.
369  int cost = costs.cost(map[next_hex], slowed);
370  if ( jamming_map ) {
371  const std::map<map_location, int>::const_iterator jam_it =
372  jamming_map->find(next_hex);
373  if ( jam_it != jamming_map->end() )
374  cost += jam_it->second;
375  }
376 
377  // Calculate movement remaining after entering next_hex.
378  next.moves_left = current.moves_left - cost;
379  next.turns_left = current.turns_left;
380  if ( next.moves_left < 0 ) {
381  // Have to delay until the next turn.
382  next.turns_left--;
383  next.moves_left = max_moves - cost;
384  }
385  if ( next.moves_left < 0 || next.turns_left < 0 ) {
386  // Either can never enter this hex or out of turns.
387  if ( edges != nullptr )
388  edges->insert(next_hex);
389  continue;
390  }
391 
392  if ( current_team ) {
393  // Account for enemy units.
394  const unit *v = resources::gameboard->get_visible_unit(next_hex, *viewing_team, see_all);
395  if ( v && current_team->is_enemy(v->side()) ) {
396  // Cannot enter enemy hexes.
397  if ( edges != nullptr )
398  edges->insert(next_hex);
399  continue;
400  }
401 
402  if ( skirmisher && next.moves_left > 0 &&
403  enemy_zoc(*current_team, next_hex, *viewing_team, see_all) &&
404  !skirmisher->get_ability_bool("skirmisher", next_hex) ) {
405  next.moves_left = 0;
406  }
407  }
408 
409  // Update full_cost_map
410  if ( full_cost_map ) {
411  if ( (*full_cost_map)[next_index].second == 0 )
412  (*full_cost_map)[next_index].first = 0;
413  int summed_cost = (turns_left - next.turns_left + 1) * max_moves - next.moves_left;
414  (*full_cost_map)[next_index].first += summed_cost;
415  (*full_cost_map)[next_index].second += 1;
416  }
417 
418  // Mark next as being collected.
419  next.search_num = search_counter;
420 
421  // Add this node to the heap.
422  hexes_to_process.push_back(next_index);
423  std::push_heap(hexes_to_process.begin(), hexes_to_process.end(), node_comp);
424 
425  // Bookkeeping (for later).
426  ++nb_dest;
427  if ( next_hex.x < xmin )
428  xmin = next_hex.x;
429  else if ( xmax < next_hex.x )
430  xmax = next_hex.x;
431  if ( next_hex.y < ymin )
432  ymin = next_hex.y;
433  else if ( ymax < next_hex.y )
434  ymax = next_hex.y;
435  }//for (i)
436  }//while (hexes_to_process)
437 
438  // Currently the only caller who uses full_cost_map doesn't need the
439  // destinations. We can skip this part.
440  if ( full_cost_map ) {
441  return;
442  }
443 
444  // Build the routes for every map_location that we reached.
445  // The ordering must be compatible with map_location::operator<.
446  destinations.reserve(nb_dest);
447  for (int x = xmin; x <= xmax; ++x) {
448  for (int y = ymin; y <= ymax; ++y)
449  {
450  const findroute_node &n = nodes[index(x,y)];
451  if ( n.search_num == search_counter ) {
452  paths::step s =
453  { map_location(x,y), n.prev, n.moves_left + n.turns_left*max_moves };
454  destinations.push_back(s);
455  }
456  }
457  }
458 }
459 
460 
462 {
463  size_t sz = v.size(), pos = 0;
464  while (sz)
465  {
466  if (v[pos + sz / 2].curr < loc) {
467  pos = pos + sz / 2 + 1;
468  sz = sz - sz / 2 - 1;
469  } else sz = sz / 2;
470  }
471  return v.begin() + pos;
472 }
473 
474 paths::dest_vect::const_iterator paths::dest_vect::find(const map_location &loc) const
475 {
476  const_iterator i = lower_bound(const_cast<dest_vect &>(*this), loc), i_end = end();
477  if (i != i_end && i->curr != loc) i = i_end;
478  return i;
479 }
480 
482 {
483  iterator i = lower_bound(*this, loc), i_end = end();
484  if (i != i_end && i->curr == loc) return;
485  paths::step s = { loc, map_location(), 0 };
487 }
488 
489 /**
490  * Returns the path going from the source point (included) to the
491  * destination point @a j (excluded).
492  */
493 std::vector<map_location> paths::dest_vect::get_path(const const_iterator &j) const
494 {
495  std::vector<map_location> path;
496  if (!j->prev.valid()) {
497  path.push_back(j->curr);
498  } else {
499  const_iterator i = j;
500  do {
501  i = find(i->prev);
502  assert(i != end());
503  path.push_back(i->curr);
504  } while (i->prev.valid());
505  }
506  std::reverse(path.begin(), path.end());
507  return path;
508 }
509 
511 {
512  return find(loc) != end();
513 }
514 
515 /**
516  * Construct a list of paths for the specified unit.
517  *
518  * This function is used for several purposes, including showing a unit's
519  * potential moves and generating currently possible paths.
520  * @param u The unit whose moves and movement type will be used.
521  * @param force_ignore_zoc Set to true to completely ignore zones of control.
522  * @param allow_teleport Set to true to consider teleportation abilities.
523  * @param viewing_team Usually the current team, except for "show enemy moves", etc.
524  * @param additional_turns The number of turns to account for, in addition to the current.
525  * @param see_all Set to true to remove unit visibility from consideration.
526  * @param ignore_units Set to true if units should never obstruct paths (implies ignoring ZoC as well).
527  */
528 paths::paths(const unit& u, bool force_ignore_zoc,
529  bool allow_teleport, const team &viewing_team,
530  int additional_turns, bool see_all, bool ignore_units)
531  : destinations()
532 {
533  std::vector<team> const &teams = *resources::teams;
534  if (u.side() < 1 || u.side() > int(teams.size())) {
535  return;
536  }
537 
540  u.total_movement(), additional_turns, destinations, nullptr,
541  allow_teleport ? &u : nullptr,
542  ignore_units ? nullptr : &teams[u.side()-1],
543  force_ignore_zoc ? nullptr : &u,
544  see_all ? nullptr : &viewing_team);
545 }
546 
547 /**
548  * Virtual destructor to support child classes.
549  */
551 {
552 }
553 
554 /**
555  * Constructs a list of vision paths for a unit.
556  *
557  * This is used to construct a list of hexes that the indicated unit can see.
558  * It differs from pathfinding in that it will only ever go out one turn,
559  * and that it will also collect a set of border hexes (the "one hex beyond"
560  * movement to which vision extends).
561  * @param viewer The unit doing the viewing.
562  * @param loc The location from which the viewing occurs
563  * (does not have to be the unit's location).
564  */
565 vision_path::vision_path(const unit& viewer, map_location const &loc,
566  const std::map<map_location, int>& jamming_map)
567  : paths(), edges()
568 {
569  const int sight_range = viewer.vision();
570 
571  // The four nullptr parameters indicate (in order): no teleports,
572  // ignore units, ignore ZoC (no effect), and see all (no effect).
573  find_routes(loc, viewer.movement_type().get_vision(),
574  viewer.get_state(unit::STATE_SLOWED), sight_range, sight_range,
575  0, destinations, &edges, nullptr, nullptr, nullptr, nullptr, &jamming_map);
576 }
577 
578 /**
579  * Constructs a list of vision paths for a unit.
580  *
581  * This constructor is provided so that only the relevant portion of a unit's
582  * data is required to construct the vision paths.
583  * @param view_costs The vision costs of the unit doing the viewing.
584  * @param slowed Whether or not the unit is slowed.
585  * @param sight_range The vision() of the unit.
586  * @param loc The location from which the viewing occurs
587  * (does not have to be the unit's location).
588  */
590  int sight_range, const map_location & loc,
591  const std::map<map_location, int>& jamming_map)
592  : paths(), edges()
593 {
594  // The four nullptr parameters indicate (in order): no teleports,
595  // ignore units, ignore ZoC (no effect), and see all (no effect).
596  find_routes(loc, view_costs, slowed, sight_range, sight_range, 0,
597  destinations, &edges, nullptr, nullptr, nullptr, nullptr, &jamming_map);
598 }
599 
600 /// Default destructor
602 {
603 }
604 
605 
606 /**
607  * Constructs a list of jamming paths for a unit.
608  *
609  * This is used to construct a list of hexes that the indicated unit can jam.
610  * It differs from pathfinding in that it will only ever go out one turn.
611  * @param jammer The unit doing the jamming.
612  * @param loc The location from which the jamming occurs
613  * (does not have to be the unit's location).
614  */
615 jamming_path::jamming_path(const unit& jammer, map_location const &loc)
616  : paths()
617 {
618  const int jamming_range = jammer.jamming();
619 
620  // The five nullptr parameters indicate (in order): no edges, no teleports,
621  // ignore units, ignore ZoC (no effect), and see all (no effect).
622  find_routes(loc, jammer.movement_type().get_jamming(),
623  jammer.get_state(unit::STATE_SLOWED), jamming_range, jamming_range,
624  0, destinations, nullptr, nullptr, nullptr, nullptr, nullptr);
625 }
626 
627 /// Default destructor
629 {
630 }
631 
633 {
635 
636  if (rt.steps.empty()) return marked_route();
637  res.route = rt;
638 
640  if (it == resources::units->end()) return marked_route();
641  unit const& u = *it;
642 
643  int turns = 0;
644  int movement = u.movement_left();
645  const team& unit_team = (*resources::teams)[u.side()-1];
646  bool zoc = false;
647 
648  std::vector<map_location>::const_iterator i = rt.steps.begin();
649 
650  for (; i !=rt.steps.end(); ++i) {
651  bool last_step = (i+1 == rt.steps.end());
652 
653  // move_cost of the next step is irrelevant for the last step
654  assert(last_step || resources::gameboard->map().on_board(*(i+1)));
655  const int move_cost = last_step ? 0 : u.movement_cost((resources::gameboard->map())[*(i+1)]);
656 
657  team const& viewing_team = (*resources::teams)[resources::screen->viewing_team()];
658 
659  if (last_step || zoc || move_cost > movement) {
660  // check if we stop an a village and so maybe capture it
661  // if it's an enemy unit and a fogged village, we assume a capture
662  // (if he already owns it, we can't know that)
663  // if it's not an enemy, we can always know if he owns the village
664  bool capture = resources::gameboard->map().is_village(*i) && ( !unit_team.owns_village(*i)
665  || (viewing_team.is_enemy(u.side()) && viewing_team.fogged(*i)) );
666 
667  ++turns;
668 
669  bool invisible = u.invisible(*i,false);
670 
671  res.marks[*i] = marked_route::mark(turns, zoc, capture, invisible);
672 
673  if (last_step) break; // finished and we used dummy move_cost
674 
675  movement = u.total_movement();
676  if(move_cost > movement) {
677  return res; //we can't reach destination
678  }
679  }
680 
681  zoc = enemy_zoc(unit_team, *(i + 1), viewing_team)
682  && !u.get_ability_bool("skirmisher", *(i+1));
683 
684  if (zoc) {
685  movement = 0;
686  } else {
687  movement -= move_cost;
688  }
689  }
690 
691  return res;
692 }
693 
695  std::vector<team> const &teams, gamemap const &map,
696  bool ignore_unit, bool ignore_defense, bool see_all)
697  : unit_(u), viewing_team_(t), teams_(teams), map_(map),
698  movement_left_(unit_.movement_left()),
699  total_movement_(unit_.total_movement()),
700  ignore_unit_(ignore_unit), ignore_defense_(ignore_defense),
701  see_all_(see_all)
702 {}
703 
704 double shortest_path_calculator::cost(const map_location& loc, const double so_far) const
705 {
706  assert(map_.on_board(loc));
707 
708  // loc is shrouded, consider it impassable
709  // NOTE: This is why AI must avoid to use shroud
710  if (!see_all_ && viewing_team_.shrouded(loc))
711  return getNoPathValue();
712 
714  int const terrain_cost = unit_.movement_cost(terrain);
715  // Pathfinding heuristic: the cost must be at least 1
716  VALIDATE(terrain_cost >= 1, _("Terrain with a movement cost less than 1 encountered."));
717 
718  // total MP is not enough to move on this terrain: impassable
719  if (total_movement_ < terrain_cost)
720  return getNoPathValue();
721 
722  int other_unit_subcost = 0;
723  if (!ignore_unit_) {
724  const unit *other_unit =
726 
727  // We can't traverse visible enemy and we also prefer empty hexes
728  // (less blocking in multi-turn moves and better when exploring fog,
729  // because we can't stop on a friend)
730 
731  if (other_unit)
732  {
733  if (teams_[unit_.side() - 1].is_enemy(other_unit->side()))
734  return getNoPathValue();
735  else
736  // This value will be used with the defense_subcost (see below)
737  // The 1 here means: consider occupied hex as a -1% defense
738  // (less important than 10% defense because friends may move)
739  other_unit_subcost = 1;
740  }
741  }
742 
743  // Compute how many movement points are left in the game turn
744  // needed to reach the previous hex.
745  // total_movement_ is not zero, thanks to the pathfinding heuristic
746  int remaining_movement = movement_left_ - static_cast<int>(so_far);
747  if (remaining_movement < 0)
748  remaining_movement = total_movement_ - (-remaining_movement) % total_movement_;
749 
750  // this will sum all different costs of this move
751  int move_cost = 0;
752 
753  // Suppose that we have only 2 remaining MP and want to move onto a hex
754  // costing 3 MP. We don't have enough MP now, so we must end our turn here,
755  // thus spend our remaining MP by waiting (next turn, with full MP, we will
756  // be able to move on that hex)
757  if (remaining_movement < terrain_cost) {
758  move_cost += remaining_movement;
759  remaining_movement = total_movement_; // we consider having full MP now
760  }
761 
762  // check ZoC
763  if (!ignore_unit_ && remaining_movement != terrain_cost
765  && !unit_.get_ability_bool("skirmisher", loc)) {
766  // entering ZoC cost all remaining MP
767  move_cost += remaining_movement;
768  } else {
769  // empty hex, pay only the terrain cost
770  move_cost += terrain_cost;
771  }
772 
773  // We will add a tiny cost based on terrain defense, so the pathfinding
774  // will prefer good terrains between 2 with the same MP cost
775  // Keep in mind that defense_modifier is inverted (= 100 - defense%)
776  const int defense_subcost = ignore_defense_ ? 0 : unit_.defense_modifier(terrain);
777 
778  // We divide subcosts by 100 * 100, because defense is 100-based and
779  // we don't want any impact on move cost for less then 100-steps path
780  // (even ~200 since mean defense is around ~50%)
781  return move_cost + (defense_subcost + other_unit_subcost) / 10000.0;
782 }
783 
784 move_type_path_calculator::move_type_path_calculator(const movetype& mt, int movement_left, int total_movement, team const &t, gamemap const &map)
785  : movement_type_(mt), movement_left_(movement_left),
786  total_movement_(total_movement), viewing_team_(t), map_(map)
787 {}
788 
789 // This is an simplified version of shortest_path_calculator (see above for explanation)
790 double move_type_path_calculator::cost(const map_location& loc, const double so_far) const
791 {
792  assert(map_.on_board(loc));
793  if (viewing_team_.shrouded(loc))
794  return getNoPathValue();
795 
797  int const terrain_cost = movement_type_.movement_cost(terrain);
798 
799  if (total_movement_ < terrain_cost)
800  return getNoPathValue();
801 
802  int remaining_movement = movement_left_ - static_cast<int>(so_far);
803  if (remaining_movement < 0)
804  remaining_movement = total_movement_ - (-remaining_movement) % total_movement_;
805 
806  int move_cost = 0;
807 
808  if (remaining_movement < terrain_cost) {
809  move_cost += remaining_movement;
810  }
811 
812  move_cost += terrain_cost;
813 
814  return move_cost;
815 }
816 
817 
819  : unit_(u), map_(map)
820 {}
821 
822 double emergency_path_calculator::cost(const map_location& loc, const double) const
823 {
824  assert(map_.on_board(loc));
825 
826  return unit_.movement_cost(map_[loc]);
827 }
828 
830 {}
831 
832 double dummy_path_calculator::cost(const map_location&, const double) const
833 {
834  return 1.0;
835 }
836 
837 /**
838  * Constructs a cost-map. For a unit each hex is mapped to the cost the
839  * unit will need to reach this hex. Considers movement-loss caused by
840  * turn changes.
841  * Can also used with multiple units to accumulate their costs efficiently.
842  * Will also count how many units could reach a hex for easy normalization.
843  * @param u the unit
844  * @param force_ignore_zoc Set to true to completely ignore zones of control.
845  * @param allow_teleport Set to true to consider teleportation abilities.
846  * @param viewing_team Usually the current team, except for "show enemy moves", etc.
847  * @param see_all Set to true to remove unit visibility from consideration.
848  * @param ignore_units Set to true if units should never obstruct paths (implies ignoring ZoC as well).
849  */
850 full_cost_map::full_cost_map(const unit& u, bool force_ignore_zoc,
851  bool allow_teleport, const team &viewing_team,
852  bool see_all, bool ignore_units)
853  :force_ignore_zoc_(force_ignore_zoc), allow_teleport_(allow_teleport),
854  viewing_team_(viewing_team), see_all_(see_all), ignore_units_(ignore_units)
855 {
856  const gamemap& map = resources::gameboard->map();
857  cost_map = std::vector<std::pair<int, int> >(map.w() * map.h(), std::make_pair(-1, 0));
858  add_unit(u);
859 }
860 
861 /**
862  * Same as other constructor but without unit. Use this when working
863  * with add_unit().
864  */
865 full_cost_map::full_cost_map(bool force_ignore_zoc,
866  bool allow_teleport, const team &viewing_team,
867  bool see_all, bool ignore_units)
868  :force_ignore_zoc_(force_ignore_zoc), allow_teleport_(allow_teleport),
869  viewing_team_(viewing_team), see_all_(see_all), ignore_units_(ignore_units)
870 {
871  const gamemap& map = resources::gameboard->map();
872  cost_map = std::vector<std::pair<int, int> >(map.w() * map.h(), std::make_pair(-1, 0));
873 }
874 
875 /**
876  * Adds a units cost map to cost_map (increments the elements in cost_map)
877  * @param u a real existing unit on the map
878  */
879 void full_cost_map::add_unit(const unit& u, bool use_max_moves)
880 {
881  std::vector<team> const &teams = *resources::teams;
882  if (u.side() < 1 || u.side() > int(teams.size())) {
883  return;
884  }
885 
886  // We don't need the destinations, but find_routes() wants to have this parameter
888 
891  (use_max_moves) ? u.total_movement() : u.movement_left(),
892  u.total_movement(), 99, dummy, nullptr,
893  allow_teleport_ ? &u : nullptr,
894  ignore_units_ ? nullptr : &teams[u.side()-1],
895  force_ignore_zoc_ ? nullptr : &u,
896  see_all_ ? nullptr : &viewing_team_,
897  nullptr, &cost_map);
898 }
899 
900 /**
901  * Adds a units cost map to cost_map (increments the elements in cost_map)
902  * This function can be used to generate a cost_map with a non existing unit.
903  * @param origin the location on the map from where the calculations shall start
904  * @param ut the unit type we are interested in
905  * @param side the side of the unit. Important for zocs.
906  */
907 void full_cost_map::add_unit(const map_location& origin, const unit_type* const ut, int side)
908 {
909  if (!ut) {
910  return;
911  }
912  unit u(*ut, side, false);
913  u.set_location(origin);
914  add_unit(u);
915 }
916 
917 /**
918  * Accessor for the cost/reach-amount pairs.
919  * Read comment in pathfind.hpp to cost_map.
920  *
921  * @return the entry of the cost_map at (x, y)
922  * or (-1, 0) if value is not set or (x, y) is invalid.
923  */
924 std::pair<int, int> full_cost_map::get_pair_at(int x, int y) const
925 {
926  const gamemap& map = resources::gameboard->map();
927  assert(cost_map.size() == static_cast<unsigned>(map.w() * map.h()));
928 
929  if (x < 0 || x >= map.w() || y < 0 || y >= map.h()) {
930  return std::make_pair(-1, 0); // invalid
931  }
932 
933  return cost_map[x + (y * map.w())];
934 }
935 
936 /**
937  * Accessor for the costs.
938  *
939  * @return the value of the cost_map at (x, y)
940  * or -1 if value is not set or (x, y) is invalid.
941  */
942 int full_cost_map::get_cost_at(int x, int y) const
943 {
944  return get_pair_at(x, y).first;
945 }
946 
947 /**
948  * Accessor for the costs.
949  *
950  * @return The average cost of all added units for this hex
951  * or -1 if no unit can reach the hex.
952  */
953 double full_cost_map::get_average_cost_at(int x, int y) const
954 {
955  if (get_pair_at(x, y).second == 0) {
956  return -1;
957  } else {
958  return static_cast<double>(get_pair_at(x, y).first) / get_pair_at(x, y).second;
959  }
960 }
961 }//namespace pathfind
bool uses_shroud() const
Definition: team.hpp:315
int total_movement() const
Definition: unit.hpp:218
Game board class.
Definition: game_board.hpp:55
Stores a set of terrain costs (for movement, vision, or "jamming").
Definition: movetype.hpp:88
virtual const unit_map & units() const
Definition: game_board.hpp:99
unit_iterator end()
Definition: map.hpp:311
const map_location & get_location() const
Definition: unit.hpp:286
marked_route mark_route(const plain_route &rt)
Add marks on a route rt assuming that the unit located at the first hex of rt travels along it...
Definition: pathfind.cpp:632
std::vector< std::pair< int, int > > cost_map
Definition: pathfind.hpp:296
bool emits_zoc() const
Definition: unit.hpp:257
std::pair< int, int > get_pair_at(int x, int y) const
Accessor for the cost/reach-amount pairs.
Definition: pathfind.cpp:924
emergency_path_calculator(const unit &u, const gamemap &map)
Definition: pathfind.cpp:818
bool get_state(const std::string &state) const
Definition: unit.cpp:1289
Definition: unit.hpp:95
map_location find_vacant_castle(const unit &leader)
Wrapper for find_vacant_tile() when looking for a vacant castle tile near a leader.
Definition: pathfind.cpp:121
static paths::dest_vect::iterator lower_bound(paths::dest_vect &v, const map_location &loc)
Definition: pathfind.cpp:461
bool shrouded(const map_location &loc) const
Definition: team.cpp:567
virtual double cost(const map_location &loc, const double so_far) const
Definition: pathfind.cpp:790
int movement_cost(const t_translation::t_terrain &terrain) const
Definition: unit.hpp:308
int pos
Definition: formula.cpp:800
int jamming() const
Definition: unit.hpp:224
Add a special kind of assert to validate whether the input from WML doesn't contain any problems that...
variant map_
Definition: formula.cpp:306
bool owns_village(const map_location &loc) const
Definition: team.hpp:190
static const int UNREACHABLE
Magic value that signifies a hex is unreachable.
Definition: movetype.hpp:85
void get_adjacent_tiles(const map_location &a, map_location *res)
Function which, given a location, will place all adjacent locations in res.
Definition: location.hpp:274
bool is_village(const map_location &loc) const
Definition: map.cpp:68
game_display * screen
Definition: resources.cpp:27
map_location find_vacant_tile(const map_location &loc, VACANT_TILE_TYPE vacancy, const unit *pass_check, const team *shroud_check, const game_board *board)
Function that will find a location on the board that is as near to loc as possible, but which is unoccupied by any units.
Definition: pathfind.cpp:56
bool is_enemy(int n) const
Definition: team.hpp:247
const_iterator find(const map_location &) const
Definition: pathfind.cpp:474
dest_vect destinations
Definition: pathfind.hpp:100
int side() const
Definition: unit.hpp:201
GLint GLint GLint GLint GLint GLint y
Definition: glew.h:1220
The basic "size" of the unit - flying, small land, large land, etc.
Definition: movetype.hpp:28
void add_unit(const unit &u, bool use_max_moves=true)
Adds a units cost map to cost_map (increments the elements in cost_map)
Definition: pathfind.cpp:879
const unit * unit_
bool get_ability_bool(const std::string &tag_name, const map_location &loc) const
Returns true if the unit is currently under effect by an ability with this given TAG NAME...
Definition: abilities.cpp:129
-file sdl_utils.hpp
GLdouble GLdouble t
Definition: glew.h:1366
virtual ~jamming_path()
Default destructor.
Definition: pathfind.cpp:628
int movement_cost(const t_translation::t_terrain &terrain, bool slowed=false) const
Returns the cost to move through the indicated terrain.
Definition: movetype.hpp:199
double get_average_cost_at(int x, int y) const
Accessor for the costs.
Definition: pathfind.cpp:953
int defense_modifier(const t_translation::t_terrain &terrain) const
Definition: unit.cpp:1520
std::vector< team > const & teams_
Definition: pathfind.hpp:215
GLdouble l
Definition: glew.h:6966
terrain_costs & get_jamming()
Definition: movetype.hpp:183
static double getNoPathValue()
Definition: pathfind.hpp:64
GLdouble GLdouble GLdouble b
Definition: glew.h:6966
static std::vector< team > *& teams
Definition: team.cpp:50
bool contains(const map_location &) const
Definition: pathfind.cpp:510
This class stores all the data for a single 'side' (in game nomenclature).
Definition: team.hpp:50
static UNUSEDNOWARN std::string _(const char *str)
Definition: gettext.hpp:82
virtual double cost(const map_location &loc, const double so_far) const
Definition: pathfind.cpp:704
GLsizei const char ** path
Definition: glew.h:4654
GLuint GLuint end
Definition: glew.h:1221
map_location prev
Definition: pathfind.cpp:164
std::vector< map_location > steps
Definition: pathfind.hpp:135
virtual double cost(const map_location &loc, const double so_far) const
Definition: pathfind.cpp:822
std::vector< team > * teams
Definition: resources.cpp:29
#define VALIDATE(cond, message)
The macro to use for the validation of WML.
move_type_path_calculator(const movetype &mt, int movement_left, int total_movement, const team &t, const gamemap &map)
Definition: pathfind.cpp:784
Structure which holds a single route between one location and another.
Definition: pathfind.hpp:132
static void find_routes(const map_location &origin, const movetype::terrain_costs &costs, bool slowed, int moves_left, int max_moves, int turns_left, paths::dest_vect &destinations, std::set< map_location > *edges, const unit *teleporter, const team *current_team, const unit *skirmisher, const team *viewing_team, const std::map< map_location, int > *jamming_map=nullptr, std::vector< std::pair< int, int > > *full_cost_map=nullptr)
Creates a list of routes that a unit can traverse from the provided location.
Definition: pathfind.cpp:267
unit * get_visible_unit(const map_location &loc, const team &current_team, bool see_all=false)
Definition: game_board.cpp:192
const bool allow_teleport_
Definition: pathfind.hpp:300
int h
Definition: pathfind.cpp:195
const GLdouble * v
Definition: glew.h:1359
static lg::log_domain log_engine("engine")
int w() const
Effective map width.
Definition: map.hpp:105
terrain_costs & get_vision()
Definition: movetype.hpp:182
vision_path(const unit &viewer, map_location const &loc, const std::map< map_location, int > &jamming_map)
Construct a list of seen hexes for a unit.
Definition: pathfind.cpp:565
game_board * gameboard
Definition: resources.cpp:20
GLboolean GLboolean GLboolean GLboolean a
Definition: glew.h:7319
VACANT_TILE_TYPE
Definition: pathfind.hpp:39
dummy_path_calculator(const unit &u, const gamemap &map)
Definition: pathfind.cpp:829
Encapsulates the map of the game.
Definition: map.hpp:37
int moves_left
Definition: pathfind.cpp:163
virtual ~vision_path()
Default destructor.
Definition: pathfind.cpp:601
full_cost_map(const unit &u, bool force_ignore_zoc, bool allow_teleport, const team &viewing_team, bool see_all=true, bool ignore_units=true)
Constructs a cost-map.
Definition: pathfind.cpp:850
Structure which holds a single route and marks for special events.
Definition: pathfind.hpp:141
static const map_location & null_location()
Definition: location.hpp:195
int movement_left() const
Returns how far a unit can move this turn (zero if incapacitated).
Definition: unit.hpp:220
static const ::config * terrain
The terrain used to create the cache.
Definition: minimap.cpp:135
typedef int(WINAPI *PFNWGLRELEASEPBUFFERDCARBPROC)(HPBUFFERARB hPbuffer
virtual double cost(const map_location &loc, const double so_far) const
Definition: pathfind.cpp:832
terrain_costs & get_movement()
Definition: movetype.hpp:181
bool invisible(const map_location &loc, bool see_all=true) const
Definition: unit.cpp:2291
A terrain string which is converted to a terrain is a string with 1 or 2 layers the layers are separa...
Definition: translation.hpp:47
Encapsulates the map of the game.
Definition: location.hpp:38
virtual ~paths()
Virtual destructor (default processing).
Definition: pathfind.cpp:550
GLuint res
Definition: glew.h:9258
int h() const
Effective map height.
Definition: map.hpp:108
Ordered vector of possible destinations.
Definition: pathfind.hpp:93
void set_location(const map_location &loc)
To be called by unit_map or for temporary units only.
Definition: unit.hpp:288
GLuint index
Definition: glew.h:1782
static bool operator<(const placing_info &a, const placing_info &b)
Definition: game_state.cpp:127
Structure which uses find_routes() to build a cost map This maps each hex to a the movements a unit w...
Definition: pathfind.hpp:267
map_location curr
Definition: astarsearch.cpp:67
const team & viewing_team_
Definition: pathfind.hpp:301
size_t i
Definition: function.cpp:1057
const bool ignore_units_
Definition: pathfind.hpp:303
GLint GLint GLint GLint GLint x
Definition: glew.h:1220
shortest_path_calculator(const unit &u, const team &t, const std::vector< team > &teams, const gamemap &map, bool ignore_unit=false, bool ignore_defense_=false, bool see_all=false)
Definition: pathfind.cpp:694
bool fogged(const map_location &loc) const
Definition: team.cpp:575
const bool force_ignore_zoc_
Definition: pathfind.hpp:299
GLdouble GLdouble GLdouble r
Definition: glew.h:1374
bool is_castle(const map_location &loc) const
Definition: map.cpp:72
int cost(const t_translation::t_terrain &terrain, bool slowed=false) const
Returns the cost associated with the given terrain.
Definition: movetype.hpp:109
virtual const gamemap & map() const
Definition: game_board.hpp:98
bool on_board(const map_location &loc) const
Tell if a location is on the map.
Definition: map.cpp:467
#define next(ls)
Definition: llex.cpp:27
int w
Definition: pathfind.cpp:195
GLclampd n
Definition: glew.h:5903
bool find(E event, F functor)
Tests whether an event handler is available.
const movetype & movement_type() const
Definition: unit.hpp:321
std::set< map_location > edges
The edges are the non-destination hexes bordering the destinations.
Definition: pathfind.hpp:117
Standard logging facilities (interface).
Object which contains all the possible locations a unit can move to, with associated best routes to t...
Definition: pathfind.hpp:71
Container associating units to locations.
Definition: map.hpp:90
utf8::string & insert(utf8::string &str, const size_t pos, const utf8::string &insert)
Insert a UTF-8 string at the specified position.
Definition: unicode.cpp:101
unsigned search_num
Definition: pathfind.cpp:168
size_t viewing_team() const
The viewing team is the team currently viewing the game.
Definition: display.hpp:102
unit_iterator find(size_t id)
Definition: map.cpp:285
int get_cost_at(int x, int y) const
Accessor for the costs.
Definition: pathfind.cpp:942
const teleport_map get_teleport_locations(const unit &u, const team &viewing_team, bool see_all, bool ignore_units)
Definition: teleport.cpp:233
std::vector< map_location > get_path(const const_iterator &) const
Returns the path going from the source point (included) to the destination point j (excluded)...
Definition: pathfind.cpp:493
const std::vector< findroute_node > & nodes
Definition: pathfind.cpp:219
std::string::const_iterator iterator
Definition: tokenizer.hpp:21
GLdouble s
Definition: glew.h:1358
This module contains various pathfinding functions and utilities.
int turns_left
Definition: pathfind.cpp:163
unit_map * units
Definition: resources.cpp:35
bool enemy_zoc(team const &current_team, map_location const &loc, team const &viewing_team, bool see_all)
Determines if a given location is in an enemy zone of control.
Definition: pathfind.cpp:138
void insert(const map_location &)
Definition: pathfind.cpp:481
jamming_path(const unit &jammer, map_location const &loc)
Construct a list of jammed hexes for a unit.
Definition: pathfind.cpp:615
void get_adjacents(std::set< map_location > &adjacents, map_location loc) const
Definition: teleport.cpp:202
int vision() const
Definition: unit.hpp:223