隨機迷宮生成與尋路演算法(1)深度優先搜尋

2021-10-03 09:05:24 字數 4832 閱讀 9974

接下來一段時間,想要研究下隨機迷宮生成演算法,打算在有空可時候偶爾更新一下這方面的學習過程。隨機迷宮的生成演算法有很多種,比如遞迴回溯,遞迴分割,隨機prime等等。今天是第一次嘗試隨機迷宮生成,就先試一下用遞迴的方法通過深度優先搜尋來生成隨機迷宮。

首先我們來明確一下基本觀念,迷宮可以通過乙個二維陣列來表示,二維陣列中的元素就表示存在於迷宮中的位置,他們可能是可以行走的路,也有可能是不能進入的障礙物或者圍欄。我們只要通過兩種不同的字元就可以標記障礙物和通道,比如我們使用false來表示乙個位置是障礙物,而使用true來表示位置可以通行。在下面的例子中我們就沿用這個規定,整個迷宮可以使用乙個二維的布林型陣列來表示。

接下來我們確定一下對迷宮的看法,我們認為乙個迷宮只能有唯一解,也就是說從起點到終點不會有兩條不一樣的路線。而遍歷迷宮的過程可以被看成是乙個拆牆的過程,如果拆了乙個牆會導致兩個已經被標記為通道的方塊連線,那麼拆這面牆就是不合法的,這個條件是遞迴回溯過程中最重要的判定條件。

最後來看一下遞迴回溯演算法的過程:

將初始位置設定為當前位置(入棧),然後將它標記為通路

從上,下,左,右四個方向尋找當前方塊的相鄰方塊,判斷找到的相鄰方塊周圍是否有其他通路,如果有則繼續尋找其他相鄰方塊,如果沒有則選擇該方塊為當前方塊(入棧)

標記當前方塊為通路,然後重複進行上乙個過程

如果當前方塊的相鄰方塊都不滿足條件,則恢復上乙個方塊為當前方塊(出棧),並繼續執行過程2

以上就是深度優先遍歷生成隨機迷宮的基本步驟,接下來我們看**實現:

定義乙個迷宮類,它的私有資料成員儲存著記錄迷宮狀態的二維陣列,查詢方向,迷宮尺寸,入口點等資訊:

class

maze

if(x == row)

if(y ==1)

if(y == column)

//cout << mazeptr[x - 1][y - 1];}}

//建立迷宮

bool

createmaze()

;private

:bool

isinrange

(int x,

int y)

;bool

isvalidentry

(int x,

int y)

;//遞迴回溯的演算法的核心實現

bool

dig(

int x,

int y)

;int startx;

int starty;

int row;

int column;

vector

int,

int>> direction =,,

,}; unique_ptr<

bool*[

]> mazeptr;

};

然後我們在類外完成對建構函式的定義,他接受行列兩個引數來動態建立乙個布林型二維陣列,並與此同時初始化為false,允許通過初始化列表來為動態分配的記憶體初始化是c++11引入的新特性,這裡為了方便管理堆記憶體,採用了智慧型指標型別unique_ptr來管理動態分配的記憶體,這種智慧型指標型別也是c++11新增的:

maze::

maze

(int row,

int column)

:row

(row)

,column

(column);}

}

定義成員函式createmaze,這個函式用來執行迷宮生成演算法,通過呼叫另乙個私有成員dig來完成:

bool maze::

createmaze()

return

true

;}

然後就是實現dig函式,正如他的名字所顯示的那樣,該函式所做的就是從乙個起點開始挖掘障礙物,只要條件允許(存在不鄰接多個路徑的新方塊)他總是盡可能的去多挖掘新的方塊:

bool maze::

dig(

int x,

int y)

mazeptr[x -1]

[y -1]

=true

;//隨機改變方向

//random_shuffle(direction.begin(),direction.end());

for(

int i =

0; i <

4; i++)if

(mazeptr[tmpx-1]

[tmpy-1]

==false)}

}return

true

;}

剩下的就是一些提供輔助功能的成員函式了,比如判斷指定方塊是否超出迷宮邊界,計算入口是否合法,通過入口尋找遍歷起點,列印迷宮狀態等等,他們的實現如下:

bool maze::

isinrange

(int x,

int y)

if(y <=

0or y >= column)

return

true;}

bool maze::

isvalidentry

(int x,

int y)

if(x ==

1or x == row or y ==

1or y == column)

return

false;}

ostream& maze::

print()

cout << endl;

}return cout;

}

呼叫這段**可以得到下圖這種迷宮:

顯然這樣生成的迷宮不具備足夠的隨機性,接著在上面的遞迴回溯中新增一些小的改變,讓每次遍歷方向隨機選擇,這樣就可以得到下面這樣的**:

#include

#include

#include

#include

#include

#include

#include

#include

#include

using

namespace std;

class

maze

if(x == row)

if(y ==1)

if(y == column)

//cout << mazeptr[x - 1][y - 1];}}

bool

createmaze()

;private

:bool

isinrange

(int x,

int y)

;bool

isvalidentry

(int x,

int y)

;bool

dig(

int x,

int y)

;int startx;

int starty;

int row;

int column;

vector

int,

int>> direction =,,

,}; unique_ptr<

bool*[

]> mazeptr;};

bool maze::

isinrange

(int x,

int y)

if(y <=

0or y >= column)

return

true;}

bool maze::

dig(

int x,

int y)

mazeptr[x -1]

[y -1]

=true

;//每次遍歷四個方向之前,對方向進行一次隨機洗牌

random_shuffle

(direction.

begin()

,direction.

end())

;for

(int i =

0; i <

4; i++)if

(mazeptr[tmpx-1]

[tmpy-1]

==false)}

}return

true;}

bool maze::

createmaze()

return

true;}

bool maze::

isvalidentry

(int x,

int y)

if(x ==

1or x == row or y ==

1or y == column)

return

false;}

ostream& maze::

print()

cout << endl;

}return cout;

}maze::

maze

(int row,

int column)

:row

(row)

,column

(column);}

}int

main

(int argc,

char

*ar**)

這次結果如下,隨機性增強了很多:

這次就先做著寫,接下來在慢慢補充改進。

隨機迷宮生成與尋路演算法(3)深度優先搜尋

該方法很容易理解 首先我們將迷宮的起始點入棧將棧頂元素標記為當前座標,然後按照已經定義好的方向陣列依序從上 下 左 右四個方向 方向可以是任意的,但沒必要每次都進行隨機選取 來遍歷當前座標的相鄰方塊如果這個取得的方塊是合法的 也即是說這個方塊不是邊界,不是障礙物,並且沒有標記為路線或者死胡同 則結束...

學習筆記 迷宮生成與尋路演算法

2016年5月12日 更新 本來一直想寫乙個遊戲,但是自己的功力又不夠,正好在 資料結構 一書中看到了棧應用之迷宮尋路演算法,所以打算寫乙個自動生成隨機迷宮並可以自動解迷宮的程式。我本來打算用c寫的,但是寫起來卻不太順手,一方面是我對c的語法不太了解,另一方面是c在好多地方反而不夠靈活。比如,當函式...

C語言 老鼠走迷宮 深度尋路演算法

這個是學校的課設,剛開始有點頭疼,但是感覺越做越有意思了,於是就有如下 可能相較於大佬還有差距,但是這是我目前所能做的最優的程式了吧!話不多說,說一下 的核心內容吧!迷宮是通過二維陣列構造的,二維組中的數字2代表牆體,0是通路,1是老鼠,3代表糧 void game 走迷宮遊戲,包含時間統計,以及對...