算法学习笔记:随机迷宫


随机迷宫算法

迷宫生成算法也有很多种,也正是由于结果随机,反过来讲就意味着该问题由无数种解,所以它完全可以利用回溯的思想。

常见算法由三种:

  1. 深度优先算法
  2. 随机prim算法
  3. 十字分割法

1. 深度优先算法

想象你是一个土拨鼠在挖洞,你不知道往哪个方向挖?这时候应该怎么做呢?通常来说,你会在这个点做上标记,然后随机选择一个方向挖,挖通一堵墙之后,再随机选择一个方向,并做上标记,然后继续挖挖墙。当你挖到了死路,也就是再挖就挖穿了的情况下,你只能往回走,走到上一个标记的岔路口,然后选择其他的方向继续挖墙。如此往复,直到你挖遍整个地图,你回头一看,哇,一个迷宫就挖好了!

初始迷宫

首先确定标准初始迷宫形式:

  1. 长宽必须为奇数
  2. 所有的双奇数坐标为道路,其余为墙
    在这里插入图片描述

算法

  1. 初始化迷宫,如 初始迷宫 所示,将所有的道路加入未访问列表
  2. 随意选择一个道路作为出发点,并将之移除未访问列表
  3. 维护一个分支栈
  4. 只要迷宫中还存在未访问的道路,进入循环:
    1. 对于当前点,维护一个相邻点列表。
    2. 搜索当前道路的相邻道路,如果该带路未被访问过,则加入相邻点列表。
    3. 如果存在这样的相邻点:
      1. 将当前道路压入分支栈
      2. 随机选择一个相邻点
      3. 移除相邻点与当前点之间的墙壁
      4. 将相邻点作为出发点,并将之移除未访问列表,进入循环。
    4. 如果找不到符合要求的相邻点
      1. 就意味着此条分支已经走到尽头
      2. 此时从分支栈当中弹出一个新的元素,进入循环。

代码

import random
import numpy as np
import matplotlib.pyplot as plt

# 深度优先算法:
# 1. 初始化迷宫,如 **初始迷宫** 所示,将所有的道路加入未访问列表
# 2. 随意选择一个道路作为出发点,并将之移除未访问列表
# 3. 维护一个分支栈
# 4. 只要迷宫中还存在未访问的道路,进入循环:
# 	1.  对于当前点,维护一个相邻点列表。
# 	2. 搜索当前道路的相邻道路,如果该带路未被访问过,则加入相邻点列表。
# 	3. 如果存在这样的相邻点:
# 		1. 将当前道路压入分支栈
# 		2. 随机选择一个相邻点
# 		3. 移除相邻点与当前点之间的墙壁
# 		4. 将相邻点作为出发点,并将之移除未访问列表,进入循环。
# 	4. 如果找不到符合要求的相邻点
# 		1. 就意味着此条分支已经走到尽头
# 		2. 此时从分支栈当中弹出一个新的元素,进入循环。

row = 31
col = 73
shape = (row, col)
unvisited = []

# 生成矩阵
matrix = np.ones(shape)
for i in range(row):
    for j in range(col):
        if i % 2 != 0 and j % 2 != 0:
            matrix[i, j] = 0
            # 未访问道路列表
            unvisited.append((i, j))

# 起点
r, c = 1, 1
# 删除未访问
unvisited.remove((r, c))
# 栈
stack = []
# 当还存在未访问的迷宫单元,进入循环
while unvisited:
    # 当前单元必须在矩阵之中,否者退出并从未访问列表当中移除
    if r in range(1, row - 1) and c in range(1, col - 1):
        # 搜索当前单元是否有未被访问过的相邻单元
        neighbour = []
        if (r - 2, c) in unvisited:
            neighbour.append((r - 2, c))
        if (r + 2, c) in unvisited:
            neighbour.append((r + 2, c))
        if (r, c - 2) in unvisited:
            neighbour.append((r, c - 2))
        if (r, c + 2) in unvisited:
            neighbour.append((r, c + 2))
        # 如果有相邻的单元
        if neighbour:
            # 将当前迷宫单元入栈
            stack.append((r, c))
            # 随机选择一个相邻单元
            r_new, c_new = random.choice(neighbour)
            # 移除当前迷宫单元与相邻迷宫单元的墙,中间的墙坐标就是横纵坐标的平均值
            r_wall = int((r + r_new) / 2)
            c_wall = int((c + c_new) / 2)
            matrix[r_wall, c_wall] = False
            # 用相邻迷宫单元作为当前迷宫单元
            r, c = r_new, c_new
            # 从未访问列表当中移除
            unvisited.remove((r, c))
        # 如果没有相邻单元,意味着该条线路已经挖到底,则试图返回上一个分支节点,这时需要判断栈空不空,若不空,则弹出一个元素
        elif stack:
            # 栈顶的迷宫单元出栈
            r, c = stack.pop()
    else:
        unvisited.remove((r, c))

# 入口
for r in range(1
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值