接下來一段時間,想要研究下隨機迷宮生成演算法,打算在有空可時候偶爾更新一下這方面的學習過程。隨機迷宮的生成演算法有很多種,比如遞迴回溯,遞迴分割,隨機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 走迷宮遊戲,包含時間統計,以及對...