186 lines
5.6 KiB
Lua
186 lines
5.6 KiB
Lua
-- 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 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(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] = {}
|
|
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.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
|
|
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
|
|
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 = do
|
|
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
|
|
return amount_needed_src
|
|
else
|
|
return amount_spare
|
|
end
|
|
end
|
|
return fill_dest, fill_src, amount_to_use
|
|
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 = should_fill(type, counts)
|
|
if drain_form ~= nil then
|
|
drain(type, form, drain_amt)
|
|
elseif fill_dest ~= nil then
|
|
fill(type, fill_src, fill_dest, fill_amt)
|
|
end
|
|
end
|
|
end
|
|
|
|
function print_counts (items)
|
|
for type, counts in pairs(items) do
|
|
for form, count in ipairs(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
|