compacting-storage.lua: Total rewrite
This commit is contained in:
parent
283df296c5
commit
d3f03632e2
1 changed files with 147 additions and 136 deletions
|
|
@ -8,164 +8,164 @@
|
||||||
|
|
||||||
local INVENTORY = "left"
|
local INVENTORY = "left"
|
||||||
local SLEEP_TIME = 30
|
local SLEEP_TIME = 30
|
||||||
local AMOUNT_USED = 63 -- the amount of item used per request
|
local NUGGET_RATIO = 63 -- amount of nuggets per craft
|
||||||
local AMOUNT_RETURNED = 7 -- the amount of item returned per request
|
local BLOCK_RATIO = 7 -- amount of blocks per craft
|
||||||
local REDUCTION_FACTOR = 0.75 -- when draining, what percent to do at a time
|
|
||||||
local ITEM_TYPES = { "iron", "copper", "zinc", "gold", "electrum" }
|
local ITEM_TYPES = { "iron", "copper", "zinc", "gold", "electrum" }
|
||||||
local PRIORITY = { "ingot", "block", "nugget" }
|
|
||||||
|
|
||||||
function stacks (num)
|
local STACKS = 64
|
||||||
return 64 * num
|
local NUGGETS = 1
|
||||||
end
|
local INGOTS = 9
|
||||||
|
local BLOCKS = 64
|
||||||
-- 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
|
-- Levels
|
||||||
local limits = {}
|
local MIN_NUM = (4 * STACKS * NUGGETS) + (4 * STACKS * INGOTS)
|
||||||
for _, type in ipairs(ITEM_TYPES) do
|
local MAX_NUM = (8 * STACKS * NUGGETS) + (8 * STACKS * INGOTS)
|
||||||
limits[type] = {
|
|
||||||
nugget = { stacks(4), stacks(8) },
|
-- TODO map targets to specific relays and faces
|
||||||
ingot = { stacks(4), stacks(8) },
|
-- Key - 1: nuggets_to_ingots, 2: ingots_to_blocks, 3: blocks_to_ingots,
|
||||||
block = { stacks(1), stacks(1000) }
|
-- 4: ingots_to_nuggets, 5: enable/disable production
|
||||||
}
|
local target = {}
|
||||||
|
target.iron = {}
|
||||||
|
target.iron[1] = "0:front"
|
||||||
|
target.iron[2] = "0:top"
|
||||||
|
target.iron[3] = "0:back"
|
||||||
|
target.iron[4] = "16:front"
|
||||||
|
target.iron[5] = "17:back"
|
||||||
|
target.copper = {}
|
||||||
|
target.copper[1] = "1:front"
|
||||||
|
target.copper[2] = "1:top"
|
||||||
|
target.copper[3] = "1:back"
|
||||||
|
target.copper[4] = "16:top"
|
||||||
|
target.copper[5] = "18:front"
|
||||||
|
target.zinc = {}
|
||||||
|
target.zinc[1] = "2:front"
|
||||||
|
target.zinc[2] = "2:top"
|
||||||
|
target.zinc[3] = "2:back"
|
||||||
|
target.zinc[4] = "16:back"
|
||||||
|
target.zinc[5] = "18:top"
|
||||||
|
target.gold = {}
|
||||||
|
target.gold[1] = "3:front"
|
||||||
|
target.gold[2] = "3:top"
|
||||||
|
target.gold[3] = "3:back"
|
||||||
|
target.gold[4] = "17:front"
|
||||||
|
target.gold[5] = "18:back"
|
||||||
|
target.electrum = {}
|
||||||
|
target.electrum[1] = "4:front"
|
||||||
|
target.electrum[2] = "4:top"
|
||||||
|
target.electrum[3] = "4:back"
|
||||||
|
target.electrum[4] = "17:top"
|
||||||
|
|
||||||
|
-- basic actions
|
||||||
|
function craft (item_type, conversion_type)
|
||||||
|
-- TODO double check this
|
||||||
|
local relay_num, face = string.match(target[item_type][conversion_type],
|
||||||
|
"(d+):(%l+)"
|
||||||
|
)
|
||||||
|
local periph = string.format("redstone_relay_%d", relay_num)
|
||||||
|
peripheral.call(periph, "setOutput", face, true)
|
||||||
|
os.sleep(0.1)
|
||||||
|
peripheral.call(periph, "setOutput", face, false)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Map types of conversions to specific faces
|
function craft_multiple (item_type, conversion_type, count)
|
||||||
local convert = {}
|
if count < 1 then
|
||||||
convert.nugget_to_ingot = "front"
|
return
|
||||||
convert.ingot_to_block = "top"
|
else
|
||||||
convert.block_to_ingot = "back"
|
craft(item_type, conversion_type)
|
||||||
|
os.sleep(1)
|
||||||
|
return craft_multiple(item_type, conversion_type, count - 1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function execute_crafts (item_type, crafts)
|
||||||
|
for type, num_crafts in pairs(crafts) do
|
||||||
|
if type == "nugget" then
|
||||||
|
if num_crafts > 0 then
|
||||||
|
craft_multiple(item_type, 4, num_crafts)
|
||||||
|
elseif num_crafts < 0 then
|
||||||
|
craft_multiple(item_type, 1, num_crafts)
|
||||||
|
end
|
||||||
|
elseif type == "block" then
|
||||||
|
if num_crafts > 0 then
|
||||||
|
craft_multiple(item_type, 2, num_crafts)
|
||||||
|
elseif num_crafts < 0 then
|
||||||
|
craft_multiple(item_type, 3, num_crafts)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function set_production (item_type, produce)
|
||||||
|
local target_string = target[item_type][5]
|
||||||
|
if target_string == nil then return end
|
||||||
|
local relay_num, face = string.match(target_string,
|
||||||
|
"(d+):(%l+)"
|
||||||
|
)
|
||||||
|
local periph = string.format("redstone_relay_%d", relay_num)
|
||||||
|
-- ON is disable production
|
||||||
|
peripheral.call(periph, "setOutput", face, not produce)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- logic
|
||||||
|
|
||||||
function sum_items (inv)
|
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 = {}
|
local result = {}
|
||||||
for _, type in ipairs(ITEM_TYPES) do
|
for _, item in pairs(inv.list()) do
|
||||||
result[type] = {}
|
if result[item.name] == nil then result[item.name] = 0 end
|
||||||
for _, form in ipairs(PRIORITY) do
|
result[item.name] = result[item.name] + item.count
|
||||||
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
|
end
|
||||||
return result
|
return result
|
||||||
end
|
end
|
||||||
|
|
||||||
-- basic actions
|
function dist_to_num (dist)
|
||||||
function request (item_type, conversion_type)
|
return dist.nuggets + dist.ingots * INGOTS + dist.blocks * BLOCKS
|
||||||
target[item_type].setOutput(convert[conversion_type], true)
|
|
||||||
os.sleep(0.1)
|
|
||||||
target[item_type].setOutput(convert[conversion_type], false)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function request_multiple (item_type, conversion_type, count)
|
function get_dist (item_type, items)
|
||||||
if count < 1 then
|
local dist = { nuggets: 0, ingots: 0, blocks: 0 }
|
||||||
return
|
for _, item in pairs(items) do
|
||||||
else
|
local type, form = item.name:match".-:(%l-)_(%l*)"
|
||||||
request(item_type, conversion_type)
|
if type == item_type and dist[form] ~= nil then
|
||||||
os.sleep(1)
|
dist[form] = dist[form] + item.count
|
||||||
return request_multiple(item_type, conversion_type, count - 1)
|
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
return dist
|
||||||
end
|
end
|
||||||
|
|
||||||
-- fundamental actions
|
function get_diff (dist1, dist2)
|
||||||
function drain (type, form, amount)
|
return {
|
||||||
local conversion = nil
|
nuggets: dist1.nuggets - dist2.nuggets,
|
||||||
if form == "nugget" then
|
ingots: dist1.ingots - dist2.ingots,
|
||||||
conversion = "nugget_to_ingot"
|
blocks: dist1.blocks - dist2.blocks
|
||||||
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
|
end
|
||||||
|
|
||||||
function fill (type, src, dest, amount)
|
function filter_clamp (diff, current_dist)
|
||||||
local conversion = nil
|
-- reduce diff numbers to what can be crafted using current resources
|
||||||
local num_requests = math.ceil(amount / AMOUNT_USED)
|
local new_diff = { nuggets: 0, ingots: 0, blocks: 0 }
|
||||||
if dest == "block" then
|
if diff.blocks > 0 then
|
||||||
conversion = "ingot_to_block"
|
new_diff.blocks = math.min(
|
||||||
elseif dest == "ingot" then
|
diff.blocks,
|
||||||
if src == "nugget" then
|
math.floor(current_dist.ingots / 9)
|
||||||
conversion = "nugget_to_ingot"
|
)
|
||||||
elseif src == "block" then
|
|
||||||
conversion = "block_to_ingot"
|
|
||||||
num_requests = math.ceil(amount / AMOUNT_RETURNED)
|
|
||||||
end
|
end
|
||||||
|
if diff.nuggets > 0 then
|
||||||
|
new_diff.nuggets = math.min(
|
||||||
|
diff.nuggets,
|
||||||
|
current_dist.ingots * 9
|
||||||
|
)
|
||||||
end
|
end
|
||||||
if conversion == nil then return end
|
new_diff.ingots = (new_diff.nuggets / 9) + (new_diff.blocks * 9)
|
||||||
print(("Converting %d %s %ss to %ss"):format(amount, type, src, dest))
|
|
||||||
request_multiple(type, conversion, num_requests)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- making the decision what to do
|
function diff_to_crafts (diff)
|
||||||
function should_drain (type, counts)
|
-- TODO double-check this one
|
||||||
for _, form in ipairs(PRIORITY) do
|
-- go from one end e.g. nuggets to the other e.g. blocks, removing
|
||||||
local diff = counts[form] - limits[type][form][2]
|
-- from the diff to create crafts until the diff is empty
|
||||||
if diff > 0 then
|
local crafts = {}
|
||||||
return form, diff * REDUCTION_FACTOR
|
crafts.nuggets = math.floor(diff.nuggets / NUGGET_RATIO)
|
||||||
end
|
crafts.blocks = math.floor(diff.blocks / BLOCK_RATIO)
|
||||||
end
|
return crafts
|
||||||
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
|
|
||||||
-- if the source is higher priority and using it would put it under
|
|
||||||
-- the fill limit, don't use it as a source
|
|
||||||
if fill_dest == nil and diff > -AMOUNT_USED then
|
|
||||||
-- do nothing
|
|
||||||
else
|
|
||||||
fill_src = form
|
|
||||||
amount_spare = counts[form]
|
|
||||||
end
|
|
||||||
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
|
|
||||||
if fill_src == "nugget" and fill_dest == "block" then return 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
|
end
|
||||||
|
|
||||||
function print_counts (items)
|
function print_counts (items)
|
||||||
|
|
@ -181,9 +181,20 @@ while true do
|
||||||
local items = sum_items(peripheral.wrap(INVENTORY))
|
local items = sum_items(peripheral.wrap(INVENTORY))
|
||||||
-- print_counts(items)
|
-- print_counts(items)
|
||||||
|
|
||||||
-- 2. take one action for each item type per cycle
|
-- 2. either work towards a desired distribution or create more resources
|
||||||
for item_type, counts in pairs(items) do
|
for _, item_type in ipairs(ITEM_TYPES) do
|
||||||
decide_action(item_type, counts)
|
local current_dist = get_dist(item_type, items)
|
||||||
|
local num = dist_to_num(current_dist)
|
||||||
|
if num > MAX_NUM then set_production(item_type, false)
|
||||||
|
if num > MIN_NUM then
|
||||||
|
local desired_dist = decide_dist(num)
|
||||||
|
local diff = get_diff(current_dist, desired_dist)
|
||||||
|
diff = filter_clamp(diff, current_dist)
|
||||||
|
local crafts = diff_to_crafts(dist)
|
||||||
|
execute_crafts(item_type, crafts)
|
||||||
|
else
|
||||||
|
set_production(item_type, true)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- sleep until next cycle
|
-- sleep until next cycle
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue