distributing algorithm further improved

This commit is contained in:
Joachim Stolberg 2018-08-20 20:53:48 +02:00
parent 37ab82b371
commit 4c86e4e6b5

@ -20,6 +20,11 @@ local CYCLE_TIME = 2
local STOP_STATE = 0 local STOP_STATE = 0
local STANDBY_STATE = -1 local STANDBY_STATE = -1
local Side2Color = {B="red", L="green", F="blue", R="yellow"}
local SlotColors = {"red", "green", "blue", "yellow"}
local Num2Ascii = {"B", "L", "F", "R"}
local FilterCache = {} -- local cache for filter settings
-- Return the total number of list entries -- Return the total number of list entries
local function invlist_num_entries(list) local function invlist_num_entries(list)
local res = 0 local res = 0
@ -49,11 +54,24 @@ end
local function AddToTbl(kvTbl, new_items, val) local function AddToTbl(kvTbl, new_items, val)
for _, l in ipairs(new_items) do for _, l in ipairs(new_items) do
kvTbl[l] = val if kvTbl[l] == nil then
kvTbl[l] = {val}
else
kvTbl[l][#kvTbl[l] + 1] = val
end
end end
return kvTbl return kvTbl
end end
local function random_list_elem(list)
if list == nil then
return nil
elseif #list > 1 then
return list[math.random(1, #list)]
else
return list[1]
end
end
local function distributor_formspec(state, filter) local function distributor_formspec(state, filter)
return "size[10,8.5]".. return "size[10,8.5]"..
@ -80,6 +98,33 @@ local function distributor_formspec(state, filter)
"listring[current_player;main]" "listring[current_player;main]"
end end
local function filter_settings(pos)
local hash = minetest.hash_node_position(pos)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
local filter = minetest.deserialize(meta:get_string("filter")) or {false,false,false,false}
local kvFilterItemNames = {} -- {<item:name> = side,...}
local OpenPorts = {} -- {side, ...}
-- collect all filter settings
for idx,slot in ipairs(SlotColors) do
local side = Num2Ascii[idx]
if filter[idx] == true then
local list = inv:get_list(slot)
local filter = invlist_entries_as_list(list)
AddToTbl(kvFilterItemNames, filter, side)
if not next(filter) then
OpenPorts[#OpenPorts + 1] = side
end
end
end
FilterCache[hash] = {
kvFilterItemNames = kvFilterItemNames,
OpenPorts = OpenPorts,
}
end
local function allow_metadata_inventory_put(pos, listname, index, stack, player) local function allow_metadata_inventory_put(pos, listname, index, stack, player)
local meta = minetest.get_meta(pos) local meta = minetest.get_meta(pos)
local inv = meta:get_inventory() local inv = meta:get_inventory()
@ -91,6 +136,7 @@ local function allow_metadata_inventory_put(pos, listname, index, stack, player)
if listname == "src" then if listname == "src" then
return stack:get_count() return stack:get_count()
elseif invlist_num_entries(list) < NUM_FILTER_ELEM then elseif invlist_num_entries(list) < NUM_FILTER_ELEM then
filter_settings(pos)
return 1 return 1
end end
return 0 return 0
@ -100,6 +146,7 @@ local function allow_metadata_inventory_take(pos, listname, index, stack, player
if minetest.is_protected(pos, player:get_player_name()) then if minetest.is_protected(pos, player:get_player_name()) then
return 0 return 0
end end
filter_settings(pos)
return stack:get_count() return stack:get_count()
end end
@ -110,37 +157,6 @@ local function allow_metadata_inventory_move(pos, from_list, from_index, to_list
return allow_metadata_inventory_put(pos, to_list, to_index, stack, player) return allow_metadata_inventory_put(pos, to_list, to_index, stack, player)
end end
local Side2Color = {B="red", L="green", F="blue", R="yellow"}
local SlotColors = {"red", "green", "blue", "yellow"}
local Num2Ascii = {"B", "L", "F", "R"} -- color to side translation
local FilterCache = {} -- local cache for filter settings
local function filter_settings(pos)
local hash = minetest.hash_node_position(pos)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
local filter = minetest.deserialize(meta:get_string("filter")) or {false,false,false,false}
local kvFilterItemNames = {} -- {<item:name> = side,...}
local kvOpenPorts = {} -- {side = true, ...}
-- collect all filter settings
for idx,slot in ipairs(SlotColors) do
local side = Num2Ascii[idx]
if filter[idx] == true then
local list = inv:get_list(slot)
local filter = invlist_entries_as_list(list)
AddToTbl(kvFilterItemNames, filter, side)
if not next(filter) then
kvOpenPorts[side] = true
end
end
end
FilterCache[hash] = {
kvFilterItemNames = kvFilterItemNames,
kvOpenPorts = kvOpenPorts,
}
end
local function start_the_machine(pos) local function start_the_machine(pos)
local node = minetest.get_node(pos) local node = minetest.get_node(pos)
@ -184,6 +200,7 @@ local function goto_sleep(pos)
return false return false
end end
-- move items to the output slots -- move items to the output slots
local function keep_running(pos, elapsed) local function keep_running(pos, elapsed)
local meta = minetest.get_meta(pos) local meta = minetest.get_meta(pos)
@ -200,52 +217,54 @@ local function keep_running(pos, elapsed)
-- read data from Cache -- read data from Cache
local kvFilterItemNames = FilterCache[hash].kvFilterItemNames local kvFilterItemNames = FilterCache[hash].kvFilterItemNames
local open_ports = table.copy(FilterCache[hash].kvOpenPorts) local open_ports = table.copy(FilterCache[hash].OpenPorts)
-- no filter configured? -- no filter configured?
if next(kvFilterItemNames) == nil then if next(kvFilterItemNames) == nil then
return true return goto_sleep(pos)
end end
local busy = false local busy = false
local unused_outputs = {B=true, L=true, F=true, R=true}
local inv = meta:get_inventory() local inv = meta:get_inventory()
local list = inv:get_list("src") local list = inv:get_list("src")
for _,stack in ipairs(list) do
if stack:get_count() > 0 then
local name = stack:get_name()
local second_try = false
-- try configured output ports -- take one stack from inventory, which fits to one output port
local side = kvFilterItemNames[name] local stack
if side then -- configured local start_idx = math.random(1, 8)
if unused_outputs[side] then for i = start_idx,start_idx+8 do
if tubelib.push_items(pos, side, stack, player_name) then stack = list[(i % 8) + 1]
stack:set_count(0) if stack:get_count() > 0 and (kvFilterItemNames[stack:get_name()] or next(open_ports)) then
unused_outputs[side] = false break
local color = Side2Color[side] end
counter[color] = counter[color] + 1 end
busy = true
else if stack:get_count() > 0 then
second_try = true -- port blocked local name = stack:get_name()
end local second_try = false
end -- try configured output ports
local side = random_list_elem(kvFilterItemNames[name])
if side then -- configured
if tubelib.push_items(pos, side, stack, player_name) then
stack:set_count(0)
local color = Side2Color[side]
counter[color] = counter[color] + 1
busy = true
else else
second_try = true -- not configured second_try = true -- port blocked
end end
else
second_try = true -- not configured
end
-- try unconfigured open output ports -- try unconfigured open output ports
if second_try then if second_try then
side,_ = next(open_ports) side = random_list_elem(open_ports)
if side then if side then
if tubelib.push_items(pos, side, stack, player_name) then if tubelib.push_items(pos, side, stack, player_name) then
stack:set_count(0) stack:set_count(0)
open_ports[side] = nil local color = Side2Color[side]
local color = Side2Color[side] counter[color] = counter[color] + 1
counter[color] = counter[color] + 1 busy = true
busy = true
end
end end
end end
end end