最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

如何用C++實現(xiàn)A*尋路算法

 更新時間:2021年06月16日 09:55:04   作者:KillerAery  
尋路是游戲比較重要的一個組成部分。因為不僅AI還有很多地方(例如RTS游戲里操控人物點到地圖某個點,然后人物自動尋路走過去)都需要用到自動尋路的功能。本文將介紹一個經(jīng)常被使用且效率理想的尋路方法-A*尋路算法,并且提供額外的優(yōu)化思路

一、A*算法介紹

尋路,即找到一條從某個起點到某個終點的可通過路徑。而因為實際情況中,起點和終點之間的直線方向往往有障礙物,便需要一個搜索的算法來解決。

有一定算法基礎的同學可能知道從某個起點到某個終點通常使用深度優(yōu)先搜索(DFS),DFS搜索的搜索方向一般是8個方向(如果不允許搜索斜向,則有4個),但是并無優(yōu)先之分。

為了讓DFS搜索更加高效,結(jié)合貪心思想,我們給搜索方向賦予了優(yōu)先級,直觀上離終點最近的方向(直觀上的意思是無視障礙物的情況下)為最優(yōu)先搜索方向,這就是A*算法。

二、A*算法步驟解析

(如下圖,綠色為起點,紅色為終點,藍色為不可通過的墻。)

從起點開始往四周各個方向搜索。

(這里的搜索方向有8個方向)

為了區(qū)分搜索方向的優(yōu)先級,我們給每個要搜索的點賦予2個值。

G值(耗費值):指從起點走到該點要耗費的值。

H值(預測值):指從該點走到終點的預測的值(從該點到終點無視障礙物情況下預測要耗費的值,也可理解成該點到終點的直線距離的值)

在這里,值 = 要走的距離

(實際上,更復雜的游戲,因為地形不同(例如陷阱,難走的沙地之類的),還會有相應不同的權(quán)值:值 = 要走的距離 * 地形權(quán)值)

我們還定義直著走一格的距離等于10,斜著走一格的距離等于14(因為45°斜方向的長度= sqrt(10^2+10^2) ≈ 14)

F值(優(yōu)先級值):F = G + H

這條公式意思:F是從起點經(jīng)過該點再到達終點的預測總耗費值。通過計算F值,我們可以優(yōu)先選擇F值最小的方向來進行搜索。

(每個點的左上角為F值,左下角為G值,右下角為H值)

計算出每個方向?qū)c的F,G,H值后,

還需要給這些點賦予當前節(jié)點的指針值(用于回溯路徑。因為一直搜下去搜到終點后,如果沒有前一個點的指針,我們將無從得知要上次經(jīng)過的是哪個點,只知道走到終點最終耗費的最小值是多少)

然后我們將這些點放入openList(開啟列表:用于存放可以搜索的點)

然后再將當前點放入closeList(關(guān)閉列表:用于存放已經(jīng)搜索過的點,避免重復搜索同一個點)

然后再從openList取出一個F值最?。ㄗ顑?yōu)先方向)的點,進行上述同樣的搜索。

在搜索過程中,如果搜索方向上的點是障礙物或者關(guān)閉列表里的點,則跳過之。

通過遞歸式的搜索,多次搜索后,最終搜到了終點。

搜到終點后,然后通過前一個點的指針值,我們便能從終點一步步回溯通過的路徑點。

(紅色標記了便是回溯到的點)

三、A*算法優(yōu)化思路

3.1、openList使用優(yōu)先隊列(二叉堆)

可以看到openlist(開啟列表),需要實時添加點,還要每次取出最小值的點。

所以我們可以使用優(yōu)先隊列(二叉堆)來作為openList的容器。

優(yōu)先隊列(二叉堆):插入一個點的復雜度為O(logN),取出一個最值點復雜度為O(logN)

3.2、障礙物列表,closeList 使用二維表(二維數(shù)組)

由于障礙物列表和closeList僅用來檢測是否能通過,所以我們可以使用bool二維表來存放。

//假設已經(jīng)定義Width和Height分別為地圖的長和寬
bool barrierList[Width][Height];
bool closetList[Width][Height];

有某個點(Xa,Yb),可以通過

if(barrierList[Xa][Yb]&&closeList[Xa][Yb])來判斷。

因為二維表用下標訪問,效率很高,但是耗空間比較多。(三維地圖使用三維表則更耗內(nèi)存。不過現(xiàn)在計算機一般都不缺內(nèi)存空間,所以盡量提升運算時間為主)

這是一個典型的犧牲內(nèi)存空間換取運算時間的例子。

3.3、深度限制

有時要搜的路徑非常長,利用A*算法搜一次付出的代價很高,造成游戲的卡頓。

那么為了保證每次搜索不會超過一定代價,可以設置深度限制,每搜一次則深度+1,搜到一定深度限制還沒搜到終點,則返還失敗值。

四、A*算法實現(xiàn)(C++代碼)

#include <iostream>
#include <list>
#include <vector>
#include <queue>

struct OpenPoint{
    int x;
    int y;
    int cost;                 // 耗費值
    int pred;                 // 預測值
    OpenPoint* father;        // 父節(jié)點
    OpenPoint() = default;
    OpenPoint(int pX,int pY, int endX, int endY, int c, OpenPoint* fatherp) : x(pX),y(pY),cost(c), father(fatherp) {
        //相對位移x,y取絕對值
        int relativeX = std::abs(endX - pX);
        int relativeY = std::abs(endY - pY);
        //x,y偏移值n
        int n = relativeX - relativeY;
        //預測值pred = (max–n)*14+n*10+c
        pred = std::max(relativeX, relativeY) * 14 - std::abs(n) * 4 + c;
    }
};

//比較器,用以優(yōu)先隊列的指針類型比較
struct OpenPointPtrCompare {
    bool operator()(OpenPoint* a, OpenPoint* b) {
        return a->pred > b->pred;
    }
};

const int width = 30;            //地圖長度
const int height = 100;          //地圖高度
char mapBuffer[width][height];   //地圖數(shù)據(jù)
int depth = 0;                   //記錄深度
const int depthLimit = 2000;     //深度限制
bool closeAndBarrierList[width][height];    //記錄障礙物+關(guān)閉點的二維表
//八方的位置
int direction[8][2] = { {1,0},{0,1},{-1,0},{0,-1},{1,1},{ -1,1 },{ -1,-1 },{ 1,-1 } };
//使用最大優(yōu)先隊列
std::priority_queue<OpenPoint*, std::vector<OpenPoint*>, OpenPointPtrCompare> openlist;
//存儲OpenPoint的內(nèi)存空間
std::vector<OpenPoint> pointList = std::vector<OpenPoint>(depthLimit);

//是否在障礙物或者關(guān)閉列表
inline bool inBarrierAndCloseList(int pX,int pY) {
    if (pX < 0 || pY < 0 || pX >= width || pY >= height)
        return true;
    return closeAndBarrierList[pX][pY];
}

//創(chuàng)建一個開啟點
inline OpenPoint* createOpenPoint(int pX,int pY,int endX,int endY, int c, OpenPoint* fatherp) {
    pointList.emplace_back(pX,pY,endX,endY, c, fatherp);
    return &pointList.back();
}

// 開啟檢查,檢查父節(jié)點
void open(OpenPoint& pointToOpen, int endX,int endY) {
    //將父節(jié)點從openlist移除
    openlist.pop();
    //深度+1
    depth++;
    //檢查p點八方的點
    for (int i = 0; i < 4; ++i)
    {
        int toOpenX = pointToOpen.x + direction[i][0];
        int toOpenY = pointToOpen.y + direction[i][1];
        if (!inBarrierAndCloseList(toOpenX,toOpenY)) {
            openlist.push(createOpenPoint(toOpenX, toOpenY, endX,endY, pointToOpen.cost + 10, &pointToOpen));
        }
    }
    for (int i = 4; i < 8; ++i)
    {
        int toOpenX = pointToOpen.x + direction[i][0];
        int toOpenY = pointToOpen.y + direction[i][1];
        if (!inBarrierAndCloseList(toOpenX, toOpenY)) {
            openlist.push(createOpenPoint(toOpenX, toOpenY, endX, endY, pointToOpen.cost + 14, &pointToOpen));
        }
    }
    //最后移入closelist
    closeAndBarrierList[pointToOpen.x][pointToOpen.y] = true;
}

//開始搜索路徑
std::list<OpenPoint*> findway(int startX,int startY, int endX,int endY) {
    std::list<OpenPoint*> road;
    // 創(chuàng)建并開啟一個父節(jié)點
    openlist.push(createOpenPoint(startX,startY, endX,endY, 0, nullptr));
    OpenPoint* toOpen = nullptr;
    //重復尋找預測和花費之和最小節(jié)點開啟檢查
    while (!openlist.empty())
    {
        toOpen = openlist.top();
        // 找到終點后,則停止搜索
        if (toOpen->x == endX && toOpen->y ==endY) {break;}//若超出一定深度(1000深度),則搜索失敗
        if (depth >= depthLimit) {
            toOpen = nullptr;
            break;
        }
        open(*toOpen, endX,endY);
    }
    for (auto rs = toOpen; rs != nullptr; rs = rs->father) {road.push_back(rs);}
    return road;
}

//創(chuàng)建地圖
void createMap() {
    for (int i = 0; i < width; ++i)
        for (int j = 0; j < height; ++j) {
            //五分之一概率生成障礙物,不可走
            if (rand() % 5 == 0) {
                mapBuffer[i][j] = '*';
                closeAndBarrierList[i][j] = true;
            }
            else {
                mapBuffer[i][j] = ' ';
                closeAndBarrierList[i][j] = false;
            }
        }
}

//打印地圖
void printMap() {
    for (int i = 0; i < width; ++i) {
        for (int j = 0; j < height; ++j)
            std::cout << mapBuffer[i][j];
        std::cout << std::endl;
    }
    std::cout << std::endl << std::endl << std::endl;
}

int main() {
    //起點
    int beginX = 0;
    int beginY = 0;
    //終點
    int endX = 29;
    int endY = 99;
    //創(chuàng)建地圖
    createMap();
    //保證起點和終點都不是障礙物
    mapBuffer[beginX][beginY] = mapBuffer[endX][endY] = ' ';
    closeAndBarrierList[beginX][beginY] = closeAndBarrierList[endX][endY] = false;
    //A*搜索得到一條路徑
    std::list<OpenPoint*> road = findway(beginX,beginY,endX,endY);
    //將A*搜索的路徑經(jīng)過的點標記為'O'
    for (auto& p : road){mapBuffer[p->x][p->y] = 'O';}
    //打印走過路后的地圖
    printMap();
    system("pause");
    return 0;
}

示例效果:

以上就是如何用C++實現(xiàn)A*尋路算法的詳細內(nèi)容,更多關(guān)于C++ A*尋路算法的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • C++實現(xiàn)二叉樹及堆的示例代碼

    C++實現(xiàn)二叉樹及堆的示例代碼

    這篇文章主要介紹了C++實現(xiàn)二叉樹及堆的示例代碼,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-04-04
  • 淺談C/C++中的static與extern關(guān)鍵字的使用詳解

    淺談C/C++中的static與extern關(guān)鍵字的使用詳解

    本篇文章是對C/C++中的static與extern關(guān)鍵字的使用進行了詳細的分析介紹,需要的朋友參考下
    2013-05-05
  • Qt信號與槽知識點總結(jié)歸納

    Qt信號與槽知識點總結(jié)歸納

    信號和槽是一種高級接口,應用于對象之間的通信,它是QT的核心特性,下面這篇文章主要給大家介紹了關(guān)于Qt信號與槽知識點總結(jié)歸納的相關(guān)資料,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下
    2022-12-12
  • 淺談do {...} while (0) 在宏定義中的作用

    淺談do {...} while (0) 在宏定義中的作用

    下面小編就為大家?guī)硪黄獪\談do {...} while (0) 在宏定義中的作用。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-12-12
  • C++遍歷文件夾獲取文件列表

    C++遍歷文件夾獲取文件列表

    這篇文章主要為大家詳細介紹了C++遍歷文件夾獲取文件列表的相關(guān)資料,感興趣的小伙伴們可以參考一下
    2016-05-05
  • 用c語言實現(xiàn)《狼人殺》游戲發(fā)牌系統(tǒng)

    用c語言實現(xiàn)《狼人殺》游戲發(fā)牌系統(tǒng)

    大家好,本篇文章主要講的是用c語言實現(xiàn)《狼人殺》游戲發(fā)牌系統(tǒng),感興趣的同學趕快來看一看吧,對你有幫助的話記得收藏一下
    2022-01-01
  • c++ 有趣的動態(tài)轉(zhuǎn)換

    c++ 有趣的動態(tài)轉(zhuǎn)換

    這篇文章主要介紹了c++ 動態(tài)轉(zhuǎn)換的相關(guān)資料,幫助大家更好的理解和使用c++編程,感興趣的朋友可以了解下
    2020-09-09
  • C語言實現(xiàn)飛機游戲(2)

    C語言實現(xiàn)飛機游戲(2)

    這篇文章主要介紹了C語言實現(xiàn)飛機游戲的第二部分,進行功能完善,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-05-05
  • 關(guān)于C語言qsort函數(shù)詳解

    關(guān)于C語言qsort函數(shù)詳解

    這篇文章主要介紹了關(guān)于C語言qsort函數(shù)詳解的相關(guān)資料,需要的朋友可以參考下面文章內(nèi)容
    2021-09-09
  • VC++基于Dx實現(xiàn)的截圖程序示例代碼

    VC++基于Dx實現(xiàn)的截圖程序示例代碼

    這篇文章主要介紹了VC++基于Dx實現(xiàn)的截圖程序示例代碼,比較實用的功能,需要的朋友可以參考下
    2014-07-07

最新評論

石城县| 那曲县| 大同市| 多伦县| 灵台县| 福鼎市| 凌源市| 沈阳市| 万载县| 西乌珠穆沁旗| 茶陵县| 甘德县| 昌宁县| 黄龙县| 随州市| 阿拉善左旗| 方山县| 九龙县| 盘山县| 洛隆县| 普兰店市| 伊吾县| 凤庆县| 新昌县| 通山县| 永年县| 丰原市| 渑池县| 靖远县| 丹江口市| 静宁县| 志丹县| 汉中市| 玉田县| 科技| 赣州市| 内黄县| 永修县| 长治市| 中阳县| 洪雅县|