m-mueller678

mystical phyto open computers

Dec 6th, 2021
673
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. local component=require('component')
  2.  
  3. local SEED_SLOT = 1
  4. local machine_name='thermal_expansion:machine'
  5.  
  6. local machines = nil
  7. local output_inventory = nil
  8. local item_requests = {}
  9. local item_seeds = {}
  10.  
  11. function remove_seed(machine)
  12.     assert(component.invoke(machine.address,'transferItem',machine.machine_side,machine.inventoy_side,1,SEED_SLOT)==1,'cannot remove seed from '..machine.address..':'..machine.side)
  13. end
  14.  
  15. function insert_seed(machine, slot)
  16.     assert(component.invoke(machine.address,'transferItem',machine.inventoy_side,machine.machine_side,1,slot)==1,'cannot insert seed into '..machine.address..':'..machine.side..'from slot '..slot)
  17. end
  18.  
  19. function get_seed(machine)
  20.     return (component.invoke(machine.address,'getStackInSlot',machine.machine_side,SEED_SLOT) or {}).name
  21. end
  22.  
  23. -- scan environemnt
  24. function get_blocks()
  25.     local seed_inventory=nil
  26.     output_inventory=nil
  27.     machines= {}
  28.     for transposer in component.list('transposer') do
  29.         local any_machines=false
  30.         local non_machine_inventory=nil
  31.         for side in 0,5 do
  32.             local inv=component.invoke(transposer,'getInventoryName',side)
  33.             if inv==machine_name then
  34.                 any_machines=true
  35.             else if inv then
  36.                 assert(non_machine_inventory==nil,'multiple non machine inventories at '..transposer)
  37.                 non_machine_inventory=inv
  38.             end
  39.         end
  40.             assert(non_machine_inventory ~=nil, 'transposer '..transposer..' has no non machine inventories')
  41.             if any_machines then
  42.             assert(seed_inventory == non_machine_inventory or seed_inventory ==nil,'multiple candidates for seed inventory: '..non_machine_inventory..', '..seed_inventory)
  43.             seed_inventory=non_machine_inventory
  44.             for side in 0,5 do
  45.                 if component.invoke(transposer,'getInventoryName',i)==machine_name then
  46.                     machines[#machines]={
  47.                         address=transposer,
  48.                         machine_side=i,
  49.                         inventoy_side=non_machine_inventory,
  50.                     }
  51.                 end
  52.             end
  53.         else
  54.             assert(output_inventory ==nil,'multiple candidates for output inventory at transposers: '..output_inventory.address..', ,'..transposer)
  55.             output_inventory={
  56.                 address=transposer,
  57.                 side=non_machine_inventory
  58.             }
  59.             end
  60.       end
  61.     end
  62. end
  63.  
  64. -- configuration file
  65. function get_item_info()
  66.     local f, err = loadfile("item_requests")
  67.     if not f then
  68.         error(err)
  69.     end
  70.     local r, s = f()
  71.     assert(type(r) == "table", "item_requests not a table")
  72.     assert(type(s) == "table", "item_seeds not a table")
  73.     item_requests = r
  74.     item_seeds = s
  75. end
  76.  
  77. --
  78. function find_seed_slot(name)
  79.     local i=1
  80.     for stack in component.invoke(machines[1].address,'getAllStacks',machines[1].inventoy_side) do
  81.         if stack.name==name then
  82.             return i
  83.         end
  84.         i=i+1
  85.     end
  86. end
  87.  
  88. -- main function, called in loop
  89. function allocate_machines()
  90.     get_blocks()
  91.     get_item_info()
  92.     local item_counts = {}
  93.    
  94.     for stack in component.invoke(output_inventory.address,'getAllStacks',output_inventory.side) do
  95.         if item_requests[item.name] then
  96.             item_counts[item.name] = (item_counts[item.name] or 0) + stack.size
  97.         end
  98.     end
  99.     local seeds = {}
  100.     local weights = {[0] = 0}
  101.     for item_name, request in pairs(item_requests) do
  102.         local available = item_counts[item_name] or 0
  103.         if available < request then
  104.             local weight = request / (available + 1)
  105.             local index = #weights + 1
  106.             weights[index] = weight
  107.             seeds[index] = item_seeds[item_name]
  108.         end
  109.     end
  110.  
  111.     for i = 2, #weights do
  112.         weights[i] = weights[i] + weights[i - 1]
  113.     end
  114.  
  115.     for _, machine in pairs(machines) do
  116.         if get_seed(machine) ~= nil then
  117.             remove_seed(machine)
  118.         end
  119.     end
  120.  
  121.     for _, machine in pairs(machines) do
  122.         local ni, ns = get_new_item_position(weights, seeds)
  123.         if ni ~= nil then
  124.             insert_seed(machine, ni, ns)
  125.         end
  126.     end
  127. end
  128.  
  129. -- seed allocation logic
  130. function get_new_item_position(weights, items)
  131.     local function remove_weight(weights, items, index)
  132.         if index < #weights then
  133.             local removed = weights[index] - weights[index - 1] or 0
  134.             local last = weights[#weights] - weights[#weights - 1]
  135.             local difference = last - removed
  136.             items[index] = items[#weights]
  137.             repeat
  138.                 weights[index] = weights[index] + difference
  139.                 index = index + 1
  140.             until index == #weights
  141.         end
  142.         weights[index] = nil
  143.         items[index] = nil
  144.     end
  145.     local function choose_weighted(weights)
  146.         local not_enough = 0
  147.         local enough = #weights
  148.         if enough == 0 then
  149.             return nil
  150.         end
  151.         local rand = math.random() * weights[#weights]
  152.         while not_enough + 1 < enough do
  153.             local mid = math.floor((not_enough + enough) / 2)
  154.             if weights[mid] < rand then
  155.                 not_enough = mid
  156.             else
  157.                 enough = mid
  158.             end
  159.         end
  160.         return enough
  161.     end
  162.  
  163.     local chosen_index = choose_weighted(weights)
  164.     if chosen_index == nil then
  165.         return nil
  166.     end
  167.     local s = find_seed_slot(items[chosen_index])
  168.     if s ~= nil then
  169.         return s
  170.     else
  171.         remove_weight(weights, items, chosen_index)
  172.         return get_new_item_position(weights, items)
  173.     end
  174. end
  175.  
  176. while true do
  177.     ok, err = pcall(allocate_machines)
  178.     if ok then
  179.         io.write("ok ")
  180.         sleep(300)
  181.     else
  182.         print()
  183.         print(err)
  184.         sleep(5)
  185.     end
  186. end
  187.  
RAW Paste Data