cc-stuff/compacting-storage.lua

224 lines
6.8 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 NUGGET_RATIO = 63 -- amount of nuggets per craft
local BLOCK_RATIO = 7 -- amount of blocks per craft
local ITEM_TYPES = { "iron", "copper", "zinc", "gold", "electrum" }
local STACKS = 64
local NUGGETS = 1
local INGOTS = 9
local BLOCKS = 81
-- Levels
local MIN_NUM = (4 * STACKS * NUGGETS) + (4 * STACKS * INGOTS)
local MAX_NUM = (8 * STACKS * NUGGETS) + (8 * STACKS * INGOTS)
-- TODO map targets to specific relays and faces
-- Key - 1: nuggets_to_ingots, 2: ingots_to_blocks, 3: blocks_to_ingots,
-- 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
function craft_multiple (item_type, conversion_type, count)
if count < 1 then
return
else
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
print(("Crafting %s nuggets"):format(item_type))
craft_multiple(item_type, 4, num_crafts)
elseif num_crafts < 0 then
print(("Crafting %s ingots"):format(item_type))
craft_multiple(item_type, 1, num_crafts)
end
elseif type == "block" then
if num_crafts > 0 then
print(("Crafting %s blocks"):format(item_type))
craft_multiple(item_type, 2, num_crafts)
elseif num_crafts < 0 then
print(("Crafting %s ingots"):format(item_type))
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
if produce then print(("Producing %s"):format(item_type))
peripheral.call(periph, "setOutput", face, not produce)
end
-- logic
function sum_items (inv)
local result = {}
for _, item in pairs(inv.list()) do
if result[item.name] == nil then result[item.name] = 0 end
result[item.name] = result[item.name] + item.count
end
return result
end
function dist_to_num (dist)
return dist.nuggets + dist.ingots * INGOTS + dist.blocks * BLOCKS
end
function get_dist (item_type, items)
local dist = { nuggets = 0, ingots = 0, blocks = 0 }
for item, count in pairs(items) do
local type, form = item:match":(%l-)_(%l*)"
form = string.format("%ss", form)
if type == item_type and dist[form] ~= nil then
dist[form] = dist[form] + count
end
end
return dist
end
function decide_dist (num)
local dist = { nuggets = 0, ingots = 0, blocks = 0 }
if num > MAX_NUM then
local excess = num - MAX_NUM
dist.blocks = math.floor(excess / BLOCKS)
num = num - (dist.blocks * BLOCKS)
end
local balance = math.floor(num / 10)
dist.nuggets, dist.ingots = balance, balance
num = num - (balance * 10)
dist.nuggets = dist.nuggets + num
return dist
end
function get_diff (dist1, dist2)
return {
nuggets = dist1.nuggets - dist2.nuggets,
ingots = dist1.ingots - dist2.ingots,
blocks = dist1.blocks - dist2.blocks
}
end
function filter_clamp (diff, current_dist)
-- reduce diff numbers to what can be crafted using current resources
local new_diff = { nuggets = 0, ingots = 0, blocks = 0 }
if diff.blocks > 0 then
new_diff.blocks = math.min(
diff.blocks,
math.floor(current_dist.ingots / 9)
)
end
if diff.nuggets > 0 then
new_diff.nuggets = math.min(
diff.nuggets,
current_dist.ingots * 9
)
end
new_diff.ingots = (new_diff.nuggets / 9) + (new_diff.blocks * 9)
end
function diff_to_crafts (diff)
-- TODO double-check this one
-- go from one end e.g. nuggets to the other e.g. blocks, removing
-- from the diff to create crafts until the diff is empty
local crafts = {}
crafts.nuggets = math.floor(diff.nuggets / NUGGET_RATIO)
crafts.blocks = math.floor(diff.blocks / BLOCK_RATIO)
return crafts
end
function print_counts (items)
for item, amount in pairs(items) do
local type, form = string.match(item, ":(%l+)_(%l+)")
if type ~= nil and form ~= nil then
print(("%s %s: %d"):format(type, form, amount))
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. either work towards a desired distribution or create more resources
for _, item_type in ipairs(ITEM_TYPES) do
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) end
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
-- sleep until next cycle
os.sleep(SLEEP_TIME)
end