-- 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 = "left" local SLEEP_TIME = 30 local AMOUNT_USED = 63 -- the amount of item used per request local AMOUNT_RETURNED = 7 -- the amount of item returned per request local REDUCTION_FACTOR = 0.75 -- when draining, what percent to do at a time 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 = {} target.iron = peripheral.wrap"redstone_relay_0" target.copper = peripheral.wrap"redstone_relay_1" target.zinc = peripheral.wrap"redstone_relay_2" target.gold = peripheral.wrap"redstone_relay_3" target.electrum = peripheral.wrap"redstone_relay_4" -- Levels local limits = {} for _, type in ipairs(ITEM_TYPES) do limits[type] = { nugget = { stacks(4), stacks(8) }, ingot = { stacks(4), stacks(8) }, block = { stacks(1), 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] = {} for _, form in ipairs(PRIORITY) do result[type][form] = 0 end end for slot, item in pairs(inv.list()) do local type, form = item.name:match".-:(%l-)_(%l*)" if result[type] ~= nil then 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.1) 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 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 local num_requests = math.ceil(amount / AMOUNT_USED) print(("Draining %d %s %ss"):format(amount, type, form)) request_multiple(type, conversion, num_requests) end function fill (type, src, dest, amount) local conversion = nil local num_requests = math.ceil(amount / AMOUNT_USED) 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" num_requests = math.ceil(amount / AMOUNT_RETURNED) end end print(("Converting %d %s %ss to %ss"):format(amount, type, src, dest)) request_multiple(type, conversion, num_requests) end -- making the decision what to do function should_drain (type, counts) for _, form in ipairs(PRIORITY) do local diff = counts[form] - limits[type][form][2] if diff > 0 then return form, diff * REDUCTION_FACTOR end end end function should_fill (type, counts) local fill_dest, fill_src, amount_needed, amount_spare = nil, nil, 0, 0 for _, form in ipairs(PRIORITY) do local diff = limits[type][form][1] - counts[form] if diff > 0 then if fill_dest == nil then fill_dest = form amount_needed = diff end else fill_src = form amount_spare = counts[form] end if fill_src ~= nil and fill_dest ~= nil then break end end local amount_to_use = nil local ratio = AMOUNT_USED / AMOUNT_RETURNED local amount_needed_src = nil if fill_src == "block" then amount_needed_src = amount_needed / ratio else amount_needed_src = amount_needed * ratio end if amount_needed_src < amount_spare then amount_to_use = amount_needed_src else amount_to_use = amount_spare end return fill_dest, fill_src, amount_to_use * REDUCTION_FACTOR end function decide_action (type, counts) -- using the levels of each form of the item, decide what to do local drain_form, drain_amt = should_drain(type, counts) local fill_dest, fill_src, fill_amt = should_fill(type, counts) if drain_form ~= nil then drain(type, drain_form, drain_amt) elseif fill_dest ~= nil and fill_src ~= nil then fill(type, fill_src, fill_dest, fill_amt) end end function print_counts (items) for type, counts in pairs(items) do for form, count in pairs(counts) do print(("%s %s: %d"):format(type, form, count)) end end end while true do -- 1. Sum items in inventory and organize by item type local items = sum_items(peripheral.wrap(INVENTORY)) -- print_counts(items) -- 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