dungeon/src/Pathfinder.cpp

197 lines
5.1 KiB
C++
Raw Permalink Normal View History

2017-09-17 20:07:38 +02:00
#include <math.h>
2017-09-17 13:43:13 +02:00
#include "Pathfinder.h"
#include "Tilemap.h"
2018-01-09 21:59:05 +01:00
#include <queue>
2017-09-17 13:43:13 +02:00
namespace Pathfinder
{
float distance(vec2i a, vec2i b)
{
float dx = a.x - b.x;
float dy = a.y - b.y;
return sqrtf(dx*dx + dy*dy);
}
2018-01-09 21:59:05 +01:00
std::vector<vec2i> a_star(Tilemap * map, vec2i start, vec2i goal)
2017-09-17 13:43:13 +02:00
{
std::vector<AStarNode*> open;
std::vector<AStarNode*> closed;
std::vector<vec2i> path;
AStarNode* st = new AStarNode();
st->pos = start;
open.emplace_back(st);
2017-09-17 13:43:13 +02:00
while (open.size() != 0) {
2017-09-17 13:43:13 +02:00
AStarNode* current = nullptr;
int currentindex = -1;
for (int i = 0; i < open.size(); i++) {
if (current == nullptr || current->f > open[i]->f) {
2017-09-17 13:43:13 +02:00
current = open[i];
currentindex = i;
}
}
open.erase(open.begin()+currentindex);
closed.emplace_back(current);
2017-09-17 13:43:13 +02:00
auto neighbours = map->get_neighbours(current->pos.x, current->pos.y);
for (auto pos : neighbours) {
2018-01-09 21:59:05 +01:00
if (!map->get_tile(pos.x, pos.y).passable) {
2017-09-17 13:43:13 +02:00
continue;
}
AStarNode* neighbour = new AStarNode();
neighbour->pos = current->pos;
neighbour->pos.x = pos.x;
neighbour->pos.y = pos.y;
neighbour->from = current;
neighbour->g = current->g + 1;
neighbour->h = distance(neighbour->pos, goal);
neighbour->f = neighbour->g + neighbour->h;
// Is this the goal?
if (neighbour->pos == goal)
{
delete neighbour;
path.emplace_back(goal);
2017-09-17 13:43:13 +02:00
while (current->from != nullptr)
{
path.emplace_back(current->pos);
2017-09-17 13:43:13 +02:00
current = current->from;
}
2017-09-17 20:07:38 +02:00
for (AStarNode* var : open)
2017-09-17 13:43:13 +02:00
{
delete var;
}
2017-09-17 20:07:38 +02:00
for (AStarNode* var : closed)
2017-09-17 13:43:13 +02:00
{
delete var;
}
return path;
}
// Check if the new node is in the closed list
bool isClosed = false;
for (auto it = closed.begin(); it != closed.end(); it++)
{
AStarNode* n = *it;
if (n->pos == neighbour->pos)
{
isClosed = true;
if (n->h > neighbour->h)
{
closed.erase(it);
delete (*it);
open.emplace_back(neighbour);
2017-09-17 13:43:13 +02:00
isClosed = false;
}
break;
}
}
if (!isClosed)
{
// Check if the new node is in the open list
bool isOpened = false;
for (auto it = open.begin(); it != open.end(); it++)
{
AStarNode* n = *it;
if (n->pos == neighbour->pos)
{
isOpened = true;
if (n->h > neighbour->h)
{
open.erase(it);
delete (*it);
open.emplace_back(neighbour);
2017-09-17 13:43:13 +02:00
}
break;
}
}
if (!isOpened)
{
open.emplace_back(neighbour);
2017-09-17 13:43:13 +02:00
}
}
else
{
delete neighbour;
}
}
for (auto it = open.begin(); it != open.end(); it++)
{
if (current == (*it))
{
open.erase(it);
delete (*it);
break;
}
}
}
2017-09-17 20:07:38 +02:00
for (AStarNode* var : open)
2017-09-17 13:43:13 +02:00
{
delete var;
}
2017-09-17 20:07:38 +02:00
for (AStarNode* var : closed)
2017-09-17 13:43:13 +02:00
{
delete var;
}
return path;
}
2018-01-09 21:59:05 +01:00
void calc_dijkstra_map(Tilemap& map, std::vector<vec2i>& goals, DijkstraMap& out, float maxValue) {
if (out.tilemap != nullptr) {
delete out.tilemap;
2017-09-17 13:43:13 +02:00
}
2018-01-09 21:59:05 +01:00
out.tilemap = new float[map.get_width() * map.get_height()];
for (int i = 0; i < map.get_width() * map.get_height(); i++) {
out.tilemap[i] = maxValue;
2017-09-17 13:43:13 +02:00
}
2018-01-09 21:59:05 +01:00
out.height = map.get_height();
out.width = map.get_width();
for (vec2i& pos : goals) {
out.setValue(pos.x, pos.y, 0);
2017-09-17 13:43:13 +02:00
}
2018-01-09 21:59:05 +01:00
std::queue<vec2i> queue;
2017-09-17 13:43:13 +02:00
2018-01-09 21:59:05 +01:00
for (vec2i& pos : goals) {
auto neigh = map.get_neighbours(pos.x, pos.y);
for (vec2i& npos : neigh) {
int val = out.get_value(npos.x, npos.y);
if (map.get_tile(npos.x, npos.y).passable && val > 1.4f) {
2017-09-17 13:43:13 +02:00
if (npos.x != 0 && npos.y != 0) {
2018-01-09 21:59:05 +01:00
out.setValue(npos.x, npos.y, 1.4f);
2017-09-17 13:43:13 +02:00
}
else {
2018-01-09 21:59:05 +01:00
out.setValue(npos.x, npos.y, 1);
2017-09-17 13:43:13 +02:00
}
2018-01-09 21:59:05 +01:00
queue.push(npos);
2017-09-17 13:43:13 +02:00
}
}
}
while (queue.size() > 0) {
2018-01-09 21:59:05 +01:00
vec2i current = queue.front();
float val = out.get_value(current.x, current.y);
queue.pop();
2017-09-17 13:43:13 +02:00
2018-01-09 21:59:05 +01:00
std::vector<vec2i> neigh = map.get_neighbours(current.x, current.y);
for (vec2i& npos : neigh) {
2017-09-17 13:43:13 +02:00
vec2i dp = npos - current;
2018-01-09 21:59:05 +01:00
float nval = val + 1;
2017-09-17 13:43:13 +02:00
if (dp.x != 0 && dp.y != 0) {
2018-01-09 21:59:05 +01:00
nval += .4f;
2017-09-17 13:43:13 +02:00
}
2018-01-09 21:59:05 +01:00
if (map.get_tile(npos.x, npos.y).passable && out.get_value(npos.x, npos.y) > nval) {
out.setValue(npos.x, npos.y, nval);
queue.push(npos);
2017-09-17 13:43:13 +02:00
}
}
}
return;
}
}