迷宫生成算法(1)深度优先搜索
接下来一段时间,想要研究下随机迷宫生成算法,打算在有空可时候偶尔更新一下这方面的学习过程。随机迷宫的生成算法有很多种,比如递归回溯,递归分割,随机Prime等等。今天是第一次尝试随机迷宫生成,就先试一下用递归的方法通过深度优先搜索来生成随机迷宫。
首先我们来明确一下基本观念,迷宫可以通过一个二维数组来表示,二维数组中的元素就表示存在于迷宫中的位置,他们可能是可以行走的路,也有可能是不能进入的障碍物或者围栏。我们只要通过两种不同的字符就可以标记障碍物和通道,比如我们使用false来表示一个位置是障碍物,而使用true来表示位置可以通行。在下面的例子中我们就沿用这个规定,整个迷宫可以使用一个二维的布尔型数组来表示。
接下来我们确定一下对迷宫的看法,我们认为一个迷宫只能有唯一解,也就是说从起点到终点不会有两条不一样的路线。而遍历迷宫的过程可以被看成是一个拆墙的过程,如果拆了一个墙会导致两个已经被标记为通道的方块连接,那么拆这面墙就是不合法的,这个条件是递归回溯过程中最重要的判定条件。
最后来看一下递归回溯算法的过程:
- 将初始位置设置为当前位置(入栈),然后将它标记为通路
- 从上,下,左,右四个方向寻找当前方块的相邻方块,判断找到的相邻方块周围是否有其他通路,如果有则继续寻找其他相邻方块,如果没有则选择该方块为当前方块(入栈)
- 标记当前方块为通路,然后重复进行上一个过程
- 如果当前方块的相邻方块都不满足条件,则恢复上一个方块为当前方块(出栈),并继续执行过程2
以上就是深度优先遍历生成随机迷宫的基本步骤,接下来我们看代码实现:
定义一个迷宫类,它的私有数据成员保存着记录迷宫状态的二维数组,查找方向,迷宫尺寸,入口点等信息:
class Maze
{
public:
//构造函数,通过传入的参数创建并创建并初始化二维数组
Maze(int row, int column);
ostream& print();
//设置迷宫入口的内联函数,注意这个入口并不是遍历起点,而是在边界上挖出的一个洞
void setEntry(int x,int y)
{
if (isValidEntry(x,y)) {
mazePtr[x - 1][y - 1] = true;
if (x == 1) {
startX = 2;
startY = y;
}
if (x == row) {
startX = row-1;
startY = y;
}
if (y == 1) {
startX = x;
startY = 2;
}
if (y == column) {
startX = 2;
startY = column-1;
}
//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<pair<int,int>> direction = {
{
1,0},{
0,1},{
-1,0},{
0,-1} };
unique_ptr<bool*[]> mazePtr;
};
然后我们在类外完成对构造函数的定义,他接受行列两个参数来动态创建一个布尔型二维数组,并与此同时初始化为false,允许通过初始化列表来为动态分配的内存初始化是C++11引入的新特性,这里为了方便管理堆内存,采用了智能指针类型unique_ptr来管理动态分配的内存,这种智能指针类型也是C++11新增的:
Maze::Maze(int row, int column):row(row),column(column)
{
mazePtr.reset(new bool*[row]);
for (int i = 0; i < row