Symphony Of Empires
pathfind.hpp
Go to the documentation of this file.
1 // Symphony of Empires
2 // Copyright (C) 2021, Symphony of Empires contributors
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program. If not, see <https://www.gnu.org/licenses/>.
16 //
17 // ----------------------------------------------------------------------------
18 // Name:
19 // pathfind.hpp
20 //
21 // Abstract:
22 // Generalized pathfinder algorithms
23 // ----------------------------------------------------------------------------
24 
25 #pragma once
26 
27 #include <queue>
28 #include <unordered_map>
29 #include <unordered_set>
30 #include <algorithm>
31 #include <functional>
32 #include <cmath>
33 
34 namespace Eng3D::Pathfind {
39  template<typename T>
40  inline std::vector<T> get_path(T start, T end, std::function<std::vector<T>(T)> g, std::function<float(T, T)> h) {
42  std::unordered_map<T, float> cost_map;
44  std::unordered_map<T, T> prev_map;
46  std::unordered_set<T> visited;
47 
48  auto comp = [](const auto& a, const auto& b) { return a.first > b.first; };
50  std::priority_queue<std::pair<float, T>,
51  std::vector<std::pair<float, T>>,
52  decltype(comp)
53  > queue;
54 
55  cost_map[start] = 0.f;
56  queue.push({ 0.f, start });
57  while(!queue.empty()) {
58  auto current = queue.top().second;
59  queue.pop();
60 
61  // If the current node has been previously visited,
62  // it's optimal cost has already been calculated, and we can skip it
63  if(visited.count(current)) continue;
64  visited.insert(current);
65 
66  // We are done
67  if(current == end) break;
68 
69  // Generate neighbours
70  for(const auto neighbor : g(current)) {
71  // If the neighbor is visited, we already have the optimal path to it
72  if(visited.count(neighbor)) continue;
73  const float cost = cost_map[current] + h(current, neighbor);
74  // If we found a new tile or a shorter path to a previously found tile
75  if(!cost_map.count(neighbor) || cost < cost_map[neighbor]) {
76  cost_map[neighbor] = cost;
77  const float priority = cost + h(neighbor, end);
78  queue.push({ priority, neighbor });
79  prev_map[neighbor] = current;
80  }
81  }
82  }
83 
84  // Unwind path and reverse
85  std::vector<T> path;
86  path.reserve(std::abs(static_cast<long>(start) - static_cast<long>(end)));
87  auto current = end;
88  while(current != start) {
89  path.push_back(current);
90  current = prev_map[current];
91  }
92  path.push_back(start);
93  return path;
94  }
95 
96  template<typename T, typename V>
97  inline void from_source(T source, const std::vector<std::vector<V>>& neighbour_rels, std::vector<float>& costs) {
98  auto cmp = [](const V& a, const V& b) { return a.cost < b.cost; };
99  std::priority_queue<V, std::vector<V>, decltype(cmp)> heap;
100  heap.emplace(0.f, source);
101  while(!heap.empty()) {
102  auto vertex = heap.top();
103  heap.pop();
104  if(vertex.cost < costs[vertex.key]) {
105  costs[vertex.key] = vertex.cost;
106  const auto& neighbours = neighbour_rels[vertex.key];
107  for(const auto& neighbour : neighbours)
108  if(neighbour.cost < costs[neighbour.key])
109  heap.emplace(neighbour.cost, neighbour.key);
110  }
111  }
112  }
113 }
std::vector< T > get_path(T start, T end, std::function< std::vector< T >(T)> g, std::function< float(T, T)> h)
Implements the A* algorithm with euclidean distance as heuristic. Returns a vector where the starting...
Definition: pathfind.hpp:40
void from_source(T source, const std::vector< std::vector< V >> &neighbour_rels, std::vector< float > &costs)
Definition: pathfind.hpp:97