mirror of
https://github.com/vcmi/vcmi.git
synced 2025-07-15 01:24:45 +02:00
New pathfinder by Spasarto
This commit is contained in:
@ -308,7 +308,15 @@ void CTerrainRect::clickLeft(tribool down)
|
||||
int3 bufpos = currentHero->getPosition(false);
|
||||
//bufpos.x-=1;
|
||||
if (mres)
|
||||
currentPath = LOCPLINT->adventureInt->heroList.items[LOCPLINT->adventureInt->heroList.selected].second = CGI->pathf->getPath(bufpos,mp,currentHero,1);
|
||||
{
|
||||
vector<Coordinate>* p;
|
||||
p = CGI->pathf->GetPath(Coordinate(bufpos),Coordinate(mp),currentHero);
|
||||
|
||||
//Convert to old format.
|
||||
currentPath = LOCPLINT->adventureInt->heroList.items[LOCPLINT->adventureInt->heroList.selected].second = CGI->pathf->ConvertToOldFormat(p);
|
||||
|
||||
//currentPath = LOCPLINT->adventureInt->heroList.items[LOCPLINT->adventureInt->heroList.selected].second = CGI->pathf->getPath(bufpos,mp,currentHero,1);
|
||||
}
|
||||
}
|
||||
void CTerrainRect::clickRight(tribool down)
|
||||
{
|
||||
|
@ -61,13 +61,16 @@ int internalFunc(void * callback)
|
||||
}
|
||||
std::cout<<"\rExtracting done :)\n";
|
||||
}
|
||||
|
||||
vector<Coordinate>* p;
|
||||
switch (*cn.c_str())
|
||||
{
|
||||
case 'P':
|
||||
std::cout<<"Policzyc sciezke."<<std::endl;
|
||||
readed>>src>>dst;
|
||||
LOCPLINT->adventureInt->terrain.currentPath = CGI->pathf->getPath(src,dst,CGI->heroh->heroInstances[0]);
|
||||
|
||||
p = CGI->pathf->GetPath(Coordinate(src),Coordinate(dst),CGI->heroh->heroInstances[0]);
|
||||
LOCPLINT->adventureInt->terrain.currentPath = CGI->pathf->ConvertToOldFormat(p);
|
||||
//LOCPLINT->adventureInt->terrain.currentPath = CGI->pathf->getPath(src,dst,CGI->heroh->heroInstances[0]);
|
||||
break;
|
||||
case 'm': //number of heroes
|
||||
std::cout<<"Number of heroes: "<<CGI->heroh->heroInstances.size()<<std::endl;
|
||||
@ -80,9 +83,9 @@ int internalFunc(void * callback)
|
||||
{
|
||||
readed>>heronum>>dest;
|
||||
const CGHeroInstance * hero = cb->getHeroInfo(0,heronum,0);
|
||||
CPath * path = CGI->pathf->getPath(hero->getPosition(false),dest,hero);
|
||||
cb->moveHero(heronum, path, 0, 0);
|
||||
delete path;
|
||||
p = CGI->pathf->GetPath(Coordinate(hero->getPosition(false)),Coordinate(dest),hero);
|
||||
cb->moveHero(heronum, CGI->pathf->ConvertToOldFormat(p), 0, 0);
|
||||
//LOCPLINT->adventureInt->terrain.currentPath = CGI->pathf->getPath(src,dst,CGI->heroh->heroInstances[0]);
|
||||
break;
|
||||
}
|
||||
case 'D': //pos description
|
||||
@ -127,6 +130,7 @@ int internalFunc(void * callback)
|
||||
break;
|
||||
}
|
||||
//SDL_Delay(100);
|
||||
delete p;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
428
CPathfinder.cpp
428
CPathfinder.cpp
@ -5,33 +5,41 @@
|
||||
#include "hch\CAmbarCendamo.h"
|
||||
#include "mapHandler.h"
|
||||
#include "CGameState.h"
|
||||
using namespace boost::logic;
|
||||
int3 CPath::startPos()
|
||||
|
||||
using namespace std;
|
||||
|
||||
vector<Coordinate>* CPathfinder::GetPath(Coordinate start, Coordinate end, const CGHeroInstance* hero)
|
||||
{
|
||||
return int3(nodes[nodes.size()-1].coord.x,nodes[nodes.size()-1].coord.y,nodes[nodes.size()-1].coord.z);
|
||||
}
|
||||
int3 CPath::endPos()
|
||||
{
|
||||
return int3(nodes[0].coord.x,nodes[0].coord.y,nodes[0].coord.z);
|
||||
Start = start;
|
||||
End = end;
|
||||
return GetPath(hero);
|
||||
}
|
||||
|
||||
CPath * CPathfinder::getPath(int3 src, int3 dest, const CGHeroInstance * hero, unsigned char type) //TODO: test it (seems to be finished, but relies on unwritten functions :()
|
||||
/*
|
||||
* Does basic input checking and setup for the path calculation.
|
||||
*/
|
||||
vector<Coordinate>* CPathfinder::GetPath(const CGHeroInstance* hero)
|
||||
{
|
||||
//check input
|
||||
if ((src.x < 0)||(src.y < 0)||(src.z < 0)||(dest.x < 0)||(dest.y < 0)||(dest.z < 0))
|
||||
if ((Start.x < 0)||(Start.y < 0)||(Start.z < 0)||(End.x < 0)||(End.y < 0)||(End.z < 0))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
if ((src.x >= CGI->mh->sizes.x)||(src.y >= CGI->mh->sizes.y)||(src.z >= CGI->mh->sizes.z)
|
||||
||(dest.x >= CGI->mh->sizes.x)||(dest.y >= CGI->mh->sizes.y)||(dest.z >= CGI->mh->sizes.z))
|
||||
if ((Start.x >= CGI->mh->sizes.x)||(Start.y >= CGI->mh->sizes.y)||(Start.z >= CGI->mh->sizes.z)
|
||||
||(End.x >= CGI->mh->sizes.x)||(End.y >= CGI->mh->sizes.y)||(End.z >= CGI->mh->sizes.z))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int3 hpos = hero->getPosition(false);
|
||||
Hero = hero;
|
||||
|
||||
tribool blockLandSea; //true - blocks sea, false - blocks land, indeterminate - allows all
|
||||
if (!hero->canWalkOnSea())
|
||||
//Reset the queues
|
||||
Open = priority_queue < vector<Coordinate>, vector<vector<Coordinate>>, Compare>();
|
||||
Closed.clear();
|
||||
|
||||
//Determine if the hero can move on water
|
||||
int3 hpos = Hero->getPosition(false);
|
||||
if (!Hero->canWalkOnSea())
|
||||
{
|
||||
if (CGI->mh->ttiles[hpos.x][hpos.y][hpos.z].terType==EterrainType::water)
|
||||
blockLandSea=false;
|
||||
@ -43,153 +51,249 @@ CPath * CPathfinder::getPath(int3 src, int3 dest, const CGHeroInstance * hero, u
|
||||
blockLandSea = indeterminate;
|
||||
}
|
||||
|
||||
//graph initialization
|
||||
graph.resize(CGI->ac->map.width);
|
||||
for(int i=0; i<graph.size(); ++i)
|
||||
CalcG(&Start);
|
||||
Start.h = 0;
|
||||
CalcG(&End);
|
||||
CalcH(&End);
|
||||
|
||||
//If it is impossible to get to where the user clicked, dont return a path.
|
||||
if(End.h == -1)
|
||||
{
|
||||
graph[i].resize(CGI->ac->map.height);
|
||||
for(int j=0; j<graph[i].size(); ++j)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//Add the Start node to the open list.
|
||||
vector<Coordinate> startPath;
|
||||
startPath.push_back(Start);
|
||||
Open.push(startPath);
|
||||
|
||||
//Calculate the path.
|
||||
vector<Coordinate>* toReturn = CalcPath();
|
||||
|
||||
if(toReturn != NULL)
|
||||
{
|
||||
graph[i][j].accesible = !CGI->mh->ttiles[i][j][src.z].blocked;
|
||||
if(i==dest.x && j==dest.y && CGI->mh->ttiles[i][j][src.z].visitable)
|
||||
graph[i][j].accesible = true; //for allowing visiting objects
|
||||
graph[i][j].dist = -1;
|
||||
graph[i][j].theNodeBefore = NULL;
|
||||
graph[i][j].visited = false;
|
||||
graph[i][j].coord.x = i;
|
||||
graph[i][j].coord.y = j;
|
||||
graph[i][j].coord.z = dest.z;
|
||||
if (CGI->mh->ttiles[i][j][src.z].terType==EterrainType::rock)
|
||||
graph[i][j].accesible = false;
|
||||
if ((blockLandSea) && (CGI->mh->ttiles[i][j][src.z].terType==EterrainType::water))
|
||||
graph[i][j].accesible = false;
|
||||
else if ((!blockLandSea) && (CGI->mh->ttiles[i][j][src.z].terType!=EterrainType::water))
|
||||
graph[i][j].accesible = false;
|
||||
if(graph[i][j].accesible)
|
||||
graph[i][j].accesible = CGI->state->players[hero->tempOwner].fogOfWarMap[i][j][src.z];
|
||||
//Flip the route since it is calculated in reverse
|
||||
int size = toReturn->size();
|
||||
for(int i = 0; i < size/2; i++)
|
||||
{
|
||||
Coordinate t = toReturn->at(i);
|
||||
(*toReturn)[i] = toReturn->at(size-1-i);
|
||||
(*toReturn)[size-1-i] = t;
|
||||
}
|
||||
}
|
||||
|
||||
//graph initialized
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
graph[src.x][src.y].dist = 0;
|
||||
|
||||
std::queue<CPathNode> mq;
|
||||
mq.push(graph[src.x][src.y]);
|
||||
|
||||
unsigned int curDist = 4000000000;
|
||||
|
||||
while(!mq.empty())
|
||||
/*
|
||||
* Does the actual path calculation. Don't call this directly, call GetPath instead.
|
||||
*/
|
||||
vector<Coordinate>* CPathfinder::CalcPath()
|
||||
{
|
||||
CPathNode cp = mq.front();
|
||||
mq.pop();
|
||||
if ((cp.coord.x == dest.x) && (cp.coord.y==dest.y))
|
||||
if(Open.empty())
|
||||
{
|
||||
if (cp.dist < curDist)
|
||||
curDist=cp.dist;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//Find the path in open with the smallest cost (f = g + h)
|
||||
//and remove it from open
|
||||
vector<Coordinate>* branch = new vector<Coordinate>();
|
||||
*branch = Open.top();
|
||||
Open.pop();
|
||||
|
||||
//Don't search elements in the closed list, for they have been visited already.
|
||||
if(!ExistsInClosed(branch->back()))
|
||||
{
|
||||
//Add it to the closed list.
|
||||
Closed.push_back(branch->back());
|
||||
|
||||
//If it is the destination
|
||||
if(branch->back().x == End.x && branch->back().y == End.y && branch->back().z == End.z)
|
||||
{
|
||||
return branch;
|
||||
}
|
||||
|
||||
//Add neighbors to the open list
|
||||
AddNeighbors(branch);
|
||||
}
|
||||
delete branch;
|
||||
|
||||
return CalcPath();
|
||||
}
|
||||
|
||||
/*
|
||||
* Determines if the given node exists in the closed list, returns true if it does. This is
|
||||
* used to ensure you dont check the same node twice.
|
||||
*/
|
||||
bool CPathfinder::ExistsInClosed(Coordinate node)
|
||||
{
|
||||
for(int i = 0; i < Closed.size(); i++)
|
||||
{
|
||||
if(node.x == Closed[i].x && node.y == Closed[i].y && node.z == Closed[i].z)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Adds the neighbors of the current node to the open cue so they can be considered in the
|
||||
* path creation. If the node has a cost (f = g + h) less than zero, it isn't added to Open.
|
||||
*/
|
||||
void CPathfinder::AddNeighbors(vector<Coordinate>* branch)
|
||||
{
|
||||
//8 possible Nodes to add
|
||||
//
|
||||
// 1 2 3
|
||||
// 4 X 5
|
||||
// 6 7 8
|
||||
|
||||
Coordinate node = branch->back();
|
||||
Coordinate* c;
|
||||
|
||||
for(int i = node.x-1; i<node.x+2;i++)
|
||||
{
|
||||
for(int j = node.y-1; j < node.y+2; j++)
|
||||
{
|
||||
if(i > 0 && j > 0 && i < CGI->mh->sizes.x-1 && j < CGI->mh->sizes.y-1)
|
||||
{
|
||||
c = new Coordinate(i,j,node.z);
|
||||
|
||||
//Calculate the distance from the end node
|
||||
CalcG(c);
|
||||
|
||||
//Calculate the movement cost
|
||||
CalcH(c);
|
||||
|
||||
if(c->g != -1 && c->h != -1)
|
||||
{
|
||||
vector<Coordinate> toAdd = *branch;
|
||||
toAdd.push_back(*c);
|
||||
Open.push(toAdd);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete c;
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculates the movement cost of the node. Returns -1 if it is impossible to travel on.
|
||||
*/
|
||||
void CPathfinder::CalcH(Coordinate* node)
|
||||
{
|
||||
/*
|
||||
* If the terrain is blocked
|
||||
* If the terrain is rock
|
||||
* If the Hero cant walk on water and node is in water
|
||||
* If the Hero is on water and the node is not.
|
||||
* If there is fog of war on the node.
|
||||
* => Impossible to move there.
|
||||
*/
|
||||
if( (CGI->mh->ttiles[node->x][node->y][node->z].blocked && !(node->x==End.x && node->y==End.y && CGI->mh->ttiles[node->x][node->y][node->z].visitable)) ||
|
||||
(CGI->mh->ttiles[node->x][node->y][node->z].terType==EterrainType::rock) ||
|
||||
((blockLandSea) && (CGI->mh->ttiles[node->x][node->y][node->z].terType==EterrainType::water)) ||
|
||||
(!CGI->state->players[Hero->tempOwner].fogOfWarMap[node->x][node->y][node->z]) ||
|
||||
((!blockLandSea) && (CGI->mh->ttiles[node->x][node->y][node->z].terType!=EterrainType::water)))
|
||||
{
|
||||
//Impossible.
|
||||
|
||||
node->h = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
int ret=-1;
|
||||
int x = node->x;
|
||||
int y = node->y;
|
||||
if(node->x>=CGI->mh->reader->map.width)
|
||||
x = CGI->mh->reader->map.width-1;
|
||||
if(node->y>=CGI->mh->reader->map.height)
|
||||
y = CGI->mh->reader->map.height-1;
|
||||
|
||||
//Get a copy of the hero we can work with. Cant use const Hero because method is not static.
|
||||
CGHeroInstance* tempHero = new CGHeroInstance();
|
||||
*tempHero = *Hero;
|
||||
|
||||
//Get the movement cost.
|
||||
ret = tempHero->getTileCost(CGI->mh->ttiles[x][y][node->z].terType, CGI->mh->reader->map.terrain[x][y].malle,CGI->mh->reader->map.terrain[x][y].nuine);
|
||||
|
||||
//Is this right? This part of the code was stolen from getCost and I wasnt sure what parameters
|
||||
//a and b represented. Seems to work though.
|
||||
if(!(node->x==End.x || node->y==End.y))
|
||||
ret*=1.41421;
|
||||
|
||||
delete tempHero;
|
||||
|
||||
node->h = ret;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculates distance from node to end node.
|
||||
*/
|
||||
void CPathfinder::CalcG(Coordinate* node)
|
||||
{
|
||||
float dist = (End.x-node->x) * (End.x-node->x) + (End.y-node->y) * (End.y-node->y);
|
||||
node->g = sqrt(dist);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Converts the old Pathfinder format for compatibility reasons. This should be replaced
|
||||
* eventually by making the need for it obsolete.
|
||||
*/
|
||||
CPath* CPathfinder::ConvertToOldFormat(vector<Coordinate>* p)
|
||||
{
|
||||
if(p == NULL)
|
||||
return NULL;
|
||||
|
||||
CPath* path = new CPath();
|
||||
|
||||
vector<CPathNode> pNodes;
|
||||
|
||||
for(int i = 0; i < p->size(); i++)
|
||||
{
|
||||
CPathNode temp;
|
||||
|
||||
//Set accesible
|
||||
if(p->at(i).h == -1)
|
||||
{
|
||||
temp.accesible = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (cp.dist > curDist)
|
||||
continue;
|
||||
}
|
||||
if(cp.coord.x>0)
|
||||
{
|
||||
CPathNode & dp = graph[cp.coord.x-1][cp.coord.y];
|
||||
if((dp.dist==-1 || (dp.dist > cp.dist + CGI->mh->getCost(int3(cp.coord.x, cp.coord.y, src.z), int3(cp.coord.x-1, cp.coord.y, src.z), hero))) && dp.accesible)
|
||||
{
|
||||
dp.dist = cp.dist + CGI->mh->getCost(int3(cp.coord.x, cp.coord.y, src.z), int3(cp.coord.x-1, cp.coord.y, src.z), hero);
|
||||
dp.theNodeBefore = &graph[cp.coord.x][cp.coord.y];
|
||||
mq.push(dp);
|
||||
}
|
||||
}
|
||||
if(cp.coord.y>0)
|
||||
{
|
||||
CPathNode & dp = graph[cp.coord.x][cp.coord.y-1];
|
||||
if((dp.dist==-1 || (dp.dist > cp.dist + CGI->mh->getCost(int3(cp.coord.x, cp.coord.y, src.z), int3(cp.coord.x, cp.coord.y-1, src.z), hero))) && dp.accesible)
|
||||
{
|
||||
dp.dist = cp.dist + CGI->mh->getCost(int3(cp.coord.x, cp.coord.y, src.z), int3(cp.coord.x-1, cp.coord.y, src.z), hero);
|
||||
dp.theNodeBefore = &graph[cp.coord.x][cp.coord.y];
|
||||
mq.push(dp);
|
||||
}
|
||||
}
|
||||
if(cp.coord.x>0 && cp.coord.y>0)
|
||||
{
|
||||
CPathNode & dp = graph[cp.coord.x-1][cp.coord.y-1];
|
||||
if((dp.dist==-1 || (dp.dist > cp.dist + CGI->mh->getCost(int3(cp.coord.x, cp.coord.y, src.z), int3(cp.coord.x-1, cp.coord.y-1, src.z), hero))) && dp.accesible)
|
||||
{
|
||||
dp.dist = cp.dist + CGI->mh->getCost(int3(cp.coord.x, cp.coord.y, src.z), int3(cp.coord.x-1, cp.coord.y-1, src.z), hero);
|
||||
dp.theNodeBefore = &graph[cp.coord.x][cp.coord.y];
|
||||
mq.push(dp);
|
||||
}
|
||||
}
|
||||
if(cp.coord.x<graph.size()-1)
|
||||
{
|
||||
CPathNode & dp = graph[cp.coord.x+1][cp.coord.y];
|
||||
if((dp.dist==-1 || (dp.dist > cp.dist + CGI->mh->getCost(int3(cp.coord.x, cp.coord.y, src.z), int3(cp.coord.x+1, cp.coord.y, src.z), hero))) && dp.accesible)
|
||||
{
|
||||
dp.dist = cp.dist + CGI->mh->getCost(int3(cp.coord.x, cp.coord.y, src.z), int3(cp.coord.x+1, cp.coord.y, src.z), hero);
|
||||
dp.theNodeBefore = &graph[cp.coord.x][cp.coord.y];
|
||||
mq.push(dp);
|
||||
}
|
||||
}
|
||||
if(cp.coord.y<graph[0].size()-1)
|
||||
{
|
||||
CPathNode & dp = graph[cp.coord.x][cp.coord.y+1];
|
||||
if((dp.dist==-1 || (dp.dist > cp.dist + CGI->mh->getCost(int3(cp.coord.x, cp.coord.y, src.z), int3(cp.coord.x, cp.coord.y+1, src.z), hero))) && dp.accesible)
|
||||
{
|
||||
dp.dist = cp.dist + CGI->mh->getCost(int3(cp.coord.x, cp.coord.y, src.z), int3(cp.coord.x, cp.coord.y+1, src.z), hero);
|
||||
dp.theNodeBefore = &graph[cp.coord.x][cp.coord.y];
|
||||
mq.push(dp);
|
||||
}
|
||||
}
|
||||
if(cp.coord.x<graph.size()-1 && cp.coord.y<graph[0].size()-1)
|
||||
{
|
||||
CPathNode & dp = graph[cp.coord.x+1][cp.coord.y+1];
|
||||
if((dp.dist==-1 || (dp.dist > cp.dist + CGI->mh->getCost(int3(cp.coord.x, cp.coord.y, src.z), int3(cp.coord.x+1, cp.coord.y+1, src.z), hero))) && dp.accesible)
|
||||
{
|
||||
dp.dist = cp.dist + CGI->mh->getCost(int3(cp.coord.x, cp.coord.y, src.z), int3(cp.coord.x+1, cp.coord.y+1, src.z), hero);
|
||||
dp.theNodeBefore = &graph[cp.coord.x][cp.coord.y];
|
||||
mq.push(dp);
|
||||
}
|
||||
}
|
||||
if(cp.coord.x>0 && cp.coord.y<graph[0].size()-1)
|
||||
{
|
||||
CPathNode & dp = graph[cp.coord.x-1][cp.coord.y+1];
|
||||
if((dp.dist==-1 || (dp.dist > cp.dist + CGI->mh->getCost(int3(cp.coord.x, cp.coord.y, src.z), int3(cp.coord.x-1, cp.coord.y+1, src.z), hero))) && dp.accesible)
|
||||
{
|
||||
dp.dist = cp.dist + CGI->mh->getCost(int3(cp.coord.x, cp.coord.y, src.z), int3(cp.coord.x-1, cp.coord.y+1, src.z), hero);
|
||||
dp.theNodeBefore = &graph[cp.coord.x][cp.coord.y];
|
||||
mq.push(dp);
|
||||
}
|
||||
}
|
||||
if(cp.coord.x<graph.size()-1 && cp.coord.y>0)
|
||||
{
|
||||
CPathNode & dp = graph[cp.coord.x+1][cp.coord.y-1];
|
||||
if((dp.dist==-1 || (dp.dist > cp.dist + CGI->mh->getCost(int3(cp.coord.x, cp.coord.y, src.z), int3(cp.coord.x+1, cp.coord.y-1, src.z), hero))) && dp.accesible)
|
||||
{
|
||||
dp.dist = cp.dist + CGI->mh->getCost(int3(cp.coord.x, cp.coord.y, src.z), int3(cp.coord.x+1, cp.coord.y-1, src.z), hero);
|
||||
dp.theNodeBefore = &graph[cp.coord.x][cp.coord.y];
|
||||
mq.push(dp);
|
||||
}
|
||||
}
|
||||
temp.accesible = true;
|
||||
}
|
||||
|
||||
CPathNode curNode = graph[dest.x][dest.y];
|
||||
if(!curNode.theNodeBefore)
|
||||
return NULL;
|
||||
//Set distance
|
||||
if(i == 0)
|
||||
temp.dist = p->at(i).h;
|
||||
else
|
||||
temp.dist = p->at(i).h + path->nodes.back().dist;
|
||||
|
||||
CPath * ret = new CPath;
|
||||
//theNodeBefore is never used outside of pathfinding?
|
||||
|
||||
while(curNode.coord!=graph[src.x][src.y].coord)
|
||||
{
|
||||
ret->nodes.push_back(curNode);
|
||||
curNode = *(curNode.theNodeBefore);
|
||||
//Set coord
|
||||
temp.coord = int3(p->at(i).x,p->at(i).y,p->at(i).z);
|
||||
|
||||
//Set visited
|
||||
temp.visited = false;
|
||||
|
||||
path->nodes.push_back(temp);
|
||||
}
|
||||
|
||||
ret->nodes.push_back(graph[src.x][src.y]);
|
||||
//YOU ARE ALL BACKWARDS!! =P
|
||||
//Flip the distances.
|
||||
for(int i = 0; i < path->nodes.size()/2;i++)
|
||||
{
|
||||
int t = path->nodes[i].dist;
|
||||
path->nodes[i].dist = path->nodes[path->nodes.size()-i-1].dist;
|
||||
path->nodes[path->nodes.size()-i-1].dist = t;
|
||||
}
|
||||
|
||||
return ret;
|
||||
return path;
|
||||
}
|
||||
|
||||
void CPathfinder::convertPath(CPath * path, unsigned int mode) //mode=0 -> from 'manifest' to 'object'
|
||||
@ -202,3 +306,41 @@ void CPathfinder::convertPath(CPath * path, unsigned int mode) //mode=0 -> from
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int3 CPath::startPos()
|
||||
{
|
||||
return int3(nodes[nodes.size()-1].coord.x,nodes[nodes.size()-1].coord.y,nodes[nodes.size()-1].coord.z);
|
||||
}
|
||||
int3 CPath::endPos()
|
||||
{
|
||||
return int3(nodes[0].coord.x,nodes[0].coord.y,nodes[0].coord.z);
|
||||
}
|
||||
|
||||
/*
|
||||
* The function used by the priority cue to determine which node to put at the top.
|
||||
*/
|
||||
bool Compare::operator()(const vector<Coordinate>& a, const vector<Coordinate>& b)
|
||||
{
|
||||
double aTotal=0;
|
||||
double bTotal=0;
|
||||
|
||||
for(int i = 0; i < a.size(); i++)
|
||||
{
|
||||
aTotal += a[i].g*a[i].h;
|
||||
}
|
||||
for(int i = 0; i < b.size(); i++)
|
||||
{
|
||||
bTotal += b[i].g*b[i].h;
|
||||
}
|
||||
|
||||
return aTotal > bTotal;
|
||||
}
|
||||
|
||||
void Coordinate::operator =(const Coordinate &other)
|
||||
{
|
||||
this->x = other.x;
|
||||
this->y = other.y;
|
||||
this->z = other.z;
|
||||
this->g = other.g;
|
||||
this->h = other.h;
|
||||
}
|
@ -1,9 +1,37 @@
|
||||
#ifndef CPATHFINDER_H
|
||||
#define CPATHFINDER_H
|
||||
#ifndef CPathfinder_H
|
||||
#define CPathfinder_H
|
||||
#include "global.h"
|
||||
#include <queue>
|
||||
#include <vector>
|
||||
#include <queue>
|
||||
#include <math.h>
|
||||
class CGHeroInstance;
|
||||
|
||||
using namespace std;
|
||||
|
||||
class Coordinate
|
||||
{
|
||||
public:
|
||||
int x;
|
||||
int y;
|
||||
int z;
|
||||
float g; //Distance from goal
|
||||
int h; //Movement cost
|
||||
|
||||
Coordinate() : x(NULL), y(NULL), z(NULL), g(NULL), h(NULL) {}
|
||||
Coordinate(int3 xyz) : x(xyz.x), y(xyz.y), z(xyz.z){}
|
||||
Coordinate(int xCor, int yCor, int zCor) : x(xCor), y(yCor), z(zCor){}
|
||||
Coordinate(int xCor, int yCor, int zCor, int dist, int penalty) : x(xCor), y(yCor), z(zCor), g(dist), h(penalty){}
|
||||
void operator=(const Coordinate& other);
|
||||
};
|
||||
|
||||
//Class used in priority queue to determine order.
|
||||
class Compare
|
||||
{
|
||||
public:
|
||||
bool operator()(const vector<Coordinate>& a, const vector<Coordinate>& b);
|
||||
};
|
||||
|
||||
//Included for old format
|
||||
struct CPathNode
|
||||
{
|
||||
bool accesible; //true if a hero can be on this node
|
||||
@ -13,6 +41,7 @@ struct CPathNode
|
||||
bool visited;
|
||||
};
|
||||
|
||||
//Included for old format
|
||||
struct CPath
|
||||
{
|
||||
std::vector<CPathNode> nodes; //just get node by node
|
||||
@ -21,18 +50,65 @@ struct CPath
|
||||
int3 endPos(); //destination point
|
||||
};
|
||||
|
||||
/**
|
||||
* main pathfinder class
|
||||
*/
|
||||
class CPathfinder
|
||||
{
|
||||
private:
|
||||
std::vector< std::vector<CPathNode> > graph;
|
||||
boost::logic::tribool blockLandSea; //true - blocks sea, false - blocks land, indeterminate - allows all
|
||||
|
||||
/*
|
||||
* Does the actual path calculation. Don't call this directly, call GetPath instead.
|
||||
*/
|
||||
vector<Coordinate>* CalcPath();
|
||||
|
||||
/*
|
||||
* Determines if the given node exists in the closed list, returns true if it does. This is
|
||||
* used to ensure you dont check the same node twice.
|
||||
*/
|
||||
bool ExistsInClosed(Coordinate node);
|
||||
|
||||
/*
|
||||
* Adds the neighbors of the current node to the open cue so they can be considered in the
|
||||
* path creation. If the node has a cost (f = g + h) less than zero, it isn't added to Open.
|
||||
*/
|
||||
void AddNeighbors(vector<Coordinate>* node);
|
||||
|
||||
/*
|
||||
* Calculates the movement cost of the node. Returns -1 if it is impossible to travel on.
|
||||
*/
|
||||
void CalcH(Coordinate* node);
|
||||
|
||||
/*
|
||||
* Calculates distance from node to end node.
|
||||
*/
|
||||
void CalcG(Coordinate* node);
|
||||
|
||||
public:
|
||||
CPath * getPath(int3 src, int3 dest, const CGHeroInstance * hero, unsigned char type=0); //calculates path between src and dest; returns pointer to CPath or NULL if path does not exists; type - type of calculation: 0 - positions are normal positions of hero; 1 - given places are tiles blocked by hero
|
||||
CPath * getPath(const int3 & src, const int3 & dest, const CGHeroInstance * hero, int (*getDist)(int3 & a, int3 & b), unsigned char type=0); //calculates path between src and dest; returns pointer to CPath or NULL if path does not exists; uses getDist to calculate distance; type - type of calculation: 0 - positions are normal positions of hero; 1 - given places are tiles blocked by hero
|
||||
//Contains nodes to be searched
|
||||
priority_queue < vector<Coordinate>, vector<vector<Coordinate>>, Compare> Open;
|
||||
|
||||
//History of nodes you have been to before
|
||||
vector<Coordinate> Closed;
|
||||
|
||||
//The start, or source position.
|
||||
Coordinate Start;
|
||||
|
||||
//The end, or destination position
|
||||
Coordinate End;
|
||||
|
||||
//A reference to the Hero.
|
||||
const CGHeroInstance* Hero;
|
||||
|
||||
/*
|
||||
* Does basic input checking and setup for the path calculation.
|
||||
*/
|
||||
vector<Coordinate>* GetPath(const CGHeroInstance* hero);
|
||||
vector<Coordinate>* GetPath(Coordinate start, Coordinate end, const CGHeroInstance* hero);
|
||||
|
||||
//Convert to oldformat
|
||||
CPath* ConvertToOldFormat(vector<Coordinate>* p);
|
||||
|
||||
static void convertPath(CPath * path, unsigned int mode); //mode=0 -> from 'manifest' to 'object'
|
||||
|
||||
};
|
||||
|
||||
#endif //CPATHFINDER_H
|
Reference in New Issue
Block a user