我从选择未访问细胞的“愚蠢和缓慢”算法中完成了Wilson算法(迷宫生成)的优化:
function aux.wilson()
local unvisited_cells = aux.width * aux.height
local y, x = math.random(aux.sy, aux.height), math.random(aux.sx, aux.width)
aux.grid[y][x].visited = true
unvisited_cells = unvisited_cells - 1
local stx, sty
-- Here is a bad part
while true do
stx, sty = math.random(aux.sx, aux.width), math.random(aux.sy, aux.height) -- Start point
if aux.grid[sty][stx].visited == false then break end
end
local ix, iy = stx, sty -- sub-vertecies
while unvisited_cells ~= 0 do
if aux.grid[iy][ix].visited == true then
aux.grid[sty][stx].visited = true
while unvisited_cells ~= 0 do
if stx == ix and sty == iy then
-- Here is a bad part
while true do
stx, sty = math.random(aux.sx, aux.width), math.random(aux.sy, aux.height)
if aux.grid[sty][stx].visited == false then break end
end
break
else unvisited_cells = unvisited_cells - 1 end
local dir = aux.grid[sty][stx].dir
if dir == "UP" then
aux.grid[sty-1][stx].visited = true
aux.grid[sty-1][stx].bottom_wall = false
sty = sty - 1
elseif dir == "DOWN" then
aux.grid[sty+1][stx].visited = true
aux.grid[sty][stx].bottom_wall = false
sty = sty + 1
elseif dir == "LEFT" then
aux.grid[sty][stx-1].visited = true
aux.grid[sty][stx-1].right_wall = false
stx = stx - 1
elseif dir == "RIGHT" then
aux.grid[sty][stx+1].visited = true
aux.grid[sty][stx].right_wall = false
stx = stx + 1
end
end
ix, iy = stx, sty
end
local dir = aux.dirs[math.random(1, 4)]
if dir == "UP" then -- UP
if iy-1 >= aux.sy then
aux.grid[iy][ix].dir = "UP"
iy = iy - 1
end
elseif dir == "DOWN" then -- DOWN
if iy+1 <= aux.height then
aux.grid[iy][ix].dir = "DOWN"
iy = iy + 1
end
elseif dir == "RIGHT" then -- RIGHT
if ix+1 <= aux.width then
aux.grid[iy][ix].dir = "RIGHT"
ix = ix + 1
end
elseif dir == "LEFT" then -- LEFT
if ix-1 >= aux.sx then
aux.grid[iy][ix].dir = "LEFT"
ix = ix - 1
end
end
end
end
// Don't mind about dirs-part, only unvisited-cells choosing matter.
更聪明一点:
function aux.wilson()
local unvisited_cells = aux.width * aux.height
local CellsHash = aux.hashCells(aux.grid)
local key = next(CellsHash, nil)
local vx, vy = aux.deHashKey(key)
CellsHash[key] = nil
aux.grid[vy][vx].visited = true
unvisited_cells = unvisited_cells - 1
key = next(CellsHash, nil)
vx, vy = aux.deHashKey(key)
CellsHash[key] = nil
local stx, sty = vx, vy
local ix, iy = stx, sty -- sub-vertecies
while unvisited_cells ~= 0 do
if aux.grid[iy][ix].visited == true then
aux.grid[sty][stx].visited = true
CellsHash[aux.hashKey(stx, sty)] = nil
while unvisited_cells ~= 0 do
if stx == ix and sty == iy then
key = next(CellsHash, nil)
vx, vy = aux.deHashKey(key)
CellsHash[key] = nil
stx, sty = vx, vy
break
else unvisited_cells = unvisited_cells - 1 end
local dir = aux.grid[sty][stx].dir
if dir == "UP" then
aux.grid[sty-1][stx].visited = true
CellsHash[aux.hashKey(stx, sty-1)] = nil
aux.grid[sty-1][stx].bottom_wall = false
sty = sty - 1
elseif dir == "DOWN" then
aux.grid[sty+1][stx].visited = true
CellsHash[aux.hashKey(stx, sty+1)] = nil
aux.grid[sty][stx].bottom_wall = false
sty = sty + 1
elseif dir == "LEFT" then
aux.grid[sty][stx-1].visited = true
CellsHash[aux.hashKey(stx-1, sty)] = nil
aux.grid[sty][stx-1].right_wall = false
stx = stx - 1
elseif dir == "RIGHT" then
aux.grid[sty][stx+1].visited = true
CellsHash[aux.hashKey(stx+1, sty)] = nil
aux.grid[sty][stx].right_wall = false
stx = stx + 1
end
end
ix, iy = stx, sty
end
local dir = aux.dirs[math.random(1, 4)]
if dir == "UP" then -- UP
if iy-1 >= aux.sy then
aux.grid[iy][ix].dir = "UP"
iy = iy - 1
end
elseif dir == "DOWN" then -- DOWN
if iy+1 <= aux.height then
aux.grid[iy][ix].dir = "DOWN"
iy = iy + 1
end
elseif dir == "RIGHT" then -- RIGHT
if ix+1 <= aux.width then
aux.grid[iy][ix].dir = "RIGHT"
ix = ix + 1
end
elseif dir == "LEFT" then -- LEFT
if ix-1 >= aux.sx then
aux.grid[iy][ix].dir = "LEFT"
ix = ix - 1
end
end
end
end
function aux.hashKey(x, y)
return x * aux.height + (y - 1)
end
function aux.deHashKey(value)
return math.floor(value/aux.height), value%aux.height + 1
end
function aux.hashCells(grid)
local vtable = {}
for yk, yv in pairs(grid) do
for xk, xv in pairs(yv) do
if xv.visited == false then
vtable[aux.hashKey(xk, yk)] = xv
end
end
end
return vtable
end
我注意到,在小网格(100x100)上,它的工作方式几乎相同,但在更大的网格上(如1000x1000),第一个版本在3-4秒内工作,但第二个版本只是冻结。我真的可以'理解为什么。我没有看到任何可能导致重大问题的操作。
我将非常感谢有关这两种算法的优化和速度的任何建议或意见。 谢谢!
UPD1:好的,经过一些研究和剖析我发现,问题出现在下一个功能中。隐藏在Lua next-function后面的哈希表和碰撞解决机制对于此目的来说真的很慢。