-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathPathFinder.cpp
More file actions
124 lines (113 loc) · 4.32 KB
/
Copy pathPathFinder.cpp
File metadata and controls
124 lines (113 loc) · 4.32 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
#include "PathFinder.hpp"
#include <algorithm>
#include <cmath>
#include <limits>
// Grid constructor, made up of nodes
Grid::Grid(int w, int h) : width(w), height(h), nodes(h, std::vector<Node>(w)) {
for (int y = 0; y < height; ++y) {
for (int x = 0; x < width; ++x) {
nodes[y][x].x = x;
nodes[y][x].y = y;
nodes[y][x].g = std::numeric_limits<float>::infinity();
nodes[y][x].h = 0;
}
}
}
// Check if a position is inside the grid bounds
bool Grid::inBounds(int x, int y) const {
return x >= 0 && x < width && y >= 0 && y < height;
}
// Function to estimate the h cost from node a to node b
float estimatedCost(Node* a, Node* b) {
return std::abs(a->x - b->x) + std::abs(a->y - b->y);
}
// Function to get the neighbours of a node (does not include diagonal neighbours)
std::vector<Node*> getNeighbours(Node* node, Grid& grid) {
std::vector<Node*> neighbours;
const int dx[] = { -1, 1, 0, 0 };
const int dy[] = { 0, 0, -1, 1 };
for (int i = 0; i < 4; ++i) {
int nx = node->x + dx[i];
int ny = node->y + dy[i];
if (grid.inBounds(nx, ny)) {
neighbours.push_back(&grid.nodes[ny][nx]);
}
}
return neighbours;
}
// Function to see if there is enough space for the object to fit through the path
bool isSpaceFree(int x, int y, Grid& grid, int objW, int objH) {
for (int dy = 0; dy < objH; ++dy) {
for (int dx = 0; dx < objW; ++dx) {
int nx = x + dx;
int ny = y + dy;
if (!grid.inBounds(nx, ny) || grid.nodes[ny][nx].wall) {
return false;
}
}
}
return true;
}
// The A Star pathfinding algorithm
std::vector<Node*> aStar(Node* start, Node* goal, Grid& grid, int objectWidth, int objectHeight) {
// List of nodes to be checked
std::vector<Node*> openSet;
start->g = 0;
start->h = estimatedCost(start, goal);
openSet.push_back(start);
Node* closestToGoal = start;
float lowestH = start->h;
while (!openSet.empty()) {
// Sort list of nodes by lowest F cost
std::sort(openSet.begin(), openSet.end(), [](Node* a, Node* b) {
return a->f() < b->f();
});
Node* current = openSet.front();
openSet.erase(openSet.begin());
// If the goal has been reached, reconstruct the path
if (current == goal) {
std::vector<Node*> path;
while (current != nullptr) {
path.push_back(current);
current = current->previousNode;
}
std::reverse(path.begin(), path.end());
return path;
}
current->visited = true;
// Check each neighbour
for (Node* neighbour : getNeighbours(current, grid)) {
// Complete checks
if (neighbour->x + objectWidth > grid.width || neighbour->y + objectHeight > grid.height) continue;
if (!isSpaceFree(neighbour->x, neighbour->y, grid, objectWidth, objectHeight)) continue;
float tentativeG = current->g + 1; // Distance/cost between neighbouring nodes
// If the cost is less (if this path to neighbor is better), then record it
if (tentativeG < neighbour->g) {
neighbour->previousNode = current;
neighbour->g = tentativeG;
neighbour->h = estimatedCost(neighbour, goal);
// Add neighbour to list of nodes if not already on it
if (std::find(openSet.begin(), openSet.end(), neighbour) == openSet.end()) {
openSet.push_back(neighbour);
}
// Get neighbour closest to goal, for checking if goal is not possible to reach
if (neighbour->h < lowestH) {
lowestH = neighbour->h;
closestToGoal = neighbour;
}
}
}
}
// If no path to goal then return path to closest possible node
if (closestToGoal != start && closestToGoal->previousNode != nullptr) {
std::vector<Node*> path;
Node* current = closestToGoal;
while (current != nullptr) {
path.push_back(current);
current = current->previousNode;
}
std::reverse(path.begin(), path.end());
return path;
}
return {}; // No path found
}