This commit is contained in:
2026-01-24 18:22:57 +01:00
parent 511816adea
commit 4465a756ef
5 changed files with 88 additions and 68 deletions
+23 -33
View File
@@ -74,36 +74,36 @@ class Node {
}; };
namespace Heuristic { namespace Heuristic {
static inline Vec2i deltaVec(const Vec2i& source, const Vec2i& target) noexcept { static inline Vec2i deltaVec(const Vec2i& start, const Vec2i& target) noexcept {
return {std::abs(source.x - target.x), std::abs(source.y - target.y)}; return {std::abs(start.x - target.x), std::abs(start.y - target.y)};
} }
static inline uint32_t manhattan(const Vec2i& source, const Vec2i& target, const uint32_t weight) noexcept { static inline uint32_t manhattan(const Vec2i& start, const Vec2i& target, const uint32_t weight) noexcept {
auto delta = deltaVec(source, target); auto delta = deltaVec(start, target);
return weight * (delta.x + delta.y); return weight * (delta.x + delta.y);
} }
static inline uint32_t octagonal(const Vec2i& source, const Vec2i& target, const uint32_t weight) noexcept { static inline uint32_t octagonal(const Vec2i& start, const Vec2i& target, const uint32_t weight) noexcept {
auto delta = deltaVec(source, target); auto delta = deltaVec(start, target);
return weight * (delta.x + delta.y) + (-6) * std::min(delta.x, delta.y); return weight * (delta.x + delta.y) + (-6) * std::min(delta.x, delta.y);
} }
static inline uint32_t euclidean(const Vec2i& source, const Vec2i& target, const uint32_t weight) noexcept { static inline uint32_t euclidean(const Vec2i& start, const Vec2i& target, const uint32_t weight) noexcept {
auto delta = deltaVec(source, target); auto delta = deltaVec(start, target);
return weight * static_cast<uint32_t>(std::sqrt(std::pow(delta.x, 2) + std::pow(delta.y, 2))); return weight * static_cast<uint32_t>(std::sqrt(std::pow(delta.x, 2) + std::pow(delta.y, 2)));
} }
static inline uint32_t chebyshev(const Vec2i& source, const Vec2i& target, const uint32_t weight) noexcept { static inline uint32_t chebyshev(const Vec2i& start, const Vec2i& target, const uint32_t weight) noexcept {
auto delta = deltaVec(source, target); auto delta = deltaVec(start, target);
return weight * std::max(delta.x, delta.y); return weight * std::max(delta.x, delta.y);
} }
static inline uint32_t euclideanNoSQR(const Vec2i& source, const Vec2i& target, const uint32_t weight) noexcept { static inline uint32_t euclideanNoSQR(const Vec2i& start, const Vec2i& target, const uint32_t weight) noexcept {
auto delta = deltaVec(source, target); auto delta = deltaVec(start, target);
return weight * static_cast<uint32_t>(std::pow(delta.x, 2) + std::pow(delta.y, 2)); return weight * static_cast<uint32_t>(std::pow(delta.x, 2) + std::pow(delta.y, 2));
} }
static constexpr uint32_t dijkstra([[maybe_unused]] const Vec2i& source, static constexpr uint32_t dijkstra([[maybe_unused]] const Vec2i& start,
[[maybe_unused]] const Vec2i& target, [[maybe_unused]] const Vec2i& target,
const uint32_t weight = 0) noexcept { const uint32_t weight = 0) noexcept {
return 0; return 0;
@@ -159,13 +159,13 @@ class AStarVirtual {
std::function<void(Node<CoordinateType>*)> _debugOpenNode; std::function<void(Node<CoordinateType>*)> _debugOpenNode;
}; };
using IsWalkableFn = std::function<bool(Vec2i)>;
template <IntegerType CoordinateType = uint32_t, bool enableDebug = false> template <IntegerType CoordinateType = uint32_t, bool enableDebug = false>
class AStar final : public AStarVirtual<CoordinateType, enableDebug> { class AStar final : public AStarVirtual<CoordinateType, enableDebug> {
public: public:
explicit AStar() {} explicit AStar() {}
std::vector<Vec2i> findPath(const Vec2i start, const Vec2i target, const Vec2i worldSize, IsWalkableFn isWalkable) {
std::vector<Vec2i> findPath(const Vec2i source, const Vec2i& target) { if (target.x < 0 || target.x >= worldSize.x || target.y < 0 || target.y >= worldSize.y) {
if (target.x < 0 || target.x >= _worldSize.x || target.y < 0 || target.y >= _worldSize.y) {
return {}; return {};
} }
@@ -178,8 +178,8 @@ class AStar final : public AStarVirtual<CoordinateType, enableDebug> {
std::unordered_map<Vec2i, Node<CoordinateType>*, Vec2i::hash> openNodeMap; std::unordered_map<Vec2i, Node<CoordinateType>*, Vec2i::hash> openNodeMap;
std::unordered_map<Vec2i, Node<CoordinateType>*, Vec2i::hash> closedNodeMap; std::unordered_map<Vec2i, Node<CoordinateType>*, Vec2i::hash> closedNodeMap;
openNodeVecPQueue.push(new Node<CoordinateType>(source)); openNodeVecPQueue.push(new Node<CoordinateType>(start));
openNodeMap.insert({source, openNodeVecPQueue.top()}); openNodeMap.insert({start, openNodeVecPQueue.top()});
while (!openNodeVecPQueue.empty()) { while (!openNodeVecPQueue.empty()) {
currentNode = openNodeVecPQueue.top(); currentNode = openNodeVecPQueue.top();
@@ -199,7 +199,7 @@ class AStar final : public AStarVirtual<CoordinateType, enableDebug> {
for (size_t i = 0; i < AStarVirtual<CoordinateType, enableDebug>::_directionsCount; ++i) { for (size_t i = 0; i < AStarVirtual<CoordinateType, enableDebug>::_directionsCount; ++i) {
Vec2i newPos = currentNode->pos + AStarVirtual<CoordinateType, enableDebug>::_directions[i]; Vec2i newPos = currentNode->pos + AStarVirtual<CoordinateType, enableDebug>::_directions[i];
if (_obstacles.contains(newPos)) { if (!isWalkable(newPos)) {
continue; continue;
} }
@@ -207,7 +207,7 @@ class AStar final : public AStarVirtual<CoordinateType, enableDebug> {
continue; continue;
} }
if (newPos.x < 0 || newPos.x >= _worldSize.x || newPos.y < 0 || newPos.y >= _worldSize.y) { if (newPos.x < 0 || newPos.x >= worldSize.x || newPos.y < 0 || newPos.y >= worldSize.y) {
continue; continue;
} }
@@ -251,17 +251,7 @@ class AStar final : public AStarVirtual<CoordinateType, enableDebug> {
return path; return path;
} }
void addObstacle(const Vec2i& pos) { _obstacles.insert(pos); }
void removeObstacle(const Vec2i& pos) { _obstacles.erase(pos); }
std::unordered_set<Vec2i, Vec2i::hash>& getObstacles() noexcept { return _obstacles; }
void clear() { _obstacles.clear(); }
void setWorldSize(const Vec2i& worldSize_) noexcept { _worldSize = worldSize_; }
private: private:
std::unordered_set<Vec2i, Vec2i::hash> _obstacles;
Vec2i _worldSize = {0, 0};
}; };
// Fast AStar are faster than normal AStar but use more ram and direct access to the map // Fast AStar are faster than normal AStar but use more ram and direct access to the map
@@ -271,7 +261,7 @@ class AStarFast final : public AStarVirtual<CoordinateType, enableDebug> {
explicit AStarFast() : _isObstacleFunction([](MapElementType value) { return value == 1; }) {} explicit AStarFast() : _isObstacleFunction([](MapElementType value) { return value == 1; }) {}
// Same as AStar::findPath() but use direct access to the map // Same as AStar::findPath() but use direct access to the map
std::vector<Vec2i> findPath(const Vec2i& source, const Vec2i& target, const std::vector<MapElementType>& map, const Vec2i& worldSize) { std::vector<Vec2i> findPath(const Vec2i& start, const Vec2i& target, const std::vector<MapElementType>& map, const Vec2i& worldSize) {
if (target.x < 0 || target.x >= worldSize.x || target.y < 0 || target.y >= worldSize.y) { if (target.x < 0 || target.x >= worldSize.x || target.y < 0 || target.y >= worldSize.y) {
return {}; return {};
} }
@@ -284,8 +274,8 @@ class AStarFast final : public AStarVirtual<CoordinateType, enableDebug> {
std::unordered_map<Vec2i, Node<CoordinateType>*, Vec2i::hash> openNodeMap; std::unordered_map<Vec2i, Node<CoordinateType>*, Vec2i::hash> openNodeMap;
std::unordered_map<Vec2i, Node<CoordinateType>*, Vec2i::hash> closedNodeMap; std::unordered_map<Vec2i, Node<CoordinateType>*, Vec2i::hash> closedNodeMap;
openNodeVecPQueue.push(new Node<CoordinateType>(source)); openNodeVecPQueue.push(new Node<CoordinateType>(start));
openNodeMap.insert({source, openNodeVecPQueue.top()}); openNodeMap.insert({start, openNodeVecPQueue.top()});
while (!openNodeVecPQueue.empty()) { while (!openNodeVecPQueue.empty()) {
currentNode = openNodeVecPQueue.top(); currentNode = openNodeVecPQueue.top();
+8 -5
View File
@@ -49,7 +49,6 @@ static void astar_bench(benchmark::State& state) {
AStar::AStar<CoordinateType, false> pathFinder; AStar::AStar<CoordinateType, false> pathFinder;
benchmark::DoNotOptimize(pathFinder); benchmark::DoNotOptimize(pathFinder);
pathFinder.setWorldSize({mapWidth, mapHeight});
pathFinder.setHeuristic(AStar::Heuristic::euclidean); pathFinder.setHeuristic(AStar::Heuristic::euclidean);
pathFinder.setDiagonalMovement(true); pathFinder.setDiagonalMovement(true);
@@ -62,15 +61,12 @@ static void astar_bench(benchmark::State& state) {
blocks[index] = 0; blocks[index] = 0;
} else { } else {
blocks[index] = 1; blocks[index] = 1;
pathFinder.addObstacle({static_cast<int32_t>(x), static_cast<int32_t>(y)});
} }
} }
} }
blocks[0] = 0; blocks[0] = 0;
pathFinder.removeObstacle({0, 0});
blocks[mapWidth * mapHeight - 1] = 0; blocks[mapWidth * mapHeight - 1] = 0;
pathFinder.removeObstacle({mapWidth - 1, mapHeight - 1});
AStar::Vec2i source(0, 0); AStar::Vec2i source(0, 0);
AStar::Vec2i target(mapWidth - 1, mapHeight - 1); AStar::Vec2i target(mapWidth - 1, mapHeight - 1);
@@ -78,8 +74,15 @@ static void astar_bench(benchmark::State& state) {
std::vector<AStar::Vec2i> path; std::vector<AStar::Vec2i> path;
benchmark::DoNotOptimize(path); benchmark::DoNotOptimize(path);
std::function<bool(AStar::Vec2i)> isWalkable = [&blocks, mapWidth, mapHeight](AStar::Vec2i pos) {
if (pos.x < 0 || pos.x >= mapWidth || pos.y < 0 || pos.y >= mapHeight) {
return false;
}
return blocks[pos.x + pos.y * mapWidth] == 0;
};
for (auto _ : state) { for (auto _ : state) {
path = pathFinder.findPath(source, target); path = pathFinder.findPath(source, target, {mapWidth, mapHeight}, isWalkable);
state.PauseTiming(); state.PauseTiming();
if (path.size() == 0) { if (path.size() == 0) {
state.SkipWithError("No path found"); state.SkipWithError("No path found");
+13 -12
View File
@@ -53,7 +53,6 @@ auto main() -> int {
generator_2.setMultiplier((uint32_t)multiplier); generator_2.setMultiplier((uint32_t)multiplier);
AStar::AStar<uint32_t, false> pathFinder; AStar::AStar<uint32_t, false> pathFinder;
pathFinder.setWorldSize({mapWidth, mapHeight});
pathFinder.setHeuristic(AStar::Heuristic::manhattan); pathFinder.setHeuristic(AStar::Heuristic::manhattan);
pathFinder.setDiagonalMovement(true); pathFinder.setDiagonalMovement(true);
@@ -95,8 +94,6 @@ auto main() -> int {
generator_2.setWeightedStrength(weighted_strength); generator_2.setWeightedStrength(weighted_strength);
generator_2.setMultiplier((uint32_t)multiplier); generator_2.setMultiplier((uint32_t)multiplier);
pathFinder.clear();
heightmap = generator_2.generate2dMeightmap(0, 0, 0, screenWidth, 0, screenHeight); heightmap = generator_2.generate2dMeightmap(0, 0, 0, screenWidth, 0, screenHeight);
for (uint64_t x = 0; x < mapWidth; x++) { for (uint64_t x = 0; x < mapWidth; x++) {
@@ -108,18 +105,22 @@ auto main() -> int {
blocks[index] = 0; blocks[index] = 0;
} else { } else {
blocks[index] = 1; blocks[index] = 1;
pathFinder.addObstacle({static_cast<int32_t>(x), static_cast<int32_t>(y)});
} }
} }
} }
blocks[0] = 0; blocks[0] = 0;
pathFinder.removeObstacle({0, 0});
blocks[mapWidth * mapHeight - 1] = 0; blocks[mapWidth * mapHeight - 1] = 0;
pathFinder.removeObstacle({mapWidth - 1, mapHeight - 1});
std::function<bool(AStar::Vec2i)> isWalkable = [&blocks, mapWidth, mapHeight](AStar::Vec2i pos) {
if (pos.x < 0 || pos.x >= mapWidth || pos.y < 0 || pos.y >= mapHeight) {
return false;
}
return blocks[pos.x + pos.y * mapWidth] == 0;
};
pathFinder.setHeuristic(AStar::Heuristic::manhattan); pathFinder.setHeuristic(AStar::Heuristic::manhattan);
auto start1 = std::chrono::high_resolution_clock::now(); auto start1 = std::chrono::high_resolution_clock::now();
auto path = pathFinder.findPath({0, 0}, {mapWidth - 1, mapHeight - 1}); auto path = pathFinder.findPath({0, 0}, {mapWidth - 1, mapHeight - 1}, {mapWidth, mapHeight}, isWalkable);
auto stop1 = std::chrono::high_resolution_clock::now(); auto stop1 = std::chrono::high_resolution_clock::now();
if (path.empty()) { if (path.empty()) {
std::cout << "Path not found" << std::endl; std::cout << "Path not found" << std::endl;
@@ -134,7 +135,7 @@ auto main() -> int {
} }
pathFinder.setHeuristic(AStar::Heuristic::euclidean); pathFinder.setHeuristic(AStar::Heuristic::euclidean);
path = pathFinder.findPath({0, 0}, {mapWidth - 1, mapHeight - 1}); path = pathFinder.findPath({0, 0}, {mapWidth - 1, mapHeight - 1}, {mapWidth, mapHeight}, isWalkable);
euclideanPathSize = path.size(); euclideanPathSize = path.size();
for (auto& i : path) { for (auto& i : path) {
@@ -143,7 +144,7 @@ auto main() -> int {
} }
pathFinder.setHeuristic(AStar::Heuristic::octagonal); pathFinder.setHeuristic(AStar::Heuristic::octagonal);
path = pathFinder.findPath({0, 0}, {mapWidth - 1, mapHeight - 1}); path = pathFinder.findPath({0, 0}, {mapWidth - 1, mapHeight - 1}, {mapWidth, mapHeight}, isWalkable);
octagonalPathSize = path.size(); octagonalPathSize = path.size();
for (auto& i : path) { for (auto& i : path) {
@@ -152,7 +153,7 @@ auto main() -> int {
} }
pathFinder.setHeuristic(AStar::Heuristic::chebyshev); pathFinder.setHeuristic(AStar::Heuristic::chebyshev);
path = pathFinder.findPath({0, 0}, {mapWidth - 1, mapHeight - 1}); path = pathFinder.findPath({0, 0}, {mapWidth - 1, mapHeight - 1}, {mapWidth, mapHeight}, isWalkable);
chebyshevPathSize = path.size(); chebyshevPathSize = path.size();
for (auto& i : path) { for (auto& i : path) {
@@ -161,7 +162,7 @@ auto main() -> int {
} }
pathFinder.setHeuristic(AStar::Heuristic::euclideanNoSQR); pathFinder.setHeuristic(AStar::Heuristic::euclideanNoSQR);
path = pathFinder.findPath({0, 0}, {mapWidth - 1, mapHeight - 1}); path = pathFinder.findPath({0, 0}, {mapWidth - 1, mapHeight - 1}, {mapWidth, mapHeight}, isWalkable);
euclideanNoSQRPathSize = path.size(); euclideanNoSQRPathSize = path.size();
for (auto& i : path) { for (auto& i : path) {
@@ -170,7 +171,7 @@ auto main() -> int {
} }
pathFinder.setHeuristic(AStar::Heuristic::dijkstra); pathFinder.setHeuristic(AStar::Heuristic::dijkstra);
path = pathFinder.findPath({0, 0}, {mapWidth - 1, mapHeight - 1}); path = pathFinder.findPath({0, 0}, {mapWidth - 1, mapHeight - 1}, {mapWidth, mapHeight}, isWalkable);
dijkstraPathSize = path.size(); dijkstraPathSize = path.size();
for (auto& i : path) { for (auto& i : path) {
+8 -7
View File
@@ -53,7 +53,6 @@ auto main() -> int {
generator_2.setMultiplier((uint32_t)multiplier); generator_2.setMultiplier((uint32_t)multiplier);
AStar::AStar<uint32_t, true> pathFinder; AStar::AStar<uint32_t, true> pathFinder;
pathFinder.setWorldSize({mapWidth, mapHeight});
pathFinder.setHeuristic(AStar::Heuristic::manhattan); pathFinder.setHeuristic(AStar::Heuristic::manhattan);
pathFinder.setDiagonalMovement(true); pathFinder.setDiagonalMovement(true);
@@ -90,8 +89,6 @@ auto main() -> int {
generator_2.setWeightedStrength(weighted_strength); generator_2.setWeightedStrength(weighted_strength);
generator_2.setMultiplier((uint32_t)multiplier); generator_2.setMultiplier((uint32_t)multiplier);
pathFinder.clear();
heightmap = generator_2.generate2dMeightmap(0, 0, 0, screenWidth, 0, screenHeight); heightmap = generator_2.generate2dMeightmap(0, 0, 0, screenWidth, 0, screenHeight);
for (uint64_t x = 0; x < mapWidth; x++) { for (uint64_t x = 0; x < mapWidth; x++) {
@@ -103,14 +100,11 @@ auto main() -> int {
blocks[index] = 0; blocks[index] = 0;
} else { } else {
blocks[index] = 1; blocks[index] = 1;
pathFinder.addObstacle({static_cast<int32_t>(x), static_cast<int32_t>(y)});
} }
} }
} }
blocks[0] = 0; blocks[0] = 0;
pathFinder.removeObstacle({0, 0});
blocks[mapWidth * mapHeight - 1] = 0; blocks[mapWidth * mapHeight - 1] = 0;
pathFinder.removeObstacle({mapWidth - 1, mapHeight - 1});
pathFinder.setHeuristic(AStar::Heuristic::euclidean); pathFinder.setHeuristic(AStar::Heuristic::euclidean);
@@ -128,8 +122,15 @@ auto main() -> int {
pathFinder.setDebugOpenNode(debugOpenNode); pathFinder.setDebugOpenNode(debugOpenNode);
std::function<bool(AStar::Vec2i)> isWalkable = [&blocks, mapWidth, mapHeight](AStar::Vec2i pos) {
if (pos.x < 0 || pos.x >= mapWidth || pos.y < 0 || pos.y >= mapHeight) {
return false;
}
return blocks[pos.x + pos.y * mapWidth] == 0;
};
auto start1 = std::chrono::high_resolution_clock::now(); auto start1 = std::chrono::high_resolution_clock::now();
auto path = pathFinder.findPath({0, 0}, {mapWidth - 1, mapHeight - 1}); auto path = pathFinder.findPath({0, 0}, {mapWidth - 1, mapHeight - 1}, {mapWidth, mapHeight}, isWalkable);
auto stop1 = std::chrono::high_resolution_clock::now(); auto stop1 = std::chrono::high_resolution_clock::now();
if (path.empty()) { if (path.empty()) {
std::cout << "Path not found" << std::endl; std::cout << "Path not found" << std::endl;
+36 -11
View File
@@ -6,15 +6,23 @@ TEST(AStar, basic_path_1) {
int mapWidth = 4; int mapWidth = 4;
int mapHeight = 4; int mapHeight = 4;
AStar::AStar pathFinder; AStar::AStar pathFinder;
pathFinder.setWorldSize({mapWidth, mapWidth});
pathFinder.setHeuristic(AStar::Heuristic::euclidean); pathFinder.setHeuristic(AStar::Heuristic::euclidean);
pathFinder.setDiagonalMovement(true); pathFinder.setDiagonalMovement(true);
AStar::Vec2i source(0, 0); AStar::Vec2i source(0, 0);
AStar::Vec2i target(mapWidth - 1, mapHeight - 1); AStar::Vec2i target(mapWidth - 1, mapHeight - 1);
std::function<bool(AStar::Vec2i)> isWalkable = [&pathFinder](AStar::Vec2i pos) {
if (pos.x < 0 || pos.x >= 4 || pos.y < 0 || pos.y >= 4) {
return false;
}
return true;
};
std::cout << "AStar::AStar pathFinder;" << std::endl; std::cout << "AStar::AStar pathFinder;" << std::endl;
auto path = pathFinder.findPath(source, target); auto path = pathFinder.findPath(source, target, {mapWidth, mapHeight}, isWalkable);
EXPECT_EQ(path.size(), 4); EXPECT_EQ(path.size(), 4);
@@ -28,14 +36,20 @@ TEST(AStar, basic_path_2) {
int mapWidth = 10; int mapWidth = 10;
int mapHeight = 10; int mapHeight = 10;
AStar::AStar pathFinder; AStar::AStar pathFinder;
pathFinder.setWorldSize({mapWidth, mapWidth});
pathFinder.setHeuristic(AStar::Heuristic::euclidean); pathFinder.setHeuristic(AStar::Heuristic::euclidean);
pathFinder.setDiagonalMovement(true); pathFinder.setDiagonalMovement(true);
AStar::Vec2i source(0, 0); AStar::Vec2i source(0, 0);
AStar::Vec2i target(mapWidth - 1, mapHeight - 1); AStar::Vec2i target(mapWidth - 1, mapHeight - 1);
auto path = pathFinder.findPath(source, target); std::function<bool(AStar::Vec2i)> isWalkable = [&pathFinder](AStar::Vec2i pos) {
if (pos.x < 0 || pos.x >= 10 || pos.y < 0 || pos.y >= 10) {
return false;
}
return true;
};
auto path = pathFinder.findPath(source, target, {mapWidth, mapHeight}, isWalkable);
EXPECT_EQ(path.size(), 10); EXPECT_EQ(path.size(), 10);
@@ -49,14 +63,20 @@ TEST(AStar, basic_diagonal_path_wrong_1) {
int mapWidth = 10; int mapWidth = 10;
int mapHeight = 10; int mapHeight = 10;
AStar::AStar pathFinder; AStar::AStar pathFinder;
pathFinder.setWorldSize({mapWidth, mapHeight});
pathFinder.setHeuristic(AStar::Heuristic::euclidean); pathFinder.setHeuristic(AStar::Heuristic::euclidean);
pathFinder.setDiagonalMovement(true); pathFinder.setDiagonalMovement(true);
AStar::Vec2i source(0, 0); AStar::Vec2i source(0, 0);
AStar::Vec2i target(19, 19); AStar::Vec2i target(19, 19);
auto path = pathFinder.findPath(source, target); std::function<bool(AStar::Vec2i)> isWalkable = [&pathFinder](AStar::Vec2i pos) {
if (pos.x < 0 || pos.x >= 10 || pos.y < 0 || pos.y >= 10) {
return false;
}
return true;
};
auto path = pathFinder.findPath(source, target, {10, 10}, isWalkable);
EXPECT_EQ(path.size(), 0); EXPECT_EQ(path.size(), 0);
} }
@@ -65,18 +85,23 @@ TEST(AStar, basic_diagonal_path_wrong_2) {
int mapWidth = 10; int mapWidth = 10;
int mapHeight = 10; int mapHeight = 10;
AStar::AStar pathFinder; AStar::AStar pathFinder;
pathFinder.setWorldSize({mapWidth, mapHeight});
pathFinder.setHeuristic(AStar::Heuristic::euclidean); pathFinder.setHeuristic(AStar::Heuristic::euclidean);
pathFinder.setDiagonalMovement(true); pathFinder.setDiagonalMovement(true);
pathFinder.addObstacle({0, 1}); std::function<bool(AStar::Vec2i)> isWalkable = [&pathFinder](AStar::Vec2i pos) {
pathFinder.addObstacle({1, 1}); if (pos.x < 0 || pos.x >= 10 || pos.y < 0 || pos.y >= 10) {
pathFinder.addObstacle({1, 0}); return false;
}
if ((pos.x == 0 && pos.y == 1) || (pos.x == 1 && pos.y == 1) || (pos.x == 1 && pos.y == 0)) {
return false;
}
return true;
};
AStar::Vec2i source(0, 0); AStar::Vec2i source(0, 0);
AStar::Vec2i target(9, 9); AStar::Vec2i target(9, 9);
auto path = pathFinder.findPath(source, target); auto path = pathFinder.findPath(source, target, {10, 10}, isWalkable);
EXPECT_EQ(path.size(), 0); EXPECT_EQ(path.size(), 0);
} }