算法自动生成迷宫地图


前言

最近学习了随机生成迷宫的算法, 分享学习经验以及碰到的问题点。目前学习两个算法 生成随机地图, 深度优先算法和广度优先算法来生成迷宫。比较下他们的不同点。

在程序中,我们用数组M表示所有的单元格子的属性,并用turtle 库来画图。用红色单元格来表示当前遍历到单元格。

一、什么是(DFS)深度优先算法?

简单来说它是一头扎到底的玩法。我们选择一条支路,尽可能不断地深入,如果遇到死路就往回退,回退过程中如果遇到没探索过的支路,就进入该支路继续深入。如此循环反复直到把所有的单元格都遍历了。

深度优先算法实现步骤

1.引入库

代码如下:

import random
import numpy as np
from turtle import *
import time

2.初始化参数

代码如下:

#初始化参数
num_rows = 20 # 生成迷宫的行数
num_cols = 20 # 生成迷宫的列数

M = np.zeros((num_rows, num_cols, 5), dtype=np.uint8)
# 阵列M将保存每个单元的阵列信息。
# 前四个坐标告诉墙壁在那些边上是否存在
# 和第五个指示在搜索中是否已访问该单元格。
# M【上,右,下,左,是否被访问】

# 我们先把第一个单元格最和后一个墙打开。
M[0, 0, 0] = 1
M[num_rows-1, num_cols-1, 2] = 1

#如下是turtle模块的初始化
tracer(0)# 最快生成图
ht()# 隐藏画笔
pensize(1)#画笔大小设为1

3.Turtle画方格函数

代码如下:

def pengoto(x, y):
    up()
    goto(x, y)
    down()


def drawing(r, c, M):
    x = 20*c-200
    y = 200-20*r
    pengoto(x, y)
    for i in range(4):
        if M[i] == 1:
            pencolor('blue')
            fd(1)
            pencolor('white')
            fd(19)
            right(90)
        else:
            pencolor('blue')
            fd(20)
            right(90)

4.开始生成数组并调用Turtle画图

# 设置开始的行和列
r = 0
c = 0
history = [(r, c)]  # 这个是历史访问的单元格列表。
n = 0  # 砸墙的数量。
# 从初始单元个一路开墙并进入下一个单元格,如果无路可走则返回。
# 我们使用while循环来执行此操作,重复该循环直到n=所有的单元格数-1.说明所有的单元格都是通的了。
while history:
    M[r, c, 4] = 1  #将此位置指定为已访问
    
    #检查相邻单元格是否可移动去,注意上下左右的边界。 
    check = []
    if c > 0 and M[r, c-1, 4] == 0:
        check.append('L')
    if r > 0 and M[r-1, c, 4] == 0:
        check.append('U')
    if c < num_cols-1 and M[r, c+1, 4] == 0:
        check.append('R')
    if r < num_rows-1 and M[r+1, c, 4] == 0:
        check.append('D')

    if len(check): #如果有单元可以去
        history.append([r, c])
        n += 1
        move = random.choice(check)#随机打开一堵墙
        # 注意数组[上, 右,下,左,1]
        if move == 'L':  
            M[r, c, 3] = 1
            c = c-1
            M[r, c, 1] = 1
        if move == 'U':
            M[r, c, 0] = 1
            r = r-1
            M[r, c, 2] = 1
        if move == 'R':
            M[r, c, 1] = 1
            c = c+1
            M[r, c, 3] = 1
        if move == 'D':
            M[r, c, 2] = 1
            r = r+1
            M[r, c, 0] = 1
    else:  #如果发现没有下个单元格可以去,我们要回溯。
        r, c = history.pop()
    # 红色显示当前单元格子
    clear()#清理下,不然内存会被占用
    fillcolor("red")
    begin_fill()
    drawing(r, c, M[r, c])
    end_fill()
    # 调用turtle画图显示当前整个地图状态。
    for i in range(num_rows): 
        for j in range(num_cols):
            drawing(i, j, M[i, j])
            update()#更新下,不然turtle会卡死
    time.sleep(0.5)
    if n == num_cols*num_rows-1:  # 当砸墙的数量等于单元格子的数量-1时结束循环。
        break

done()

二、什么是(BFS)广度优先算法?

广度优先搜索是按层来处理顶点,距离开始点最近的那些顶点首先被访问,而最远的那些顶点则最后被访问,这个和树的层序变量很像,BFS的代码使用了一个队列。Prim

广度优先算法实现步骤

1.引入库

代码如下:

import random
import numpy as np
from turtle import *
import timet

2.初始化参数

代码如下:

#初始化参数
num_rows = 20 # 生成迷宫的行数
num_cols = 20 # 生成迷宫的列数

M = np.zeros((num_rows, num_cols, 5), dtype=np.uint8)
# 阵列M将保存每个单元的阵列信息。
# 前四个坐标告诉墙壁在那些边上是否存在
# 和第五个指示在搜索中是否已访问该单元格。
# M【上,右,下,左,是否被访问】

# 我们先把第一个单元格最和后一个墙打开。
M[0, 0, 0] = 1
M[num_rows-1, num_cols-1, 2] = 1

#如下是turtle模块的初始化
tracer(0)# 最快生成图
ht()# 隐藏画笔
pensize(1)#画笔大小设为1

3.Turtle画方格函数

代码如下:

def pengoto(x, y):
    up()
    goto(x, y)
    down()


def drawing(r, c, M):
    x = 20*c-200
    y = 200-20*r
    pengoto(x, y)
    for i in range(4):
        if M[i] == 1:
            pencolor('blue')
            fd(1)
            pencolor('white')
            fd(19)
            right(90)
        else:
            pencolor('blue')
            fd(20)
            right(90)

4.开始生成数组并调用Turtle画图

# 设置开始的行和列
r = 0
c = 0
history = [(r, c)]  # 这个是历史访问的单元格列表。
n = 0  # 砸墙的数量。
while history:
    # 随机选择一个可以敲墙的单元格
    r, c = random.choice(history)
    M[r, c, 4] = 1  # 把单元设成以访问
    history.remove((r, c))
    check = []
#如果随机选择的单元格具有多个边
#将其连接到现有的迷宫,
    if c > 0:
        if M[r, c-1, 4] == 1:
            check.append('L')
        elif M[r, c-1, 4] == 0:
            history.append((r, c-1))
            M[r, c-1, 4] = 2
    if r > 0:
        if M[r-1, c, 4] == 1:
            check.append('U')
        elif M[r-1, c, 4] == 0:
            history.append((r-1, c))
            M[r-1, c, 4] = 2
    if c < num_cols-1:
        if M[r, c+1, 4] == 1:
            check.append('R')
        elif M[r, c+1, 4] == 0:
            history.append((r, c+1))
            M[r, c+1, 4] = 2
    if r < num_rows-1:
        if M[r+1, c, 4] == 1:
            check.append('D')
        elif M[r+1, c, 4] == 0:
            history.append((r+1, c))
            M[r+1, c, 4] = 2
# 随机前往一个边界墙.
    if len(check):
    	n+=1
        move = random.choice(check)
        if move == 'L':  # [上,右,下,左,1]
            M[r, c, 3] = 1
            c = c-1
            M[r, c, 1] = 1
        if move == 'U':
            M[r, c, 0] = 1
            r = r-1
            M[r, c, 2] = 1
        if move == 'R':
            M[r, c, 1] = 1
            c = c+1
            M[r, c, 3] = 1
        if move == 'D':
            M[r, c, 2] = 1
            r = r+1
            M[r, c, 0] = 1

    # 红色方格显示当前单元格子位置
    clear()#清理下,不然内存会一直被占用。
    fillcolor("red")
    begin_fill()
    drawing(r, c, M[r, c])
    end_fill()
    # 调用turtle画图显示当前整个地图状态。
    for i in range(num_rows): 
        for j in range(num_cols):
            drawing(i, j, M[i, j])
            update()#需要跟新下,不然会卡死
    time.sleep(0.5)
    if n == num_cols*num_rows-1:  # 当砸墙的数量等于单元格子的数量-1时结束循环。
        break

done()

总结

1、深度优先算法:是对每一个可能的分支路径深入到不能再深入为止,深度优先法生成的迷宫扭曲,有着一条明显的主路。
2、广度优先算法:系统地展开并检查图中的所有节点,直到遍历完成。

程序生产的图片如下:
在这里插入图片描述
视频如下:

深度优先算法和广度优先算法的生成迷宫

  • 2
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值