A*寻路算法学习及实现

来源:互联网 发布:淘宝外卖点麻辣烫 编辑:程序博客网 时间:2024/04/30 22:57

A*寻路算法学习及实现

  • 算法简介
    A*算法是游戏中常用的一种寻路算法,通过该算法可以求得节点化地图上起点到终点的一条最短路。
    它将最短路算法(Dijkstra)和启发式算法(Greedy Best-First-Search)进行了结合。通过代价函数  F=G+进行寻找最短路(G为离起点最近的目标节点的距离;H为该目标节点到终点的距离,起到启发作用);有效避免了Dijstra寻路过程中的搜索空间很大的缺点,又避免了简单启发式算法在复杂地形下找不到最优路径的问题。具体细节可以参考Stanford的A*简介。
  • 算法流程

    • 符号标记:
      • 代价函数 F=G+
      • 开列表(open list)和闭列表(close list),openList用于存储当前已搜索过的节点的邻接节点,closeList用于存储已经搜索过的节点,当openList中的F值最小的节点被选中为当前搜索节点(curNode)后,将该节点放入closeList中;
      • 父节点(parentNode),表示该节点到起点所需要经过的最短路中的第一个节点;
      • 相邻节点间的距离(D):垂直或水平相邻距离为10,斜对角相邻距离为14;
      • 地图(map),起点(S),终点(D),当前搜索节点(curNode);
      • map是经节点化处理过的,这里将地图处理成网格,每个网格即为一个节点;
      • 每个节点有四种状态:
        普通状态(normal)表示该节点为可通过节点;
        障碍状态(obstacle)表示该节点为障碍物,不可通过;
        开状态(open)表示该节点在openList中;
        闭状态(close)表示该节点在closeList中;
    • 流程:
      • 初始化:生成map;openList、closeList为空;curNode = S;
      • while(curNode != D) —- 一直搜索到终点加入到openList结束
        • closeList.push_back(curNode) —- 搜索过的节点放入闭集合;
        • 更新当前搜索的节点curNode的邻接节点adjNodes状态:
          • 对adjNodes中的normal节点(nd):将其父节点设为curNode,并将该节点加入到openList中,然后计算该节点的代价值(G = curNode.G + nd.D, H = nd到终点的Manhattan距离,即从nd到终点D只进行横向和纵向移动所需要经过的距离,F = G+H);
          • 对adjNodes中的open节点(od):比较其经过curNode到起点的代价(G’ = curNode.G + od.D)与该点原来到起点的代价(G)做比较: 如果 G’ < G,则更新od的父节点为curNode,并更新其代价函数值(G=G’,F = G + H);否则不做更改;
          • 对adjNode中的其他类型节点:不做处理;
        • 查找当前openList中F值最小的节点,赋给curNode。然后将其保存到closeList中,并从openList中移除;
      • 搜索到起点S 到终点 D的路径后,从终点D开始,逐一查找其父节点,直到起点S,便找到了起点到终点间的一条最短路;
  • 寻路结果

    • map:
      这里写图片描述
    • 寻路:
      • 终点位置1,寻路结果
      • 终点位置2寻路结果
        这里写图片描述
  • 代码实现
#include <iostream>#include <vector>#include <algorithm>#include "DebugFunc.h"typedef unsigned int uint;typedef enum ENodeFlag{    ENF_OPEN,           //open    ENF_CLOSE,          //close    ENF_NORMAL,         //normal    ENF_OBSTACLE,       //obstacle}ENodeFlag;typedef struct SPoint{       int x;          //地图节点的横坐标;    int y;          //地图节点的纵坐标;    SPoint(int ax = -1, int ay = -1)    {        x = ax; y = ay;    }    const SPoint operator=(const SPoint &p)    {        x = p.x;        y = p.y;        return *this;    }    bool operator!=(const SPoint &p)    {        return (p.x != x) || (p.y != y);    }}SPoint;typedef struct SCost{    int G;          //起点到当前节点的cost;    int H;          //当前节点到终点的预估cost;    int F;          //总代价,F=G+H;    SCost()    {        G = H = F = 0;    }}SCost;typedef struct SMap{    char    m;          //地图节点表示;    char    f;          //节点状态标记,open/close/normal;    SCost   c;          //路径代价;    SPoint  p;          //父节点坐标;    SMap()    {        m = '.'; f = ENF_NORMAL;    }}SMap;typedef std::vector<std::vector<SMap>> TArray;  // 定义存储矩阵的类型;const uint  hoffset = 10;   //水平移动单位距离;const uint  soffset = 14;   //斜对角移动的单位距离;const uint  INFI    = 0xFFFFFFF;//无穷值;using namespace std;void AStar(TArray &map, const SPoint &s, const SPoint &d);int main(int argc, char **argv){    //生成地图;    const int mapSize = 30;    TArray map(mapSize, vector<SMap>(mapSize));    SPoint s, d;    s.x = 1; s.y = 9;       //起点坐标;    d.x = 28; d.y = 17;     //终点坐标;    map[s.x][s.y].m = 'S';    map[d.x][d.y].m = 'D';    for (int i = 2; i < mapSize - 5; ++i)    {        map[mapSize/2][i].m = '0';         map[mapSize/2][i].f = ENF_OBSTACLE;    }    for (int i = 1; i < 10; ++i)    {        map[i][mapSize/2].m = '0';        map[i][mapSize/2].f = ENF_OBSTACLE;        map[mapSize - i][d.y - 2].m = '0';        map[mapSize - i][d.y - 2].f = ENF_OBSTACLE;    }    for (int i = d.y - 2; i < d.y + 4; ++i)    {        map[d.x - 2][i].m = '0';         map[d.x - 2][i].f = ENF_OBSTACLE;    }    //打印地图;    PRINT("'.'--普通地面\t'0'--障碍物\t'S'--起点\n'D'--终点\t'o'--S到D的路径\n");    for (uint x = 0; x < mapSize; ++x)    {        for (uint y = 0; y < mapSize; ++y)        {            PRINT("%c ", map[x][y].m);        }        PRINT("\n");    }    AStar(map, s, d); //进行寻路;    //显示寻路结果;    SPoint curNode = map[d.x][d.y].p;    while (curNode != s)    {        map[curNode.x][curNode.y].m = 'o';        curNode = map[curNode.x][curNode.y].p;    }    PRINT("-----------------------------------------------------\n");    for (uint x = 0; x < mapSize; ++x)    {        for (uint y = 0; y < mapSize; ++y)        {            PRINT("%c ", map[x][y].m);        }        PRINT("\n");    }    system("pause");    return 0;}void UpdateOpenNode(TArray &map, const SPoint &curNode,                    const SPoint &endNode, vector<SPoint> &openList){    int sX = 0, sY = 0, eX = 0, eY = 0;    sX = (curNode.x - 1) >= 0 ? curNode.x - 1 : 0;    eX = (curNode.x + 1) < map.size() ? curNode.x + 1 : map.size() - 1;    sY = (curNode.y - 1) >= 0 ? curNode.y - 1 : 0;    eY = (curNode.y + 1) < map.size() ? curNode.y + 1 : map.size() - 1;    for (int curX = sX; curX <= eX; ++curX)    {        for (int curY = sY; curY <= eY; ++curY)        {            if (map[curX][curY].f == ENF_NORMAL)            {                openList.push_back(SPoint(curX, curY));                map[curX][curY].p   = curNode;                map[curX][curY].c.G = map[curNode.x][curNode.y].c.G                                       + static_cast<int>(sqrt((float)(abs(curX - curNode.x)                                       + abs(curY - curNode.y))) * 10);                                                    map[curX][curY].c.H = (abs(curX - endNode.x) + abs(curY - endNode.y)) * 10;                map[curX][curY].c.F = map[curX][curY].c.H + map[curX][curY].c.G;                map[curX][curY].f   = ENF_OPEN;            }            else if (map[curX][curY].f == ENF_OPEN)            {                int curG = map[curNode.x][curNode.y].c.G                             + static_cast<int>(sqrt((float)(abs(curX - curNode.x)                             + abs(curY - curNode.y))) * 10);                if (curG < map[curX][curY].c.G)  //经过当前节点的路径更短;                {                    map[curX][curY].c.G = curG;                    map[curX][curY].c.F = curG +map[curX][curY].c.H;                    map[curX][curY].p   = curNode;                }            }        }    }}void AStar(TArray &map, const SPoint &s, const SPoint &d){    uint mapSize = map.size();    vector<SPoint> openList;    openList.reserve(mapSize);    SPoint curNode = s;     while(curNode != d)    {        map[curNode.x][curNode.y].f = ENF_CLOSE;        //将当前节点加入闭节点列表;        UpdateOpenNode(map, curNode, d, openList);      //更新当前节点周围的相邻节点到开列表中;        //查找当前开列表中cost最小的节点;这里可做优化,将cost信息保存进来,用堆结构加速查找过程;        int minCost = INFI;        vector<SPoint>::iterator itor = openList.begin(), minItor;        for (; itor != openList.end(); ++itor)        {            if (map[itor->x][itor->y].c.F < minCost)            {                minItor = itor;                curNode = *itor;                minCost = map[itor->x][itor->y].c.F;            }        }        openList.erase(minItor);  //从openList中移除当前节点;    }}
0 0
原创粉丝点击