cc-stuff/compacting-storage.lua
2026-01-17 17:33:29 -05:00

251 lines
7.1 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 MAIN_TICKER = ""
local REQUEST_TICKER = ""
local CRAFTING_REQUESTER = ""
local STORAGE_ADDR = ""
local COMPACTING_ADDR = ""
local UNPACKING_ADDR = ""
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 = {
nugget = "minecraft",
ingot = "minecraft",
block = "minecraft",
},
copper = {
nugget = "create",
ingot = "minecraft",
block = "minecraft",
},
zinc = {
nugget = "create",
ingot = "create",
block = "create",
},
gold = {
nugget = "minecraft",
ingot = "minecraft",
block = "minecraft",
},
electrum = {
nugget = "createaddition",
ingot = "createaddition",
block = "createaddition",
},
}
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)
local getName = {
nugget = function (item_type)
return ("%s:%s_nugget"):format(
ITEM_TYPES[item_type].nugget,
item_type
)
end,
ingot = function (item_type)
return ("%s:%s_ingot"):format(
ITEM_TYPES[item_type].ingot,
item_type
)
end,
block = function (item_type)
return ("%s:%s_block"):format(
ITEM_TYPES[item_type].block,
item_type
)
end,
}
-- basic actions
function craft (requester, item_type, conversion_type)
-- conversion_type key: 1, nuggets to ingots; 2, ingots to blocks;
-- 3, blocks to ingots; 4, ingots to nuggets
local convert = {
getName.nugget,
getName.ingot,
getName.block,
getName.ingot,
}
local name = convert[conversion_type](item_type)
local compacting = conversion_type <= 2
local count, address
if compacting then
count = NUGGET_RATIO
address = COMPACTING_ADDR
else
count = BLOCK_RATIO
address = UNPACKING_ADDR
end
requester.setAddress(address)
requester.setRequest({ name = name, count = count })
requester.request()
end
function craft_multiple (requester, item_type, conversion_type, count)
if count < 1 then
return
else
craft(requester, item_type, conversion_type)
os.sleep(1)
return craft_multiple(requester, item_type, conversion_type, count - 1)
end
end
function execute_crafts (requester, item_type, crafts)
local num_crafts = crafts.nugget
if num_crafts > 0 then
print(("Crafting %s nuggets"):format(item_type))
craft_multiple(requester, item_type, 4, num_crafts)
elseif num_crafts < 0 then
print(("Crafting %s ingots"):format(item_type))
craft_multiple(requester, item_type, 1, -num_crafts)
end
num_crafts = crafts.block
if num_crafts > 0 then
print(("Crafting %s blocks"):format(item_type))
craft_multiple(requester, item_type, 2, num_crafts)
elseif num_crafts < 0 then
print(("Crafting %s ingots"):format(item_type))
craft_multiple(requester, item_type, 3, -num_crafts)
end
end
function request_more (ticker, item_type)
ticker.requestFiltered(STORAGE_ADDR, { name = getName.nugget(item_type) })
end
-- logic
function sum_items (inv_f)
local result = {}
for _, item in pairs(inv_f()) 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.nugget + (dist.ingot * INGOTS) + (dist.block * BLOCKS)
end
function get_dist (item_type, items)
local dist = { nugget = 0, ingot = 0, block = 0 }
for item, count in pairs(items) do
local type, form = item:match":(%l-)_(%l*)"
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 = { nugget = 0, ingot = 0, block = 0 }
if num > MAX_NUM then
local excess = num - MAX_NUM
dist.block = math.floor(excess / BLOCKS)
num = num - (dist.block * BLOCKS)
end
local balance = math.floor(num / 10)
dist.nugget, dist.ingot = balance, balance
num = num - (balance * 10)
dist.nugget = dist.nugget + num
return dist
end
function get_diff (dist1, dist2)
return {
nugget = dist1.nugget - dist2.nugget,
ingot = dist1.ingot - dist2.ingot,
block = dist1.block - dist2.block
}
end
function filter_clamp (diff, current_dist)
-- reduce diff numbers to what can be crafted using current resources
if diff.block > 0 then
diff.block = math.min(
diff.block - (diff.block % BLOCK_RATIO),
math.floor(current_dist.ingot / 9)
)
end
if diff.nugget > 0 then
diff.nugget = math.min(
diff.nugget - (diff.nugget % NUGGET_RATIO),
current_dist.ingot * 9
)
end
diff.ingot = (-diff.nugget / 9) + (-diff.block * 9)
return diff
end
function diff_to_crafts (diff)
-- 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.nugget = math.floor(diff.nugget / NUGGET_RATIO)
crafts.block = math.floor(diff.block / 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
local main_t = peripheral.wrap(MAIN_TICKER)
local request_t = peripheral.wrap(REQUEST_TICKER)
local craft_requester = peripheral.wrap(CRAFTING_REQUESTER)
craft_requester.setConfiguration("strict")
local requesting = {}
while true do
-- 1. Sum items in inventory and organize by item type
local items = sum_items(main_t.stock)
-- print_counts(items)
-- 2. either work towards a desired distribution or create more resources
for item_type, _ in pairs(ITEM_TYPES) do
local current_dist = get_dist(item_type, items)
local num = dist_to_num(current_dist)
if num > MIN_NUM then
local desired_dist = decide_dist(num)
local diff = get_diff(desired_dist, current_dist)
diff = filter_clamp(diff, current_dist)
local crafts = diff_to_crafts(diff)
execute_crafts(craft_requester, item_type, crafts)
elseif num > MAX_NUM then
-- keep requesting until above MAX_NUM
requesting[item_type] = nil
else
requesting[item_type] = true
end
if requesting[item_type] then
request_more(request_t, item_type)
end
end
-- sleep until next cycle
os.sleep(SLEEP_TIME)
end