小试A*
来源:互联网 发布:二手手机测试软件 编辑:程序博客网 时间:2024/05/17 09:05
前天从网上看了A* 的介绍,觉得有意思,于是自己想试着写一个。
A*有很多的应用,这里就写个经典使用之一,寻路。
网上有很多介绍A* 概念的东西,这就不说了,有个文章觉得写的不错,给个地址算了
Click Here
====================================
思想主要是按那页最下面的老外介绍的,实现了一下。
==============================
map.map 12行16列,注意对齐,字母d表示目的地,字母s表示出发点
oooooooooooooooo
oooooooooooooooo
ood o
oo o
ooooooooooooo o
ooo o
ooo o oooooooo
ooo o oooooooo
ooo o
o o
o s oooooooooooo
oooooooooooooooo
==========================
Node.h /// 节点定义结构体
#ifndef NODE_H
#define NODE_H
typedef struct node_tag NODE;
typedef unsigned char UCHAR;
struct node_tag
{
int f;
int g;
int h;
int x;
int y;
int tileNumber;
NODE* father;
NODE* child[8];
};
typedef struct point_tag
{
int x;
int y;
}POINT;
#endif ///:~
=============================
TileMethod.h ///处理块的一些方法
#ifndef TILE_METHOD_H
#define TILE_METHOD_H
#include <list>
#include "Node.h"
class CTileMethod
{
public:
bool IsAccessible(int x,int y);
POINT GetSourcePoint();
POINT GetDestPoint();
int GetOrderNumber(int x,int y);
};
#endif ///:~
=======================
TileMethod.cpp ///对应实现
#include "TileMethod.h"
using namespace std;
extern char map[12][16];
bool CTileMethod::IsAccessible(int x,int y)
{
if(map[x][y]=='o')
{
return false;
}
return true;
}
POINT CTileMethod::GetSourcePoint()
{
POINT source;
for(int i=0;i<12;i++)
{
for(int j=0;j<16;j++)
{
if(map[i][j]=='s')
{
source.x = i;
source.y = j;
return source;
}
}
}
}
POINT CTileMethod::GetDestPoint()
{
POINT dest;
for(int i=0;i<12;i++)
{
for(int j=0;j<16;j++)
{
if(map[i][j]=='d')
{
dest.x = i;
dest.y = j;
return dest;
}
}
}
}
int CTileMethod::GetOrderNumber(int x,int y)
{
//x=0,y=0 number = 0
//x=1,y=0 number = 16
//x=2,y=1 number = 33
return (x*16+y);
}
=======================
AStar.h ////A* 头文件
#ifndef A_STAR_H
#define A_STRA_H
#include "Node.h"
#include <list>
#include "TileMethod.h"
class CAStar
{
public:
NODE* FindPath(int sx,int sy,int dx,int dy);
void GenerateChildren(NODE*& bestNode,int dx,int dy);
void GenerateChild(NODE*& bestNode,int x,int y,int dx,int dy,bool bOblique);
NODE* CheckInList(std::list<NODE*>& listTemp,int tileNumber);
void ClearUp();
void ReSortList(std::list<NODE*>& listTemp,NODE* node);
void InsertList(std::list<NODE*>& listTemp,NODE* node);
void PrintList(std::list<NODE*>& listTemp);
private:
CTileMethod tiler;
};
=========================
AStar.cpp ///实现
#include "AStar.h"
#include <cmath>
#include <iostream>
using namespace std;
extern char map[12][16];
list<NODE*> listOpen;
list<NODE*> listClosed;
typedef list<NODE*>::iterator ListIter;
NODE* CAStar::FindPath(int sx,int sy,int dx,int dy)
{
NODE* node = NULL;
NODE* bestNode = NULL;
bool bFindPath = false;
int destTile = tiler.GetOrderNumber(dx,dy);
node = (NODE*)malloc(sizeof(NODE));
for(int i=0;i<8;i++)
{
node->child[i]=NULL;
}
node->g = 0 ;
node->h = (abs(sx-dx)+abs(sy-dy))*10;
node->f = node->g + node->h;
node->father = NULL;
node->tileNumber = tiler.GetOrderNumber(sx,sy);
node->x = sx;
node->y = sy;
listOpen.push_back(node);
while(!listOpen.empty())
{
bestNode = listOpen.front();
listOpen.pop_front();
listClosed.push_back(bestNode);
if(bestNode->tileNumber == destTile)
{
bFindPath = true;
break;
}
GenerateChildren(bestNode,dx,dy);
}
if(bFindPath)
{
return bestNode;
}
else
{
return NULL;
}
}
void CAStar::GenerateChildren(NODE*& bestNode,int dx,int dy)
{
int x,y;
bool bUpExtension = false;
bool bRightExtension = false;
bool bDownExtension = false;
bool bLeftExtension = false;
//从左上角开始,顺时针方向扩展
if((bUpExtension=tiler.IsAccessible(x=bestNode->x-1,y=bestNode->y))) // to up
{
GenerateChild(bestNode,x,y,dx,dy,false);
}
if((bRightExtension=tiler.IsAccessible(x=bestNode->x,y=bestNode->y+1))) // to right
{
GenerateChild(bestNode,x,y,dx,dy,false);
}
if((bDownExtension=tiler.IsAccessible(x=bestNode->x+1,y=bestNode->y))) // to down
{
GenerateChild(bestNode,x,y,dx,dy,false);
}
if((bLeftExtension=tiler.IsAccessible(x=bestNode->x,y=bestNode->y-1))) // to left
{
GenerateChild(bestNode,x,y,dx,dy,false);
}
///处理穿过corner的情况
if(bUpExtension && bLeftExtension)
{
if(tiler.IsAccessible(x=bestNode->x-1,y=bestNode->y-1)) // to up,to left
{
GenerateChild(bestNode,x,y,dx,dy,true);
}
}
if(bUpExtension && bRightExtension)
{
if(tiler.IsAccessible(x=bestNode->x-1,y=bestNode->y+1)) //to up,to right
{
GenerateChild(bestNode,x,y,dx,dy,true);
}
}
if(bDownExtension && bRightExtension)
{
if(tiler.IsAccessible(x=bestNode->x+1,y=bestNode->y+1)) // to down,to right
{
GenerateChild(bestNode,x,y,dx,dy,true);
}
}
if(bDownExtension && bLeftExtension)
{
if(tiler.IsAccessible(x=bestNode->x+1,y=bestNode->y-1)) // to down ,to left
{
GenerateChild(bestNode,x,y,dx,dy,true);
}
}
}
void CAStar::ReSortList(list<NODE*>& listTemp,NODE* node)
{
ListIter lit;
for(lit=listTemp.begin();lit!=listTemp.end();lit++)
{
if((*lit)->tileNumber == node->tileNumber)
{
listTemp.erase(lit);
break;
}
}
InsertList(listTemp,node);
}
void CAStar::InsertList(list<NODE*>& listTemp,NODE* node)
{
ListIter lit;
bool bInsert = false;
for(lit=listTemp.begin();lit!=listTemp.end();lit++)
{
if((*lit)->f >= node->f)
{
bInsert = true;
listTemp.insert(lit,node);
break;
}
}
if(!bInsert)
{
listTemp.push_back(node);
}
}
void CAStar::GenerateChild(NODE*& bestNode,int x,int y,int dx,int dy,bool bOblique)
{
int tileNumber = tiler.GetOrderNumber(x,y);
int i;
NODE* old = NULL;
int g;
if(bOblique)
{
g = bestNode->g + 14;
}
else
{
g = bestNode->g + 10;
}
if((old=CheckInList(listOpen,tileNumber))!=NULL) //在开放列表中
{
for(i=0;i<8;i++)
{
if(bestNode->child[i]==NULL)
{
break;
}
}
bestNode->child[i] = old;
if(g < old->g)
{
old->father = bestNode;
old->g = g;
old->f = g + old->h;
ReSortList(listOpen,old);
}
}
else if((old=CheckInList(listClosed,tileNumber))!=NULL) //在封闭列表中
{
//do nothing
}
else ///未开辟,不在开放列表中,也不在封闭列表中
{
NODE* newChild = (NODE*)malloc(sizeof(NODE));
for(i=0;i<8;i++)
{
newChild->child[i]=NULL;
}
newChild->father = bestNode;
newChild->g = g;
newChild->h = (abs(x-dx)+abs(y-dy))*10;
newChild->f = g + newChild->h;
newChild->tileNumber = tileNumber;
newChild->x = x;
newChild->y = y;
for(i=0;i<8;i++)
{
if(bestNode->child[i]==NULL)
{
break;
}
}
bestNode->child[i] = newChild;
InsertList(listOpen,newChild);
//PrintList(listOpen);
}
}
void CAStar::ClearUp()
{
ListIter lit;
for(lit=listOpen.begin();lit!=listOpen.end();lit++)
{
free(*lit);
}
for(lit=listClosed.begin();lit!=listClosed.end();lit++)
{
free(*lit);
}
}
NODE* CAStar::CheckInList(std::list<NODE*>& listTemp,int tileNumber)
{
ListIter lit;
for(lit=listTemp.begin();lit!=listTemp.end();lit++)
{
if((*lit)->tileNumber == tileNumber)
{
return (*lit);
}
}
return NULL;
}
void CAStar::PrintList(list<NODE*>& listTemp)
{
ListIter lit;
cout<<"ListOpen:"<<endl;
for(lit=listTemp.begin();lit!=listTemp.end();lit++)
{
cout<<(*lit)->f<<" < ";
}
cout<<endl;
}
=====================
main.cpp /// 程序入口
#include "AStar.h"
#include "Node.h"
#include <iostream>
#include <fstream>
using namespace std;
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
char map[12][16]={{' '}};
void InitMap();
int main()
{
InitMap();
CAStar pathFinder;
CTileMethod methoder;
POINT sourcePoint = methoder.GetSourcePoint();
POINT destPoint = methoder.GetDestPoint();
int x,y;
NODE* result = pathFinder.FindPath(sourcePoint.x,sourcePoint.y,destPoint.x,destPoint.y);
if(result!=NULL)
{
while(result->father->father)
{
x = result->father->x;
y = result->father->y;
map[x][y] = '.';
result = result->father;
}
for(int i=0;i<12;i++)
{
for(int j=0;j<16;j++)
{
cout<<map[i][j]<<" ";
}
cout<<endl;
}
}
else
{
cout<<"没找到路径!";
}
pathFinder.ClearUp();
getchar();
return 0;
}
void InitMap()
{
ifstream in("map.map");
int i=0;
int j=0;
char c;
while((c=in.get())!=EOF)
{
if(c=='o'||c==' '||c=='s'||c=='d')
{
map[i][j] = c;
j++;
if(j==16)
{
j = 0;
i++;
}
}
}
}
==========================
运行截图:
o表示障碍物,s是源点,d是目标,点是寻找好的路径。
接下来可以试验移植到direct中试试了~~