哈希优化和威尔逊迷宫生成算法

时间:2016-11-09 17:04:23

标签: algorithm optimization lua maze

我从选择未访问细胞的“愚蠢和缓慢”算法中完成了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后面的哈希表和碰撞解决机制对于此目的来说真的很慢。

0 个答案:

没有答案