AI 隨機迷宮 迷宮求解

2022-03-06 02:04:11 字數 2939 閱讀 2798

本文記錄了,人工智慧中簡單的搜尋策略中的路徑搜尋策略中的a*演算法,來實現迷宮尋路的問題.(這只是一次本人的課外作業)

完整的程式原始碼已經傳送到我的git.這裡只記錄了我的思路和感想以及收穫.

產生隨機迷宮

迷宮求解沒有迷宮怎麼可以呢.而本人是個懶人,每次都要手動輸入迷宮,重複性的工作讓我很不爽.你可以在程式中用陣列定義乙個迷宮啊,有強迫症的我,怎麼可以這樣隨便的要求自己的程式呢.及時求解演算法的出來了,但是測試資料有限,還是讓我很不爽的,所以,乾脆先花一些時間,寫個隨機迷宮的產生吧.

遇事先搜尋,看看前輩有沒有經驗分享,站在前輩的肩膀上,你可以少走很多彎路.

本人搜尋到一篇**:基於圖的深度遍歷產生隨機迷宮的演算法研究,看了以後,發現**中有很多的錯誤,而且演算法也不簡潔,有很多地方完全可以非常簡化的,但是非要寫的那麼複雜,生怕別人可以看懂似得.所以,就按照自己的理解,簡單的實現了隨機迷宮的產生.

參考上圖,紅色(起始位置),綠色(終點位置).而我產生隨機迷宮的方法簡單,產生的迷宮有一定的侷限性.如圖所示,從起始位置(最左上角)開始,每次隨機的選取當前節點的右邊或下邊的節點作為擴充套件的節點.順便還要判斷一下下乙個結點是否越界.通過這種方法會產生一條從矩形的乙個點到另乙個點的最短路徑,該條路徑是沒有迴路的路徑,就這樣,當隨機選擇出一條路徑以後,其餘的點任意擺布,是牆是路都可以,最終我們一定會得到一條最短的路徑,我的簡單隨機迷宮誕生了.

至於更加完善的隨機迷宮的產生,以後有時間了再學習一下.

a*演算法遍歷

a*演算法中重要的由2張表,open表和close表.

open表存放的都是沒有擴充套件的節點,而且表裡的內容(fn=gn+hn)是按照從小到大排序的。

close表存放的都是已經擴充套件過的節點,也就說已經遍歷過的節點,這表裡的節點中就存在著最終的路徑。

a*演算法先是利用open表和close表找到最終的目標節點,然後倒序從close表裡依次把以前遍歷過的路徑節點找出來,即可得到完整的路徑。

就想上圖所示的簡單迷宮一樣,開始的時候,會同時擴充套件右邊和下面的節點,存入open表裡,然後選擇open表中f最小的值,而在這個例子中,選擇的是下面的方塊,所以就這樣沿著紅色箭頭的方向一直擴充套件下去,直到,發現open表中的2個節點有10和12,這時候,才調轉方向,拋棄12,選擇10((0,1)節點)繼續開始新的遍歷(藍色箭頭的方向),最終找到終點。

找到終點以後,圖中的陰影的結點都在close表裡面,然後,我們發現路徑中的g從終點到起點是倒序的,h則是公升序的。我們就利用這個特性來實現路徑的輸出。g=10的下乙個節點的特徵是(g=g-1&&節點是相鄰的)根據這個判斷,我們就會很容易的倒序找到完整的路徑了。詳細的實現的方法參見**。

我的收穫

花費了一周的時間來實現這個功能,使用的c++語言,而且中間也遇到了不少的困難。當你遇到的困難實在想不起好的解決方法的時候,那麼不妨先放下,做其他的事情.晚上睡覺的時候,或者吃放走路洗澡的時候,腦子裡想想就可以了.解決問題的關鍵是在一瞬間想起來的,實在不行的時候,不妨讓大腦放鬆一下,不必心急火燎,容易上火.

bug(1)

堆疊的溢位:以前寫程式的時候沒有遇到過這種問題,曾經都使用過上萬的資料空間,也沒有出現過問題,但是這次的二維陣列qt上面使用23*23,也就是迷宮的長和寬就出現這種情況了。長和寬23*23,那麼頂點總共529個,轉化為邊的關係則有529*529=279841,額,確實有點大。解決方法很簡單,定義成全域性變數或者結構裡面使用指標,函式裡面使用動態的malloc記憶體分配,就ok了。

翻譯過來就是算數異常,這個bug直到現在我也沒有解決,因為不妨礙我程式的執行,這個bug只在程式除錯的時候才出現。如下:

大家知道程式除錯的環境和執行的環境是不一樣的,就那qt來說吧,執行的時候mingw,而除錯的時候是gdb,根據圖示,這裡應該出現了k=0的情況,random產生的隨機數的範圍是0~k-1所以,出錯了。我是這麼想的,也可能錯了,如有見解,請指點。關於這次的程式,使我的gdb也崩潰了,害得我還重新安裝了qt。

參考資料這麼說的:出現了segmentation fault,基本上的原因是,非法的記憶體訪問。例如陣列的越界,在迴圈操作時迴圈變數的控制問題,也有字串拷貝時長度溢位,指標指向了非法的空間,還有就是申明乙個指標,但卻沒有對其初始化,就直接引用,或者沒有開闢記憶體空間就釋放記憶體,所以要檢查申請空間時間的成功。

程式設計習慣的改進:

說實話程式大了,**多了,有時候就不在意良好的程式設計習慣了。這次在遇到bug的時候,請教了qq群的網友,雖說最終的問題沒有解決,但是,給我提了不少寶貴的建議。

(1)變數的使用和定義盡量額緊湊,靠在一起。

(2)最重要的也就是這一句:不要在判斷語句中使用有***的語句。何為***?會改變程式狀態的語句。如下:

if(getchar()=='

y'||getchar()=='y'

){}

getchar()從緩衝區讀取乙個字元,讀乙個少乙個,那麼讀的過程中程式的狀態是不是改變了?

好的寫法如下:

char ch=toupper(getchar());

if('

y'==ch)

{}

學習的道路艱鉅而漫長.

迷宮問題求解(1) 簡單迷宮

標頭檔案 include include include include include maze.h define max 100 typedef struct position datatype typedef struct stack stack void stackinit stack s ...

A 演算法求解迷宮

cpp view plaincopy include include include using namespace std 方向向量 int direc 4 2 封閉,開放列表標記 enum flag 最小堆節點類 堆優先順序為 f g h g為當前的路徑長 h為估計當前位置到目標位置開銷探測 當...

迷宮求解(棧)

這篇部落格是借鑑了always 的部落格修改得到了,感謝他的幫助。採用了以棧為基礎,在棧的基礎上進行迷宮的求解,用stack和maze兩個檔案來實現功能。stack.h的實現如下 pragma once include include include include typedef int dire...