迷宫生成-递归除法(它是如何工作的?)

Maze generation - recursive division (how it works?)

本文关键字:何工作 工作 递归 迷宫 除法      更新时间:2023-10-16

我想学习如何生成完美的迷宫。我正在努力理解递归除法算法。我不明白如何实现这个算法。这是我的代码:

bool maze[20][20];
void initMaze()
{
for(int i = 0; i < 20; i++)
for(int j = 0; j < 20; j++)
maze[i][j] = false;
for(int i = 0; i < 20; i++)
maze[0][i] = true;
for(int i = 0; i < 20; i++)
maze[19][i] = true;
for(int i = 0; i < 20; i++)
maze[i][0] = true;
for(int i = 0; i < 20; i++)
maze[i][19] = true;
}
int randNum(int min, int max)
{
return rand()%(max-min+1)+min;
}
void drawVWall(int minY, int maxY, int x)
{
int passage = randNum(minY, maxY);
for(int i = minY; i <= maxY; i++)
if(i != passage)
maze[i][x] = true;
}
void drawHWall(int minX, int maxX, int y)
{
int passage = randNum(minX, maxX);
for(int i = minX; i <= maxX; i++)
if(i != passage)
maze[y][i] = true;
}
void divison(int x, int y, int maxx, int maxy, int h)
{
if(h)
{
if(maxx <= 2)
return;
int wallY = randNum(y, maxy);
drawHWall(x, maxx, wallY);
if(wallY < maxy - wallY)
divison(x, wallY, maxx, maxy, !h);
else if(wallY > maxy - wallY)
divison(x, y, maxx, wallY, !h);
}
else
{
if(maxy <= 2)
return;
int wallX = randNum(x, maxx);
drawVWall(y, maxy, wallX);
if(wallX < maxx - wallX)
divison(wallX, y, maxx, maxy, !h);
else if(wallX > maxx - wallX)
divison(x, y, wallX, maxy, !h);
}
}
initMaze();
divison(2, 2, 18, 18, true);

这段代码有问题,因为它经常冻结程序(某个地方的无限循环),但如果它有效,它会生成这样的"迷宫":生成的"迷宫">

我不想问你我的代码。我只想了解如何实现这个算法,我错在哪里,我应该做什么。我需要生成一个没有封闭区域的完美迷宫。

首先,您必须决定如何设计迷宫。使用整个单元格来表示墙或通道。这意味着你对选择作为新墙和通道的数字有一些限制。在您的示例中,不应该创建厚墙,其中两个垂直墙相邻,它们之间没有通道。

用你的方法,一个N×CCD_ 2迷宫由CCD_;(2*N + 1)。"迷宫"坐标从0到N,"栅格"坐标从零到2*N + 1。在迷宫坐标中执行算法,并在创建墙时使用栅格坐标。

在网格坐标中,墙必须在偶数索引处,畜栏必须在奇数索引处。两个指数偶数总是最后迷宫中的一堵墙,两个指数奇数总是一个自由细胞。一个偶数一个奇数意味着可能穿过一堵墙。

举例来说,这里有a4×4迷宫:

X    0   1   2   3
x  0 1 2 3 4 5 6 7 8
# # # # # # # # #   0
#   +   +   +   #   1  0
# + # + # + # # #   2
#   +   +   +   #   3  1
# + # + # + # # #   4
#   +   +   +   #   5  2
# + # + # + # # #   6
#   +   +   +   #   7  3
# # # # # # # # #   8
y  Y

小写字母(xy)为网格坐标;大写字母(XY)是迷宫坐标。散列标记#总是墙,但加号+最终要么是通道,要么是墙。

第二个问题是递归本身。建造墙后,已将活动空间细分为两个区域。现在必须将算法应用于两个新区域。

所以不是:

if (wallY < maxy - wallY)
divison(x, wallY, maxx, maxy, !h);
else if (wallY > maxy - wallY)
divison(x, y, maxx, wallY, !h);

你应该这样做:

divison(x, wallY, maxx, maxy, !h);
divison(x, y, maxx, wallY, !h);

当然,你必须有一个条件来停止递归,但你已经有了:当空间太小时,你不会再建造更多的墙。

你的例子中的大房间表明你只进入了迷宫的一个新的部分。那些大房间是你不会经常去的。