小试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中试试了~~

原创粉丝点击