Python迷宫生成和迷宫破解算法实例


Posted in Python onDecember 24, 2019

迷宫生成

1.随机PRIM

思路:先让迷宫中全都是墙,不断从列表(最初只含有一个启始单元格)中选取一个单元格标记为通路,将其周围(上下左右)未访问过的单元格放入列表并标记为已访问,再随机选取该单元格与周围通路单元格(若有的话)之间的一面墙打通。重复以上步骤直到列表为空,迷宫生成完毕。这种方式生成的迷宫难度高,岔口多。

效果:

Python迷宫生成和迷宫破解算法实例

代码:

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


def build_twist(num_rows, num_cols): # 扭曲迷宫
	# (行坐标,列坐标,四面墙的有无&访问标记)
 m = np.zeros((num_rows, num_cols, 5), dtype=np.uint8)
 r, c = 0, 0
 trace = [(r, c)]
 while trace:
  r, c = random.choice(trace)
  m[r, c, 4] = 1	# 标记为通路
  trace.remove((r, c))
  check = []
  if c > 0:
   if m[r, c - 1, 4] == 1:
    check.append('L')
   elif m[r, c - 1, 4] == 0:
    trace.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:
    trace.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:
    trace.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:
    trace.append((r + 1, c))
    m[r + 1, c, 4] = 2
  if len(check):
   direction = random.choice(check)
   if direction == 'L':	# 打通一面墙
    m[r, c, 0] = 1
    c = c - 1
    m[r, c, 2] = 1
   if direction == 'U':
    m[r, c, 1] = 1
    r = r - 1
    m[r, c, 3] = 1
   if direction == 'R':
    m[r, c, 2] = 1
    c = c + 1
    m[r, c, 0] = 1
   if direction == 'D':
    m[r, c, 3] = 1
    r = r + 1
    m[r, c, 1] = 1
 m[0, 0, 0] = 1
 m[num_rows - 1, num_cols - 1, 2] = 1
 return m

2.深度优先

思路:从起点开始随机游走并在前进方向两侧建立墙壁,标记走过的单元格,当无路可走(周围无未访问过的单元格)时重复返回上一个格子直到有新的未访问单元格可走。最终所有单元格都被访问过后迷宫生成完毕。这种方式生成的迷宫较为简单,由一条明显但是曲折的主路径和不多的分支路径组成。

效果:

Python迷宫生成和迷宫破解算法实例

代码:

def build_tortuous(num_rows, num_cols): # 曲折迷宫
 m = np.zeros((num_rows, num_cols, 5), dtype=np.uint8)
 r = 0
 c = 0
 trace = [(r, c)]
 while trace:
  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):
   trace.append([r, c])
   direction = random.choice(check)
   if direction == 'L':
    m[r, c, 0] = 1
    c = c - 1
    m[r, c, 2] = 1
   if direction == 'U':
    m[r, c, 1] = 1
    r = r - 1
    m[r, c, 3] = 1
   if direction == 'R':
    m[r, c, 2] = 1
    c = c + 1
    m[r, c, 0] = 1
   if direction == 'D':
    m[r, c, 3] = 1
    r = r + 1
    m[r, c, 1] = 1
  else:
   r, c = trace.pop()
 m[0, 0, 0] = 1
 m[num_rows - 1, num_cols - 1, 2] = 1
 return m

迷宫破解

效果:

Python迷宫生成和迷宫破解算法实例

Python迷宫生成和迷宫破解算法实例

1.填坑法

思路:从起点开始,不断随机选择没墙的方向前进,当处于一个坑(除了来时的方向外三面都是墙)中时,退一步并建造一堵墙将坑封上。不断重复以上步骤,最终就能抵达终点。

优缺点:可以处理含有环路的迷宫,但是处理时间较长还需要更多的储存空间。

代码:

def solve_fill(num_rows, num_cols, m): # 填坑法
 map_arr = m.copy()	# 拷贝一份迷宫来填坑
 map_arr[0, 0, 0] = 0
 map_arr[num_rows-1, num_cols-1, 2] = 0
 move_list = []
 xy_list = []
 r, c = (0, 0)
 while True:
  if (r == num_rows-1) and (c == num_cols-1):
   break
  xy_list.append((r, c))
  wall = map_arr[r, c]
  way = []
  if wall[0] == 1:
   way.append('L')
  if wall[1] == 1:
   way.append('U')
  if wall[2] == 1:
   way.append('R')
  if wall[3] == 1:
   way.append('D')
  if len(way) == 0:
   return False
  elif len(way) == 1:	# 在坑中
   go = way[0]
   move_list.append(go)
   if go == 'L':	# 填坑
    map_arr[r, c, 0] = 0
    c = c - 1
    map_arr[r, c, 2] = 0
   elif go == 'U':
    map_arr[r, c, 1] = 0
    r = r - 1
    map_arr[r, c, 3] = 0
   elif go == 'R':
    map_arr[r, c, 2] = 0
    c = c + 1
    map_arr[r, c, 0] = 0
   elif go == 'D':
    map_arr[r, c, 3] = 0
    r = r + 1
    map_arr[r, c, 1] = 0
  else:
   if len(move_list) != 0:	# 不在坑中
    come = move_list[len(move_list)-1]
    if come == 'L':
     if 'R' in way:
      way.remove('R')
    elif come == 'U':
     if 'D' in way:
      way.remove('D')
    elif come == 'R':
     if 'L' in way:
      way.remove('L')
    elif come == 'D':
     if 'U' in way:
      way.remove('U')
   go = random.choice(way)	# 随机选一个方向走
   move_list.append(go)
   if go == 'L':
    c = c - 1
   elif go == 'U':
    r = r - 1
   elif go == 'R':
    c = c + 1
   elif go == 'D':
    r = r + 1
 r_list = xy_list.copy()	
 r_list.reverse()	# 行动坐标记录的反转
 i = 0
 while i < len(xy_list)-1:	# 去掉重复的移动步骤
  j = (len(xy_list)-1) - r_list.index(xy_list[i])
  if i != j:	# 说明这两个坐标之间的行动步骤都是多余的,因为一顿移动回到了原坐标
   del xy_list[i:j]
   del move_list[i:j]
   r_list = xy_list.copy()
   r_list.reverse()
  i = i + 1
 return move_list

2.回溯法

思路:遇到岔口则将岔口坐标和所有可行方向压入栈,从栈中弹出一个坐标和方向,前进。不断重复以上步骤,最终就能抵达终点。

优缺点:计算速度快,需要空间小,但无法处理含有环路的迷宫。

代码:

def solve_backtrack(num_rows, num_cols, map_arr): # 回溯法
 move_list = ['R']
 m = 1	# 回溯点组号
 mark = []
 r, c = (0, 0)
 while True:
  if (r == num_rows-1) and (c == num_cols-1):
   break
  wall = map_arr[r, c]
  way = []
  if wall[0] == 1:
   way.append('L')
  if wall[1] == 1:
   way.append('U')
  if wall[2] == 1:
   way.append('R')
  if wall[3] == 1:
   way.append('D')
  come = move_list[len(move_list) - 1]
  if come == 'L':
   way.remove('R')
  elif come == 'U':
   way.remove('D')
  elif come == 'R':
   way.remove('L')
  elif come == 'D':
   way.remove('U')
  while way:
   mark.append((r, c, m, way.pop()))	# 记录当前坐标和可行移动方向
  if mark:
   r, c, m, go = mark.pop()
   del move_list[m:]	# 删除回溯点之后的移动
  else:
   return False
  m = m + 1
  move_list.append(go)
  if go == 'L':
   c = c - 1
  elif go == 'U':
   r = r - 1
  elif go == 'R':
   c = c + 1
  elif go == 'D':
   r = r + 1
 del move_list[0]
 return move_list

测试

rows = int(input("Rows: "))
cols = int(input("Columns: "))

Map = build_twist(rows, cols)
plt.imshow(draw(rows, cols, Map), cmap='gray')
fig = plt.gcf()
fig.set_size_inches(cols/10/3, rows/10/3)
plt.gca().xaxis.set_major_locator(plt.NullLocator())
plt.gca().yaxis.set_major_locator(plt.NullLocator())
plt.subplots_adjust(top=1, bottom=0, right=1, left=0, hspace=0, wspace=0)
plt.margins(0, 0)
fig.savefig('aaa.png', format='png', transparent=True, dpi=300, pad_inches=0)

move = solve_backtrack(rows, cols, Map)
plt.imshow(draw_path(draw(rows, cols, Map), move), cmap='hot')
fig = plt.gcf()
fig.set_size_inches(cols/10/3, rows/10/3)
plt.gca().xaxis.set_major_locator(plt.NullLocator())
plt.gca().yaxis.set_major_locator(plt.NullLocator())
plt.subplots_adjust(top=1, bottom=0, right=1, left=0, hspace=0, wspace=0)
plt.margins(0, 0)
fig.savefig('bbb.png', format='png', transparent=True, dpi=300, pad_inches=0)

以上这篇Python迷宫生成和迷宫破解算法实例就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Python 相关文章推荐
python杀死一个线程的方法
Sep 06 Python
Python用for循环实现九九乘法表
May 31 Python
Python 仅获取响应头, 不获取实体的实例
Aug 21 Python
python中利用numpy.array()实现俩个数值列表的对应相加方法
Aug 26 Python
python3 下载网络图片代码实例
Aug 27 Python
关于Python3 类方法、静态方法新解
Aug 30 Python
在Python中利用pickle保存变量的实例
Dec 30 Python
Python request操作步骤及代码实例
Apr 13 Python
自学python用什么系统好
Jun 23 Python
python图片合成的示例
Nov 09 Python
Python爬虫实现selenium处理iframe作用域问题
Jan 27 Python
解决Python保存文件名太长OSError: [Errno 36] File name too long
May 11 Python
Python3 A*寻路算法实现方式
Dec 24 #Python
python logging添加filter教程
Dec 24 #Python
python打印异常信息的两种实现方式
Dec 24 #Python
numpy实现神经网络反向传播算法的步骤
Dec 24 #Python
python异常处理和日志处理方式
Dec 24 #Python
Python 音频生成器的实现示例
Dec 24 #Python
Python concurrent.futures模块使用实例
Dec 24 #Python
You might like
php开发留言板的CRUD(增,删,改,查)操作
2012/04/19 PHP
PHP5中Cookie与 Session使用详解
2013/04/30 PHP
浅谈php serialize()与unserialize()的用法
2013/06/05 PHP
十幅图告诉你什么是PHP引用
2015/02/22 PHP
PHP会员找回密码功能的简单实现
2016/09/05 PHP
PHP通过get方法获得form表单数据方法总结
2018/09/12 PHP
Firefox 无法获取cssRules 的解决办法
2006/10/11 Javascript
关于js中for in的缺陷浅析
2013/12/02 Javascript
经过绑定元素时会多次触发mouseover和mouseout事件
2014/02/28 Javascript
jquery JSON的解析方式示例介绍
2014/07/27 Javascript
Jquery实现兼容各大浏览器的Enter回车切换输入焦点的方法
2014/09/01 Javascript
JS实现随机乱撞彩色圆球特效的方法
2015/05/05 Javascript
Sublime Text 3常用插件及安装方法
2015/12/16 Javascript
基于jquery实现表格无刷新分页
2016/01/07 Javascript
javascript鼠标滑过显示二级菜单特效
2020/11/18 Javascript
再谈Javascript中的异步以及如何异步
2016/08/19 Javascript
微信小程序链接传参并跳转新页面
2016/11/29 Javascript
javascript实现简易计算器
2017/02/01 Javascript
小程序input数据双向绑定实现方法
2019/10/17 Javascript
[07:47]DOTA2国际邀请赛采访专栏:探访Valve总部
2013/08/08 DOTA
CentOS 6.5下安装Python 3.5.2(与Python2并存)
2017/06/05 Python
python实现合并两个排序的链表
2019/03/03 Python
python通过txt文件批量安装依赖包的实现步骤
2019/08/13 Python
python matplotlib库的基本使用
2020/09/23 Python
python GUI计算器的实现
2020/10/09 Python
python 实现弹球游戏的示例代码
2020/11/17 Python
python 数据类型强制转换的总结
2021/01/25 Python
python中os.remove()用法及注意事项
2021/01/31 Python
分享30个新鲜的CSS3打造的精美绚丽效果(附演示下载)
2012/12/28 HTML / CSS
html5基础标签(html5视频标签 html5新标签用法)
2013/12/30 HTML / CSS
英国知名奢侈品包包品牌:Milli Millu
2016/12/22 全球购物
美国著名的户外用品品牌:L.L.Bean
2018/01/05 全球购物
奢华时尚的创新平台:Baltini
2020/10/03 全球购物
餐厅总厨求职信
2014/03/04 职场文书
办公室主任竞聘演讲稿
2014/05/15 职场文书
2014年向国旗敬礼活动总结
2014/09/27 职场文书