生成迷宫



2019年06月22日    Author:Guofei

文章归类: 0x80_数据结构与算法    文章编号: 821001

版权声明:本文作者是郭飞。转载随意,但需要标明原文链接,并通知本人
原文链接:https://www.guofei.site/2019/06/22/maze.html


定义

  1. 我们讨论二维情况
  2. 可以通行的区域,我们叫做“路”,用1或2表示。具体说,1表示生成迷宫之前就已经存在的路,并且在迭代过程中还没有加入到迷宫体系中。2表示生成过程中加入到迷宫体系中的路。
  3. 不可通行的区域,我们叫做“墙”,用0或-1表示。其中0是可以被打通变成路的墙,-1是不能被打通的墙(海)

方案1:深度优先搜索

特点

  • 有一条特别长的主路
  • 路线很扭曲
import matplotlib.pyplot as plt
import numpy as np

# step1:生成一个网点图
length, width = 50, 50  # 定义迷宫大小
maze = np.zeros(shape=(length, width))
maze[::2, ::2] = 1

# 每次只能上下左右试探
step_set = np.array([[1, 0],
                     [-1, 0],
                     [0, 1],
                     [0, -1]])


def find_next_step(maze, point, step_set):
    # 用递归实现深度优先搜索
    step_set = np.random.permutation(step_set)
    for next_step in step_set:
        next_point = point + next_step * 2
        x, y = next_point
        if 0 <= x < length and 0 <= y < width:  # 在格子内
            if maze[x, y] == 1:  # 如果还没打通,就打通
                maze[x, y] = 2
                maze[(point + next_step)[0], (point + next_step)[1]] = 2
                maze, _, _ = find_next_step(maze, next_point, step_set)  # 深度优先搜索
    # 全部遍历后,还是找不到,就是这个叶节点没有下一步了,返回即可
    return maze, point, step_set


# 定义起点
point = np.array([0, 0])
find_next_step(maze, point, step_set)

# 至于终点,道路上的每个点都可以作为终点
plt.imshow(maze)
plt.show()

解释一下思路

step1:生成一个网点格子,下面黄色是道路,紫色是墙

step2:从起点出发,进行下面的深度优先搜索:
对于当前点,递归遍历上下左右4个最近的道路,
如果道路未被加入路径,就加入路径,移动到当前点
直到无法递归为止。

step3:得到迷宫并画图

方案2:广度优先搜索

既然有深度优先搜索,就有广度优先搜索。
实现很简单,就是深度优先搜索方案改一改。
地图特点:

  • 不会出现一条特别长的主路的情况

改进:分块生成迷宫

前面我们已经有了生成迷宫的方法,自然能想到分块生成迷宫,这种方法可以实现以下两种迷宫

  1. 有时候,我们不想让迷宫太复杂,想让某些分支路线限定在某个区域内。
  2. 有时候,我们不想让路径填充整个迷宫,想留下一片未开垦地。

先看要求2

我们只需要挖掉一些区域即可,例如

maze[4:9, 4:17] = -1
maze[12:39, 20:39] = -1

效果如下:

完整代码

import matplotlib.pyplot as plt
import numpy as np

# step1:生成一个网点图
length, width = 50, 50  # 定义迷宫大小
maze = np.zeros(shape=(length, width))
maze[::2, ::2] = 1
maze[4:9, 4:17] = -1
maze[12:39, 20:39] = -1
# 每次只能上下左右试探
step_set = np.array([[1, 0],
                     [-1, 0],
                     [0, 1],
                     [0, -1]])


def find_next_step(maze, point, step_set):
    # 用递归实现深度优先搜索
    step_set = np.random.permutation(step_set)
    for next_step in step_set:
        next_point = point + next_step * 2
        x, y = next_point
        if 0 <= x < length and 0 <= y < width:  # 在格子内
            if maze[x, y] == 1:  # 如果还没打通,就打通
                maze[x, y] = 2
                maze[(point + next_step)[0], (point + next_step)[1]] = 2
                maze, _, _ = find_next_step(maze, next_point, step_set)  # 深度优先搜索
    # 全部遍历后,还是找不到,就是这个叶节点没有下一步了,返回即可
    return maze, point, step_set


# 定义起点
point = np.array([0, 0])
find_next_step(maze, point, step_set)

# 至于终点,道路上的每个点都可以作为终点
plt.imshow(maze)
plt.show()

看要求1

我们在挖掉的区域内,生成一个小迷宫,然后把两个迷宫连接起来

import matplotlib.pyplot as plt
import numpy as np


def find_next_step(maze, point, step_set):
    # 用递归实现深度优先搜索
    length, width = maze.shape
    step_set = np.random.permutation(step_set)
    for next_step in step_set:
        next_point = point + next_step * 2
        x, y = next_point
        if 0 <= x < length and 0 <= y < width:  # 在格子内
            if maze[x, y] == 1:  # 如果还没打通,就打通
                maze[x, y] = 2
                maze[(point + next_step)[0], (point + next_step)[1]] = 2
                maze, _, _ = find_next_step(maze, next_point, step_set)  # 深度优先搜索
    # 全部遍历后,还是找不到,就是这个叶节点没有下一步了,返回即可
    return maze, point, step_set


length, width = 50, 50  # 定义迷宫大小
maze = np.zeros(shape=(length, width))
maze[::2, ::2] = 1
maze[4:9, 4:17] = -1
maze[12:39, 20:39] = -1
# 每次只能上下左右试探
step_set = np.array([[1, 0],
                     [-1, 0],
                     [0, 1],
                     [0, -1]])

point = np.array([0, 0])
find_next_step(maze, point, step_set)

# 在右下的方块里生成一个迷宫
maze1 = np.zeros_like(maze[12:39, 20:39])
maze1[::2, ::2] = 1
find_next_step(maze1, point, step_set)

# 把小迷宫覆盖到大迷宫上
maze[12:39, 20:39] = maze1
maze[11, 20] = 2  # 不要忘记把大迷宫和小迷宫连接起来

plt.imshow(maze)
plt.show()


您的支持将鼓励我继续创作!