Python四⼤迷宫⽣成算法实现(3):递归分割算法
python迷宫⽣成算法实现:递归分割算法
递归分割算法简介
先介绍下算法使⽤的地图,地图最外围默认是⼀圈墙,其中⽩⾊单元是迷宫单元,⿊⾊单元是墙。⽰例地图的宽度和长度都为11。
第⼀个图⽤⼗字将地图分割成4个⼩矩阵,可以看到这个⼗字交点所在的位置(WALL_X, WALL_Y),在这个图中为(6,4),注意WALL_X, WALL_Y都必须是偶数。同时迷宫的长度和宽度必须为奇数。
第⼆图在4个⼩矩阵的相邻四条边上随机选择三条边来打通(每条边上去掉⼀个单元的墙),使得这4个⼩矩阵连通。
这是⼀个递归算法,重复调⽤算法直到矩阵的长度或宽度<=1:
1 算法调⽤参数是⼀个矩阵的位置(x, y, width, height)
2 判断矩阵是否不能继续分割(长度或宽度<=1)
如果能继续分割
随机选择⼗字交点的位置(WALL_X, WALL_Y), 将这条⼗字所在的单元都设为墙,分割成4个更⼩的矩阵.
⼗字所在的四条边中随机选择三条边来打通(每条边上去掉⼀个单元的墙)
对于4个⼩矩阵递归调⽤算法
否则,直接返回
关键代码介绍
保存基本信息的地图类
地图类⽤于保存和获取迷宫算法使⽤的基础地图信息。
1. 先创建⼀个map类, 初始化参数设置地图的长度和宽度,并设置保存地图信息的⼆维数据map的值为0, 值为0表⽰该单元可以移
动,值为1表⽰该单元是墙。定义在算法中⽤到的Enum 类MAP_ENTRY_TYPE 和 WALL_DIRECTION。
class MAP_ENTRY_TYPE(Enum):
MAP_EMPTY =0,
MAP_BLOCK =1,
class WALL_DIRECTION(Enum):
WALL_LEFT =0,
WALL_UP =1,
WALL_RIGHT =2,
温州少儿英语提高班WALL_DOWN =3,
class Map():
def__init__(lf, width, height):
lf.width = width
世界杯西班牙夺冠
xiaonelf.height = height
lf.map=[[0for x in range(lf.width)]for y in range(lf.height)]
2. 在map类中添加将⼀个map单元设置为某个值的函数,判断某个单元是否是墙的函数,和是否是有效单元的函数。
def tMap(lf, x, y, value):
if value == MAP_ENTRY_TYPE.MAP_EMPTY:
lf.map[y][x]=0
elif value == MAP_ENTRY_TYPE.MAP_BLOCK:
lf.map[y][x]=1
def isMovable(lf, x, y):
return lf.map[y][x]!=1
def isValid(lf, x, y):
if x <0or x >= lf.width or y <0or y >= lf.height:
return Falcold water
return True
3. 在map类中添加⼀个显⽰地图的函数,可以看到,这边只是简单的打印出所有节点的值,值为1时打印’#"表⽰强,或1的意思上⾯已
经说明,在后⾯显⽰寻路算法结果时,会使⽤到值2,表⽰⼀条从开始节点到⽬标节点的路径。
friendsdef showMap(lf):
for row in lf.map:
s =''
foundationsfor entry in row:
if entry ==0:
s +=' 0'
elif entry ==1:
s +=' #'
el:
s +=' X'
print(s)
算法主函数介绍
小学二年级数学应用题doRecursiveDivision 函数 先调⽤tMap函数将地图最外围四条边都设置为墙。传⼊recursiveDivision 函数的参数是矩阵的位置(x, y, width, height),假如地图的宽度是31,长度是21,则传⼊参数为(1,1,29,19)。
def doRecursiveDivision(map):
# draw four margin wall lines
四级听力mp3for x in range(0,map.width):
map.tMap(x,0, MAP_ENTRY_TYPE.MAP_BLOCK)
水獭英语
map.tMap(x,map.height-1, MAP_ENTRY_TYPE.MAP_BLOCK)
for y in range(0,map.height):
map.tMap(0, y, MAP_ENTRY_TYPE.MAP_BLOCK)
map.tMap(map.width-1, y, MAP_ENTRY_TYPE.MAP_BLOCK)
recursiveDivision(map,1,1,map.width -2,map.height -2, MAP_ENTRY_TYPE.MAP_BLOCK)
recursiveDivision 函数就是上⾯算法主循环的实现。
# recursive division algorithm
def recursiveDivision(map, x, y, width, height, wall_value):
if width <=1or height <=1:
return
#generate a row and a column wall index, they must be even number
wall_x, wall_y =(getWallIndex(x, width), getWallIndex(y, height))
#t horizontal and vertical lines to wall
for i in range(x, x+width):
map.tMap(i, wall_y, wall_value)
for i in range(y, y+height):
map.tMap(wall_x, i, wall_value)
#create three holes
generateHoles(map, x, y, width, height, wall_x, wall_y)
recursiveDivision(map, x, y, wall_x - x, wall_y - y, wall_value)
recursiveDivision(map, x, wall_y +1, wall_x - x, y + height - wall_y -1, wall_value)
recursiveDivision(map, wall_x +1, y, x + width - wall_x -1, wall_y - y, wall_value)
recursiveDivision(map, wall_x +1, wall_y +1, x + width - wall_x -1, y + height - wall_y -1, wall_value)
getWallIndex函数获取指定范围的随机偶数。
generateHoles函数,选择三条边打通,有个特别要注意的是,当外层的矩阵和⼗字墙相邻的单元是连通的情况下,⽐如下图所⽰的红⾊单元,这时候红⾊单元必须要打通,不然会导致迷宫不连通。
# start must be a odd number, wall_index must be a even number
def getWallIndex(start, length):
asrt length >=3
eact
wall_index = randint(start +1, start + length -2)
if wall_index %2==1:
wall_index -=1
return wall_index
# must check adjacent entry of four margin entries,
# if adjacent entry is movable, must t the margin entry as the hole
def generateHoles(map, x, y, width, height, wall_x, wall_y):
holes =[]
hole_entrys =[(randint(x, wall_x -1), wall_y),(randint(wall_x +1, x + width -1), wall_y),
(wall_x, randint(y, wall_y -1)),(wall_x, randint(wall_y +1, y + height -1))]
margin_entrys =[(x, wall_y),(x+width-1, wall_y),(wall_x, y),(wall_x, y + height-1)]
adjacent_entrys =[(x-1, wall_y),(x+width, wall_y),(wall_x, y -1),(wall_x, y + height)]
for i in range(4):
adj_x, adj_y =(adjacent_entrys[i][0], adjacent_entrys[i][1])
if map.isValid(adj_x, adj_y)and map.isMovable(adj_x, adj_y):
map.tMap(margin_entrys[i][0], margin_entrys[i][1], MAP_ENTRY_TYPE.MAP_EMPTY)
el:
holes.append(hole_entrys[i])
ignore_hole = randint(0,len(holes)-1)
for i in range(0,len(holes)):
if i != ignore_hole:
map.tMap(holes[i][0], holes[i][1], MAP_ENTRY_TYPE.MAP_EMPTY)
代码的初始化
可以调整地图的长度,宽度,注意长度和宽度必须为奇数。
def run():
WIDTH =31
HEIGHT =21
map= Map(WIDTH, HEIGHT)
doRecursiveDivision(map)
map.showMap()
if __name__ =="__main__":
run()
执⾏的效果图如下,迷宫中’#‘表⽰墙,空格’ '表⽰通道。
完整代码
使⽤python3.7编译
from random import randint, choice
from enum import Enum
class MAP_ENTRY_TYPE(Enum):
MAP_EMPTY =0,
MAP_BLOCK =1,
class WALL_DIRECTION(Enum):
WALL_LEFT =0,
WALL_UP =1,
WALL_RIGHT =2,
WALL_DOWN =3,
class Map():
def__init__(lf, width, height):
lf.width = width
lf.height = height
lf.map=[[0for x in range(lf.width)]for y in range(lf.height)]
def tMap(lf, x, y, value):
if value == MAP_ENTRY_TYPE.MAP_EMPTY:
lf.map[y][x]=0
elif value == MAP_ENTRY_TYPE.MAP_BLOCK:
lf.map[y][x]=1
def isMovable(lf, x, y):
return lf.map[y][x]!=1
def isValid(lf, x, y):
if x <0or x >= lf.width or y <0or y >= lf.height:
return Fal
return True