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

Posted

技术标签:

【中文标题】迷宫生成 - 递归除法(它是如何工作的?)【英文标题】:Maze generation - recursive division (how it works?) 【发布时间】:2017-01-09 17:41:02 【问题描述】:

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

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);

这段代码有问题,因为它经常冻结程序(某处的无限循环),但如果它有效,它会生成一个像这样的“迷宫”: Generated 'maze'

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

【问题讨论】:

递归似乎难倒很多人。一个常见的聪明的说法是:“一个人必须理解递归才能理解递归。”您可以从这个项目中退后一步,尝试使用更简单的问题来理解递归。这是 Wikipedia 的链接以开始使用。 en.wikipedia.org/wiki/Recursion. 查看这个可爱的debug 博客寻求帮助。从您到目前为止的帖子来看,您似乎没有做太多调试程序。您没有描述您对 RDA 的理解不足的地方,或者您的程序与您所理解的不匹配的地方。简而言之,“我不明白”和“它只是给了我这个 blob”不足以描述问题。 请注意,递归除法会产生丑陋的迷宫,因为长长的顶层墙很突出。见:weblog.jamisbuck.org/2011/1/12/… 非常感谢您的回答。 【参考方案1】:

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

使用您的方法,N × N 迷宫由 (2*N + 1) × (2*N + 1) 的数组表示。你有“迷宫”坐标 0 到 N 和“网格”坐标 0 到 2*N + 1。在创建墙壁时在迷宫坐标中执行算法并使用网格坐标。

在网格坐标中,墙壁必须在偶数索引处,而走廊必须在奇数索引处。两个索引偶数始终是最终迷宫中的一堵墙,两个索引奇数始终是一个空闲单元。一偶一奇表示有可能穿墙。

为了说明,这里是一个 4×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

小写字母(x,y)是网格坐标;大写字母(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);

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

您示例中的大房间表明您只递归到迷宫的一个新子部分。大房间是您没有递归到的房间。

【讨论】:

我明白了。谢谢你的解释,我会努力解决的。

以上是关于迷宫生成 - 递归除法(它是如何工作的?)的主要内容,如果未能解决你的问题,请参考以下文章

谁能解释这个除法算法是如何工作的?

数学:除法问题生成器

如何在不使用递归或`/`运算符的情况下进行除法?

excel表格怎么计算除法

在随机生成的迷宫上使用递归回溯

(C++)一行代码递归实现辗转相除法