【问题标题】:Python - backtracking maze generation recursive function understandingPython——回溯迷宫生成递归函数理解
【发布时间】:2018-09-08 05:24:19
【问题描述】:

我一直在寻找在 python 中创建迷宫的方法。
我在rosettacode 遇到了下面的代码。
我知道代码使用递归来构建迷宫。
我了解代码行并且知道我在阅读什么,并且我想使用该代码,但我缺少对该代码的关键理解。

这段代码中的递归函数究竟是如何知道何时停止的?

from random import shuffle, randrange

def make_maze(w = 16, h = 8):
    vis = [[0] * w + [1] for _ in range(h)] + [[1] * (w + 1)]
    ver = [["|  "] * w + ['|'] for _ in range(h)] + [[]]
    hor = [["+--"] * w + ['+'] for _ in range(h + 1)]

    def walk(x, y):
        vis[y][x] = 1

        d = [(x - 1, y), (x, y + 1), (x + 1, y), (x, y - 1)]
        shuffle(d)
        for (xx, yy) in d:
            if vis[yy][xx]: continue
            if xx == x: hor[max(y, yy)][x] = "+  "
            if yy == y: ver[y][max(x, xx)] = "   "
            walk(xx, yy)

    walk(randrange(w), randrange(h))

    s = ""
    for (a, b) in zip(hor, ver):
        s += ''.join(a + ['\n'] + b + ['\n'])
    return s

if __name__ == '__main__':
    print(make_maze())

【问题讨论】:

  • 滚动到您引用的页面顶部:Start at a random cell. Mark the current cell as visited, and get a list of its neighbors. For each neighbor, starting with a randomly selected neighbor: If that neighbor hasn't been visited, remove the wall between this cell and that neighbor, and then recurse with that neighbor as the current cell. - 当所有邻居都被访问时,它会停止。
  • 如果您将尺寸更改为 2 和 3 并注意How to debug small programs (#2),您可以自己调试它的工作...

标签: python python-3.x recursion depth-first-search backtracking


【解决方案1】:

将调试打印应用于您的代码:

from random import shuffle, randrange

def make_maze(w = 3, h =3):
    vis = [[0] * w + [1] for _ in range(h)] + [[1] * (w + 1)]
    ver = [["|  "] * w + ['|'] for _ in range(h)] + [[]]
    hor = [["+--"] * w + ['+'] for _ in range(h + 1)]

    def debugPrint():
        print("-"*16)
        s = ""
        for (a, b) in zip(hor, ver):
            s += ''.join(a + ['\n'] + b + ['\n'])
        print(s )

        for r in vis:
            print(r) 


    def walk(x, y):
        debugPrint()

        vis[y][x] = 1

        d = [(x - 1, y), (x, y + 1), (x + 1, y), (x, y - 1)]
        shuffle(d)
        for (xx, yy) in d:
            if vis[yy][xx]: continue
            if xx == x: hor[max(y, yy)][x] = "+  "
            if yy == y: ver[y][max(x, xx)] = "   "

            walk(xx, yy)



    walk(randrange(w), randrange(h))

    s = ""
    for (a, b) in zip(hor, ver):
        s += ''.join(a + ['\n'] + b + ['\n'])
    return s

if __name__ == '__main__':
    print(make_maze())

可视化正在发生的事情:

----------------
+--+--+--+
|  |  |  |
+--+--+--+
|  |  |  |
+--+--+--+
|  |  |  |
+--+--+--+


[0, 0, 0, 1]
[0, 0, 0, 1]
[0, 0, 0, 1]
[1, 1, 1, 1]
----------------
+--+--+--+
|  |  |  |
+--+--+--+
|  |  |  |
+  +--+--+
|  |  |  |
+--+--+--+


[0, 0, 0, 1]
[1, 0, 0, 1]
[0, 0, 0, 1]
[1, 1, 1, 1]
----------------
+--+--+--+
|  |  |  |
+--+--+--+
|  |  |  |
+  +--+--+
|     |  |
+--+--+--+


[0, 0, 0, 1]
[1, 0, 0, 1]
[1, 0, 0, 1]
[1, 1, 1, 1]
----------------
+--+--+--+
|  |  |  |
+--+--+--+
|  |  |  |
+  +--+--+
|        |
+--+--+--+


[0, 0, 0, 1]
[1, 0, 0, 1]
[1, 1, 0, 1]
[1, 1, 1, 1]
----------------
+--+--+--+
|  |  |  |
+--+--+--+
|  |  |  |
+  +--+  +
|        |
+--+--+--+


[0, 0, 0, 1]
[1, 0, 0, 1]
[1, 1, 1, 1]
[1, 1, 1, 1]
----------------
+--+--+--+
|  |  |  |
+--+--+  +
|  |  |  |
+  +--+  +
|        |
+--+--+--+


[0, 0, 0, 1]
[1, 0, 1, 1]
[1, 1, 1, 1]
[1, 1, 1, 1]
----------------
+--+--+--+
|  |     |
+--+--+  +
|  |  |  |
+  +--+  +
|        |
+--+--+--+


[0, 0, 1, 1]
[1, 0, 1, 1]
[1, 1, 1, 1]
[1, 1, 1, 1]
----------------
+--+--+--+
|        |
+--+--+  +
|  |  |  |
+  +--+  +
|        |
+--+--+--+


[0, 1, 1, 1]
[1, 0, 1, 1]
[1, 1, 1, 1]
[1, 1, 1, 1]
----------------
+--+--+--+
|        |
+--+  +  +
|  |  |  |
+  +--+  +
|        |
+--+--+--+


[1, 1, 1, 1]
[1, 0, 1, 1]
[1, 1, 1, 1]
[1, 1, 1, 1]

最终输出:

+--+--+--+
|        |
+--+  +  +
|  |  |  |
+  +--+  +
|        |
+--+--+--+

【讨论】:

  • 我做到了,但这是我的问题,我不能到达一个点,我被 1 包围,我在其他地方有一个 0,但在相邻单元格中没有?我可能在这里遗漏了一些非常明显的东西。
  • 是的,你可以,但这不是悲剧。在每一步中,所有“免费的”都被收集到d = [(x - 1, y), (x, y + 1), (x + 1, y), (x, y - 1)] 中,并且对于每一步,在对它们进行洗牌后使用递归。如果一个没有邻居并且没有被访问过,它将被递归标记为已访问。如果其中一个已经被其他循环访问过,它将忽略它以进行进一步的迷宫操作。
  • @Rxzlion 除了最后一个单元格之外的每个单元格都将被访问一次。最后一个只有已经访问过的邻居,所以for... 只会在其作用域if 中遇到continues,并且永远不会触及递归
猜你喜欢
  • 2014-05-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多