5
« on: August 30, 2013, 10:17:56 AM »
Assuming you're using C++ and the standard libraries, maybe something like this...
struct node {
node() : x(0), y(0), g(0), h(0), f(0), state(UNDISCOVERED), previous_step(NULL), tile(NULL) { }
void ResetForDestination( node* destination )
{
// initialises node for new path
h = std::abs(x - destination->y) + std::abs(y - destination->y);
g = f = INT_MAX;
state = UNDISCOVERED;
previous_step = NULL;
}
void Open( node* previous, std::multiset<node*>& open_set )
{
// adds node to the open list, records where it came from and how long the path is
previous_step = previous;
g = previous_step ? previous_step->g + 1 : 0;
f = g + h;
state = OPEN;
open_set.insert( this );
}
int x,y;
int g,h,f;
enum { UNDISCOVERED, OPEN, CLOSED } state;
node* previous_step;
node* neighbours[4];
tile* tile;
};
struct nodeCompare {
bool operator()(const node* lhs, const node* rhs)
{
if(!lhs) return true;
if(!rhs) return false;
return lhs->f < rhs->f;
}
};
bool initialised = false;
std::vector< std::vector<node> > nodes;
void Initialise( int max_X, int max_Y )
{
nodes.resize(max_X);
for (int x = 0; x < max_X; ++x)
{
nodes[x].resize(max_Y);
for (int y = 0; y < max_Y; ++y)
{
nodes[x][y].x = x;
nodes[x][y].y = y;
nodes[x][y].tile = &tiles[x][y];
nodes[x][y].neighbours[0] = x > 0 ? &nodes[x-1][y] : NULL;
nodes[x][y].neighbours[1] = x < max_X-1 ? &nodes[x+1][y] : NULL;
nodes[x][y].neighbours[2] = y > 0 ? &nodes[x][y-1] : NULL;
nodes[x][y].neighbours[3] = y < max_Y-1 ? &nodes[x][y+1] : NULL;
}
}
initialised = true;
}
bool FindPathFrom_To( int start_X, int start_Y, int dest_X, int dest_Y, std::list<tile*>& path )
{
if( !initialised )
{
Initialise( MAPX, MAPY );
}
// reinitialise node map
node* start_node = &nodes[start_X][start_Y];
node* destination_node = &nodes[dest_X][dest_Y];
for (int x = 0; x < max_X; ++x)
for (int y = 0; y < max_Y; ++y)
nodes[x][y].ResetForDestination(destination_node);
// open list, automatically sorts by f
std::multiset<node*, nodeCompare> open;
start_node->Open( NULL, open );
// search
while( !open.empty() )
{
// find the current cheapest node (which will be at the start of the set)
node* current_node = *open.begin();
if( current_node == destination_node )
{
break;
}
// open all adjacent nodes
for( int i = 0; i < 4; i++ )
{
if( current_node->neighbours[i] && current_node->neighbours[i]->state == node::UNDISCOVERED )
{
current_node->neighbours[i]->Open( current_node, open );
}
}
// remove current node from the open list
current_node->state = node::CLOSED;
open_set.erase( open.begin() );
}
// calculate the final path
path.clear();
node* current_step = destination_node;
while( current_step )
{
path.push_front( current_step->tile );
if( current_step == start_node )
{
return true;
}
current_step = current_step->previous_step;
}
return false;
}
I haven't compiled it, let alone tested it but all the basics are there (even if it's rather messy).
You call 'Initialise' to create your pathfinding map and then 'FindPathFrom_To' to get a list of tiles you need to traverse. It returns false if no path was found.