|
关于随机迷宫的算法的理论,一个简单算法的详细解释和使用时的注意:
首先先抄下演示中使用的算法代码段:
复制代码
//=================Function Start======================
function RandomMZ takes integer offset returns nothing
local integer rd
local integer symbol
local integer tmp
local integer lDir
local integer direction
set udg_isVisited[offset]=true
loop
set symbol=0
if (offset>10 and udg_isVisited[offset-11]==false) then
set symbol=symbol+1
endif
if (offset-offset/11*11>0 and udg_isVisited[offset-1]==false) then
set symbol=symbol+2
endif
if (offset <110 and udg_isVisited[offset+11]==false) then
set symbol=symbol+4
endif
if (offset-offset/11*11-10<0 and udg_isVisited[offset+1]==false) then
set symbol=symbol+8
endif
exitwhen (symbol==0)
set lDir=0
set tmp=symbol
loop
exitwhen (tmp==0)
set lDir=lDir+tmp-tmp/2*2
set tmp=tmp/2
endloop
set rd=GetRandomInt(1,lDir)
set tmp=symbol-symbol/2*2
set direction=1
loop
exitwhen (tmp==1 and rd==1)
set symbol=symbol/2
if (tmp==1) then
set rd=rd-1
endif
set tmp=symbol-symbol/2*2
set direction=direction+1
endloop
if (direction==1) then
set udg_toDown[offset-11]=true
call RandomMZ(offset-11)
endif
if (direction==2) then
set udg_toRight[offset-1]=true
call RandomMZ(offset-1)
endif
if (direction==3) then
set udg_toDown[offset]=true
call RandomMZ(offset+11)
endif
if (direction==4) then
set udg_toRight[offset]=true
call RandomMZ(offset+1)
endif
endloop
endfunction
//=================Function End======================
其中使用的全局变量有:
boolean isVisited[]
boolean toDown[]
boolean toRight[]
现在解释各个变量的意义
迷宫一般由X*Y个房间构成,比如说这个6*5的迷宫(X=6,Y=5)
---------------------->X
0 1 2 3 4 5
| ┏━┳━┳━┳━┳━┳━┓
| 0┃0 ┃1 ┃2 ┃3 ┃4 ┃5 ┃
| ┣━╋━╋━╋━╋━╋━┫
| 1┃6 ┃7 ┃8 ┃9 ┃10┃11┃
| ┣━╋━╋━╋━╋━╋━┫
| 2┃12┃13┃14┃15┃16┃17┃
| ┣━╋━╋━╋━╋━╋━┫
| 3┃18┃19┃20┃21┃22┃23┃
| ┣━╋━╋━╋━╋━╋━┫
y 4┃24┃25┃26┃27┃28┃29┃
┗━┻━┻━┻━┻━┻━┛
====1====下标表示
由于JASS中只有一维数组,我们只能通过计算下标来找到每个房间储存的位置
如(0,0)下标是0,(3,4)下标是4*6+3=27,而下标是19的房间坐标为(19%6,[19/6])=(1,3)
(19%6即19/6的余数,具体算法是19-19/6*6,[19/6]即对19/6取整)
左右相邻的两个房间下标相差1,上下相邻的房间下标相差X
第1行下标=X*(Y-1),第一列下标特点是能被X整除,最后一列下标特点是加1后能被X整
除
====2====迷宫的储存
我们用toRight记录每个房间于其右边的房间是否连通,toDown记录是否与下面的房间连通
(为什么不用toLeft和toTop记录与左边和上面的房间的连通情况?原因是重复)
所以,toRight(19)和toDown(19)记录了房间(1,3)和(2,3)(1,4)的连通情况
通过一个X*Y大小的toRight和toDown的数组我们就可以记录一个X*Y的迷宫了
我们的目标就是随机算出每个房间的连通情况
====3====isVisited数组
isVisited数组保存每个房间的访问情况
对于一个随机迷宫的简单算法:
1.首先,将所有房间的连通情况设为不连通,进入某个房间
2.进入某个房间R后,如果R四周有未访问过的房间,则从未访问的房间中随机选择一个房间vR,连通R与
vR,并进入房间vR
3.如果房间R四周的房间已经全部访问过,则返回上一个房间
4.重复过程2和3,直到所有房间全部访问为止
该算法生成的迷宫任意两个房间之间有且只有一条通路
证明从略.
某些朋友可能已经知道怎么做了,从某个房间开始进行一次深度优先遍历即可
下面详细解释一下代码
1.function RandomMZ takes integer offset returns nothing
不要告诉我不知道这句话是什么意思...
offset 即为进入房间的下标,在T中的call RandomMZ(0)即进入(0,0)房间
2.变量定义
local integer rd============随机数
local integer symbol========标志
local integer tmp===========临时变量
local integer lDir==========房间四周剩余未访问的房间数量
local integer direction=====最终决定的方向 1=上 2=左 3=下 4=右
3.set udg_isVisited[offset]=true
进入一个房间首先将其设为已访问
4.set symbol=0
symbol作为标志位记录每个房间的连通情况,用2进制位记录,即为二进制的(0000)
5.
if (offset>10 and udg_isVisited[offset-11]==false) then
set symbol=symbol+1
endif
如果上方有房间并且未访问,则将Symbol的第一位置1(二进制第一位是1)
if (offset-offset/11*11>0 and udg_isVisited[offset-1]==false) then
set symbol=symbol+2
endif
如果左边有房间并且未访问,则将Symbol的第二位置1(二进制第二位是2)
if (offset <110 and udg_isVisited[offset+11]==false) then
set symbol=symbol+4
endif
如果下方有房间并且未访问,则将Symbol的第三位置1(二进制第三位是4)
if (offset-offset/11*11-10<0 and udg_isVisited[offset+1]==false) then
set symbol=symbol+8
endif
如果右边有房间并且未访问,则将Symbol的第四位置1(二进制第四位是8)
比如Symbol=13,转换为二进制是(1101),就是上,下,右的房间可以访问,左边没有房间或房间已访问
6.exitwhen (symbol==0)
如果symbol=0,也就是没有房间可访问,那么退出循环,返回上一个房间
7.
set lDir=0
set tmp=symbol
loop
exitwhen (tmp==0)
set lDir=lDir+tmp-tmp/2*2
set tmp=tmp/2
endloop
这一段代码计算四周可访问的房间的数量,并保存在lDir中
8.set rd=GetRandomInt(1,lDir)
rd从1到lDir中随机取数(因为共lDir个房间可访问),决定访问可访问房间中的第几个
9.
set tmp=symbol-symbol/2*2
set direction=1
loop
exitwhen (tmp==1 and rd==1)
set symbol=symbol/2
if (tmp==1) then
set rd=rd-1
endif
set tmp=symbol-symbol/2*2
set direction=direction+1
endloop
得到访问房间的方向.具体是用计数器实现,依次取得每一个房间的状态,如果可访问,则将rd减1
当rd=1并且当前房间可访问时停止循环,这样当前的房间即为通过rd选择的房间
PS:以上7,8,9实现了随机选择可访问的房间,如果有更好的算法说一声啊
10. if (direction==1) then
set udg_toDown[offset-11]=true
call RandomMZ(offset-11)
endif
if (direction==2) then
set udg_toRight[offset-1]=true
call RandomMZ(offset-1)
endif
if (direction==3) then
set udg_toDown[offset]=true
call RandomMZ(offset+11)
endif
if (direction==4) then
set udg_toRight[offset]=true
call RandomMZ(offset+1)
endif
更据选择的方向决定下标变化,将两个房间连通,并进入该房间
11.loop
4,5,6,7,8,9,10
endloop
之所以重复4,5,6,7,8,9,10的过程是保证每个房间四周的房间都全部访问(根据6,那时候退出循环)
不会有遗漏的房间存在
12.endfunction
......
关于使用:
实际上修改这段代码很简单
比如要生成一个30*30的迷宫,只要简单的把该函数中的"11"全改为30,"10"全改为29(=30-1),"110"改为
870(=30*(30-1))即可,剩下的过程就是根据连通情况画出图了,在演示中也有T的例子,这点不再罗嗦
PS:由于生成的迷宫任意两个房间之间有且只有一条通路,迷宫有时候回显得比较简单,这时候可以修改
一下算法,比如随机连通两个不相连的房间,以增加回路,提高迷宫的复杂性
差不多就将这些,欢迎各位指正 |
|