-- 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 = 64 -- 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 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) 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 in pairs(items) do local type, form = item.name:match".-:(%l-)_(%l*)" if type == item_type and dist[form] ~= nil then dist[form] = dist[form] + item.count end end 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 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. 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) 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