forked from Mirrorlandia_minetest/digilines
Replace DFS with BFS.
Replace the recursive depth-first search of a wire network with an iterative breadth-first search, primarily to reduce memory footprint and eliminate the possibility of stack overflow.
This commit is contained in:
parent
7ecb29e87f
commit
514fb2e289
65
internal.lua
65
internal.lua
@ -63,27 +63,54 @@ function digiline:rules_link_anydir(output, input)
|
|||||||
or digiline:rules_link(input, output)
|
or digiline:rules_link(input, output)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function queue_new()
|
||||||
|
return {nextRead = 1, nextWrite = 1}
|
||||||
|
end
|
||||||
|
|
||||||
|
local function queue_empty(queue)
|
||||||
|
return queue.nextRead == queue.nextWrite
|
||||||
|
end
|
||||||
|
|
||||||
|
local function queue_enqueue(queue, object)
|
||||||
|
local nextWrite = queue.nextWrite
|
||||||
|
queue[nextWrite] = object
|
||||||
|
queue.nextWrite = nextWrite + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
local function queue_dequeue(queue)
|
||||||
|
local nextRead = queue.nextRead
|
||||||
|
local object = queue[nextRead]
|
||||||
|
queue[nextRead] = nil
|
||||||
|
queue.nextRead = nextRead + 1
|
||||||
|
return object
|
||||||
|
end
|
||||||
|
|
||||||
function digiline:transmit(pos, channel, msg, checked)
|
function digiline:transmit(pos, channel, msg, checked)
|
||||||
local checkedid = tostring(pos.x).."_"..tostring(pos.y).."_"..tostring(pos.z)
|
local queue = queue_new()
|
||||||
if checked[checkedid] then return end
|
queue_enqueue(queue, pos)
|
||||||
checked[checkedid] = true
|
while not queue_empty(queue) do
|
||||||
|
local curPos = queue_dequeue(queue)
|
||||||
|
local node = minetest.get_node(curPos)
|
||||||
|
local spec = digiline:getspec(node)
|
||||||
|
if spec then
|
||||||
|
-- Effector actions --> Receive
|
||||||
|
if spec.effector then
|
||||||
|
spec.effector.action(curPos, node, channel, msg)
|
||||||
|
end
|
||||||
|
|
||||||
local node = minetest.get_node(pos)
|
-- Cable actions --> Transmit
|
||||||
local spec = digiline:getspec(node)
|
if spec.wire then
|
||||||
if not spec then return end
|
local rules = digiline:importrules(spec.wire.rules, node)
|
||||||
|
for _, rule in ipairs(rules) do
|
||||||
|
local nextPos = digiline:addPosRule(curPos, rule)
|
||||||
-- Effector actions --> Receive
|
if digiline:rules_link(curPos, nextPos) then
|
||||||
if spec.effector then
|
local checkedID = tostring(nextPos.x) .. "_" .. tostring(nextPos.y) .. "_" .. tostring(nextPos.z)
|
||||||
spec.effector.action(pos, node, channel, msg)
|
if not checked[checkedID] then
|
||||||
end
|
checked[checkedID] = true
|
||||||
|
queue_enqueue(queue, nextPos)
|
||||||
-- Cable actions --> Transmit
|
end
|
||||||
if spec.wire then
|
end
|
||||||
local rules = digiline:importrules(spec.wire.rules, node)
|
end
|
||||||
for _,rule in ipairs(rules) do
|
|
||||||
if digiline:rules_link(pos, digiline:addPosRule(pos, rule)) then
|
|
||||||
digiline:transmit(digiline:addPosRule(pos, rule), channel, msg, checked)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
Loading…
Reference in New Issue
Block a user