diff --git a/compacting-storage.lua b/compacting-storage.lua new file mode 100644 index 0000000..5bedc20 --- /dev/null +++ b/compacting-storage.lua @@ -0,0 +1,153 @@ +-- Program to control a compacting storage made with create. + +-- NOTE: set block -> ingot refresh amount higher than the level desired in +-- this program to prioritize using available resources before generating +-- new ones + +-- constants + +local INVENTORY = "" +local SLEEP_TIME = 5 +local ITEM_TYPES = { "iron", "copper", "zinc", "gold", "electrum" } +local PRIORITY = { "ingot", "block", "nugget" } + +function stacks (num) + return 64 * num +end + +-- TODO map targets to specific relays +local target = {} +for _, type in ipairs(ITEM_TYPES) do + target[type] = { + "nugget" = { stacks(4), stacks(8) }, + "ingot" = { stacks(4), stacks(8) }, + "block" = { stacks(4), stacks(1000) } + } +end + +-- Map types of conversions to specific faces +local convert = {} +convert["nugget_to_ingot"] = "front" +convert["ingot_to_block"] = "top" +convert["block_to_ingot"] = "back" + +function sum_items (inv) + -- organize list of item, count into item_type: (count_N, count_I, count_B) + -- item name will be in form `{mod}:{item_type}_{form}` + local result = {} + for _, type in ipairs(ITEM_TYPES) do + result[type] = {} + end + for slot, item in pairs(inv.list()) do + local type, form = item.name:match".-:(%l-)_(%l*)" + if result[type][form] == nil then + result[type][form] = item.count + else + result[type][form] = result[type][form] + item.count + end + end + return result +end + +-- basic actions +function request (item_type, conversion_type) + target[item_type].setOutput(convert.conversion_type, true) + os.sleep(0.05) + target[item_type].setOutput(convert.conversion_type, false) +end + +function request_multiple (item_type, conversion_type, count) + if count < 1 then return end + if count == 1 then + return request(item_type, conversion_type) + else + request(item_type, conversion_type) + os.sleep(1) + return request_multiple(item_type, conversion_type, count - 1) + end +end + +-- fundamental actions +-- assumptions: a drain or fill of 1 will increase or decrease the amount of +-- that item by 63 +function drain (type, form, amount) + local conversion = nil + if form == "nugget" then + conversion = "nugget_to_ingot" + elseif form == "ingot" then + conversion = "ingot_to_block" + end + request_multiple(type, conversion, amount) +end + +function fill (type, form, amount) + local conversion = nil + if dest == "block" then + conversion = "ingot_to_block" + elseif dest == "ingot" then + if src == "nugget" then + conversion = "nugget_to_ingot" + elseif src == "block" then + conversion = "block_to_ingot" + end + end + request_multiple(type, conversion, amount) +end + +-- making the decision what to do +-- assumptions: a drain or fill of 1 will increase or decrease the amount of +-- that item by 63 +function should_drain (type, counts) + local drain_form, amount = nil, 0 + for _, form in ipairs(PRIORITY) do + local diff = counts[form] - target[type][form][2] + if diff > 0 then + amount = math.ceil(diff / 63) + drain_form = form + return drain_form, amount + end + end +end + +function should_fill (type, counts) + local fill_dest, fill_src, amount = nil, nil, 0 + for _, form in ipairs(PRIORITY) do + local diff = target[type][form][1] - counts[form] + if diff > 0 then + if fill_dest == nil then + amount = math.ceil(diff / 63) + fill_dest = form + end + else + fill_src = form + end + if fill_src ~= nil and fill_dest ~= nil then break end + end + return fill_dest, fill_src, amount +end + +function decide_action (type, counts) + -- using the levels of each form of the item, decide what to do + for _, form in ipairs(PRIORITY) do + local drain_form, drain_amt = should_drain(type, counts) + local fill_dest, fill_src, fill_amt + if drain_form ~= nil then + drain(type, form, drain_amt) + elseif fill_dest ~= nil then + fill(type, form, fill_amt) + end + end +end + +while true do + -- 1. Sum items in inventory and organize by item type + local items = sum_items(peripheral.wrap(INVENTORY)) + + -- 2. take one action for each item type per cycle + for item_type, counts in pairs(items) do + decide_action(item_type, counts) + end + + -- sleep until next cycle + os.sleep(SLEEP_TIME) +end