Browse Source

New pathfinder by Spasarto

Michał W. Urbańczyk 17 years ago
parent
commit
697f26529a
4 changed files with 381 additions and 151 deletions
  1. 9 1
      CAdvmapInterface.cpp
  2. 9 5
      CConsoleHandler.cpp
  3. 278 136
      CPathfinder.cpp
  4. 85 9
      CPathfinder.h

+ 9 - 1
CAdvmapInterface.cpp

@@ -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)
 {

+ 9 - 5
CConsoleHandler.cpp

@@ -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;
 }

+ 278 - 136
CPathfinder.cpp

@@ -5,33 +5,41 @@
 #include "hch\CAmbarCendamo.h"
 #include "mapHandler.h"
 #include "CGameState.h"
-using namespace boost::logic;
-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()
+
+using namespace std;
+
+vector<Coordinate>* CPathfinder::GetPath(Coordinate start, Coordinate end, const CGHeroInstance* hero)
 {
-	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)
+	{
+		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].resize(CGI->ac->map.height);
-		for(int j=0; j<graph[i].size(); ++j)
+		//Flip the route since it is calculated in reverse
+		int size = toReturn->size();
+		for(int i = 0; i < size/2; i++)
 		{
-			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];
+			Coordinate t = toReturn->at(i);
+			(*toReturn)[i] = toReturn->at(size-1-i);
+			(*toReturn)[size-1-i] = t;
 		}
 	}
 
-	//graph initialized
-
-	graph[src.x][src.y].dist = 0;
+	return toReturn;
+}
 
-	std::queue<CPathNode> mq;
-	mq.push(graph[src.x][src.y]);
+/*
+ * Does the actual path calculation.  Don't call this directly, call GetPath instead.
+*/
+vector<Coordinate>* CPathfinder::CalcPath()
+{
+	if(Open.empty())
+	{
+		return NULL;
+	}
 
-	unsigned int curDist = 4000000000;
+	//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();
 
-	while(!mq.empty())
+	//Don't search elements in the closed list, for they have been visited already.
+	if(!ExistsInClosed(branch->back()))
 	{
-		CPathNode cp = mq.front();
-		mq.pop();
-		if ((cp.coord.x == dest.x) && (cp.coord.y==dest.y))
-		{
-			if (cp.dist < curDist)
-				curDist=cp.dist;
-		}
-		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)
+		//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)
 		{
-			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);
-			}
+			return branch;
 		}
-		if(cp.coord.x<graph.size()-1 && cp.coord.y<graph[0].size()-1)
+
+		//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++)
 		{
-			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)
+			if(i > 0 && j > 0 && i < CGI->mh->sizes.x-1 && j < CGI->mh->sizes.y-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.theNodeBefore = &graph[cp.coord.x][cp.coord.y];
-				mq.push(dp);
+				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);
+				}
 			}
 		}
-		if(cp.coord.x>0 && cp.coord.y<graph[0].size()-1)
+	}
+
+	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)
 		{
-			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 = false;
 		}
-		if(cp.coord.x<graph.size()-1 && cp.coord.y>0)
+		else
 		{
-			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'
@@ -201,4 +305,42 @@ void CPathfinder::convertPath(CPath * path, unsigned int mode) //mode=0 -> from
 			path->nodes[i].coord = CGHeroInstance::convertPosition(path->nodes[i].coord,true);
 		}
 	}
+}
+
+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;
 }

+ 85 - 9
CPathfinder.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