a*算法初步(源代碼)

關於a*算法的文章和代碼有很多,這裏是我整理的一份源代碼,從別人的例子中修改過來的。在這個代碼示例中加入了地圖信息對尋址結果的影響,可以用在包含不同種類的地形信息的地圖中尋址。由於代碼可以調試,你可以看清楚每一個步驟是怎麼做的,在這裏我就不多做講解了。
#include <windows.h>
#include <stdio.h>

#define COLS 3 //地圖
#define ROWS 3
#define TOTAL_TILES 9

#define TileNum( x, y ) ( y * COLS + x + 1 ) //判斷是地圖上的第幾個格子

struct NODE {
 long f,h,i; //在這裏,我增加了一個i函數,主要用於地圖信息
 int g;
 int x,y;
 int NodeNum;
 struct NODE *Parent;
 struct NODE *Child[8];       /* a node may have upto 8+(NULL) children. */
 struct NODE *NextNode;       /* for filing purposes */
};

struct NODE *OPEN;
struct NODE *CLOSED;

int TileMap[TOTAL_TILES] = { /  
1, 1, 1, /
1, 2, 1, /
1, 1, 1
};
//地圖信息,目前由(0,0)點到(2,2)點的尋址結果是(0,0)->(1,1)->(2,2)。如果中間的那個2修改成4,表明不能行走或者是沼澤路面行走困難,尋址結果是(0,0)->(0,1)->(1,2)->(2,2)。

struct STACK {
    struct NODE *NodePtr;
    struct STACK *NextStackPtr;
};
struct STACK *Stack;

void Push(struct NODE *Node)
{
    struct STACK *tmp;
    tmp = ( struct STACK *)calloc(1,sizeof(struct STACK));
    tmp->NodePtr = Node;
    tmp->NextStackPtr = Stack->NextStackPtr;
    Stack->NextStackPtr = tmp;
}

struct NODE *Pop()
{
    struct NODE *tmp;
    struct STACK *tmpSTK;
    tmpSTK = Stack->NextStackPtr;
    tmp = tmpSTK->NodePtr;
    Stack->NextStackPtr = tmpSTK->NextStackPtr;
    free( tmpSTK );
    return( tmp );
}

struct NODE *CheckOPEN(int tilenum)
{
 struct NODE *tmp = OPEN->NextNode;
 while( tmp ) {
  if( tmp->NodeNum == tilenum )
   return( tmp );
  else
   tmp = tmp->NextNode;
 }
 return( NULL );
}

struct NODE *CheckCLOSED(int tilenum)
{
 struct NODE *tmp = CLOSED->NextNode;
 while( tmp ) {
  if( tmp->NodeNum == tilenum )
   return( tmp );
  else
   tmp = tmp->NextNode;
 }
 return( NULL );
}

void PropagateDown(struct NODE *Old)
{
 int c,g;
 struct NODE *Child, *Father;

 g = Old->g;
 for( c = 0; c < 8; c ++ ) {
  if( ( Child = Old->Child[c] ) == NULL ) break;
  if( g + 1 < Child->g ) {
   Child->g = g + 1;
   Child->f = Child->g + Child->h + Child->i;
   //Child->f = Child->g + Child->h;
   Child->Parent = Old;
   Push( Child );
  }
 }
 while( Stack->NextStackPtr != NULL ) {
  Father = Pop();
  for( c = 0; c < 8; c ++ ) {
   if( ( Child = Father->Child[c] ) == NULL ) break;
   if( Father->g + 1 < Child->g ) {
    Child->g = Father->g + 1;
    Child->f = Child->g + Child->h + Child->i;
    //Child->f = Child->g + Child->h;
    Child->Parent = Father;
    Push( Child );
   }
  }
 }
}

void Insert(struct NODE *Successor)
{
 struct NODE *tmp1,*tmp2;
 long f;

 if(OPEN->NextNode == NULL) {
  OPEN->NextNode = Successor;
  return;
 }

 f = Successor->f;
 tmp1 = OPEN;
 tmp2 = OPEN->NextNode;
 while( ( tmp2 != NULL ) && ( tmp2->f < f ) ) {
  tmp1 = tmp2;
  tmp2 = tmp2->NextNode;
 }
 Successor->NextNode = tmp2;
 tmp1->NextNode = Successor;
}

void GenerateSucc(struct NODE *BestNode,long x, long y, long dx, long dy)
{
 int g, TileNumS, c;
 struct NODE *Old,*Successor;

 TileNumS = TileNum( x, y );
 //g = BestNode->g + TileMap[TileNumS];
 g = BestNode->g + 1;

 if( ( Old = CheckOPEN(TileNumS) ) != NULL ) {
  for( c = 0; c < 8; c ++ ) {
   if( BestNode->Child[c] == NULL ) break;
  }
  BestNode->Child[c] = Old;
  if( g < Old->g ) {
   Old->Parent = BestNode;
   Old->g = g;
   Old->f = g + Old->h + Old->i;
   //Old->f = g + Old->h;
  }
 }
 else if( ( Old = CheckCLOSED(TileNumS) ) != NULL ) {
  for( c = 0; c < 8; c ++ ) {
   if( BestNode->Child[c] == NULL ) break;
  }
  BestNode->Child[c] = Old;
  if( g < Old->g ) {
   Old->Parent = BestNode;
   Old->g = g;
   //Old->f = g + Old->h;
   Old->f = g + Old->h + Old->i;
   PropagateDown( Old );
  }
 }
 else {
  Successor = (struct NODE *)calloc(1,sizeof( struct NODE ));
  Successor->Parent = BestNode;
  Successor->NodeNum = TileNumS;
  Successor->g = g;
  //Successor->h = abs( x - dx ) + abs( y - dy );
  Successor->h = ( x - dx ) * ( x - dx ) + ( y - dy ) * ( y - dy );
  Successor->i = TileMap[Successor->NodeNum-1];
  Successor->f = g + Successor->h + Successor->i;
  //Successor->f = g + Successor->h;
  Successor->x = x;
  Successor->y = y;
  Insert(Successor);
  for( c = 0; c < 8; c ++ ) {
   if( BestNode->Child[c] == NULL ) break;
  }
  BestNode->Child[c]=Successor;
 }
}

void GenerateSuccessors(struct NODE *BestNode,long dx,long dy)
{
 long x,y;

 /* Upper-Left  */
 x = BestNode->x - 1; y = BestNode->y - 1;
 if( x >= 0 && y >= 0 )
  GenerateSucc(BestNode,x,y,dx,dy);

 /* Upper       */
 x = BestNode->x; y = BestNode->y - 1;
 if( y >= 0 )
  GenerateSucc(BestNode,x,y,dx,dy);

 /* Upper-Right */
 x = BestNode->x + 1; y = BestNode->y - 1;
 if( x < COLS && y >= 0 )
  GenerateSucc(BestNode,x,y,dx,dy);

 /* Right       */
 x = BestNode->x + 1; y = BestNode->y;
 if( x < COLS )
  GenerateSucc(BestNode,x,y,dx,dy);

 /* Lower-Right */
 x = BestNode->x + 1; y = BestNode->y + 1;
 if( x < COLS && y < ROWS )
  GenerateSucc(BestNode,x,y,dx,dy);

 /* Lower       */
 x = BestNode->x; y = BestNode->y + 1;
 if( y < ROWS )
  GenerateSucc(BestNode,x,y,dx,dy);

 /* Lower-Left  */
 x = BestNode->x - 1; y = BestNode->y + 1;
 if( x >= 0 && y < ROWS )
  GenerateSucc(BestNode,x,y,dx,dy);

 /* Left        */
 x = BestNode->x - 1; y = BestNode->y;
 if( x >= 0 )
  GenerateSucc(BestNode,x,y,dx,dy);
}

struct NODE *ReturnBestNode(void)
{
 struct NODE *tmp;
 tmp = OPEN->NextNode;
 OPEN->NextNode = tmp->NextNode;
 tmp->NextNode = CLOSED->NextNode;
 CLOSED->NextNode = tmp;
 return(tmp);
}

struct NODE *FindPath(long sx, long sy, long dx, long dy)
{
 struct NODE *Node, *BestNode;
 int TileNumDest = TileNum(dx,dy);
 OPEN = (struct NODE *)calloc(1,sizeof( struct NODE ));
 CLOSED = (struct NODE *)calloc(1,sizeof( struct NODE ));

 Node=(struct NODE *)calloc(1,sizeof( struct NODE ));
 Node->NodeNum = TileNum(sx,sy);
 Node->g = 0;
 //Node->h = abs( sx - dx ) + abs( sy - dy );
 Node->h = ( sx - dx ) * ( sx - dx ) + ( sy - dy ) * ( sy - dy );
 Node->i = TileMap[Node->NodeNum-1];
 Node->f = Node->g + Node->h + Node->i;
 //Node->f = Node->g + Node->h;
 Node->x = sx;
 Node->y = sy;

 OPEN->NextNode=Node;
 for (;;) {
  BestNode = (struct NODE *)ReturnBestNode();
  if( BestNode->NodeNum == TileNumDest ) break;
  GenerateSuccessors( BestNode, dx, dy );
 }
 return BestNode;
};

INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
 Stack=( struct STACK *)calloc(1,sizeof(struct STACK));
 struct NODE * Path = FindPath( 0, 0, 2, 2 );
 return 0;
}

雖然用上面的算法可以找到目的地址,但是目前有幾個問題:
1)效率問題:當起點到終點的路徑不存在的時候,a*的花費比較大,應該加如預尋址算法或者改進當前算法。
2)當地圖中不能走的地方邊邊角角較多的時候,尋址的結果中折線較多,此時可以尋求其次優解,將路徑美化。
3)尋址方向目前有8個,對應於2D的八個方向,感覺應該能擴展到3D空間當中,做一個3D的a*尋址。3D尋址的時候應該是26個方向。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章