Advertisement
fatboychummy

Pain and suffering part 2 (optimized now :D)

Aug 14th, 2023
1,012
0
Never
1
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 10.74 KB | None | 0 0
  1. -- These values are per 500mB, since a crystal takes 6000mB to make, we will need to divide everything by 12 later to get their actual increment in values.
  2. ---@type table<string, laser_item>
  3. local LASER_VALUES = {}
  4. do
  5.   local function ilv(name, purity, strength, efficiency, max_purity, max_strength, max_efficiency)
  6.     LASER_VALUES[name] = {
  7.       purity = purity or 0,
  8.       strength = strength or 0,
  9.       efficiency = efficiency or 0,
  10.       max_purity = max_purity or 100,
  11.       max_strength = max_strength or 100,
  12.       max_efficiency = max_efficiency or 100
  13.     }
  14.   end
  15.  
  16.   ilv("minecraft:ender_pearl", 2, 0, 0, 100, 0, 0)
  17.   ilv("minecraft:quartz", -1, 0, 7, 0, 0, 80)
  18.   ilv("minecraft:gunpowder", -5, 8, 4, 0, 70, 60)
  19.   ilv("minecraft:diamond", 5, 0, 0, 100, 0, 0)
  20.   ilv("minecraft:glowstone_dust", -2, 6, 3, 0, 50, 50)
  21.   ilv("minecraft:iron_ingot", 0, -2, 1, 0, 0, 20)
  22.   ilv("rftoolsbase:dimensionalshard", 1, 8, 8, 100, 80, 80)
  23.   ilv("minecraft:prismarine_shard", 0, 3, 3, 0, 30, 30)
  24.   ilv("minecraft:gold_ingot", 0, -1, 1, 0, 0, 30)
  25.   ilv("minecraft:prismarine_crystals", 0, 4, 4, 0, 35, 35)
  26.   ilv("minecraft:coal", -1, -10, 0, 0, 0, 0)             -- Not sure why you'd want to use coal.
  27.   ilv("minecraft:nether_star", -60, 90, 90, 0, 100, 100) -- Very powerful, but also requires a repurification.
  28.   ilv("minecraft:nether_wart", -3, 2, -2, 0, 35, 1)
  29.   ilv("minecraft:redstone", -1, 5, 0, 0, 60, 0)
  30.   ilv("minecraft:slime_ball", 0, 0, -10, 0, 0, 1) -- Not sure why you'd want to use slime balls.
  31.   ilv("minecraft:emerald", 8, 0, 0, 100, 0, 0)    -- May be used as a subsitute to repurification?
  32.   ilv("minecraft:blaze_powder", -6, 5, 5, 0, 70, 70)
  33.   ilv("minecraft:ghast_tear", -20, 25, 15, 0, 100, 100)
  34.   ilv("minecraft:snowball", 1, 0, 1, 30, 0, 40)
  35. end
  36.  
  37. --- Deep clone a table
  38. ---@param t any
  39. ---@return any t
  40. local function deep_copy(t)
  41.   if type(t) ~= "table" then return t end
  42.  
  43.   local out = {}
  44.  
  45.   for k, v in pairs(t) do
  46.     out[k] = deep_copy(v)
  47.   end
  48.  
  49.   return out
  50. end
  51.  
  52. --- This function will do the exact same thing as the original best_item_combo function.
  53. --- However, there will be a few things done to optimize the algorithm, as currently there are just
  54. --- too many combinations to check.
  55. --- We will note, the original description is as follows:
  56. ---   This function will bruteforce the best combination of items to use in the lasers.
  57. ---   It will return a table of items to use, and the amount of items to use, and in what order.
  58. ---   This function only needs to care about strength and efficiency, though we must note purity CANNOT go below 1%
  59. ---   This function will also take into account the amount of items we have in the storage chest.
  60. ---   We will likely need to use some heavy recursion here.
  61. --- In order to optimize this, we will need to do a few things:
  62. ---  1. We will need to sort the items by their type, so we can group them together.
  63. ---  2. We will greedily take from each type, until they reach their maximum potency, minimum purity, or run out of items.
  64. --- Hopefully this will be enough to optimize it.
  65. ---@param current laser_list? The current list of items we are using, along with the current strength, efficiency, and purity.
  66. ---@param item_list short_laser_item[]? The list of items we can use.
  67. ---@return table<integer, string> list The best list of items found.
  68. ---@return integer strength The strength of the best list of items found.
  69. ---@return integer efficiency The efficiency of the best list of items found.
  70. ---@return integer purity The purity of the best list of items found.
  71. local function best_item_combo_optimized(current, item_list)
  72.   local x = not current
  73.   -- Initial purity (after leaving the purifier) is 85%, initial strength is 10%, initial efficiency is 10%.
  74.   current = current or { list = {}, used = {}, strength = 10, efficiency = 10, purity = 85 }
  75.  
  76.   if not item_list then
  77.     -- We will need to initialize the list of items available, searching the storage chest and adding items as we see them.
  78.     -- We should collapse all similar items so all we have are the item names and the amount of items.
  79.     item_list = {}
  80.  
  81.     local storage = config.peripherals.chests.storage
  82.     local list = smn.call(storage, "list")
  83.     for _, item in pairs(list) do
  84.       local found = false
  85.       for _, item2 in ipairs(item_list) do
  86.         if item.name == item2.name then
  87.           item2.count = item2.count + item.count
  88.           found = true
  89.           break
  90.         end
  91.       end
  92.  
  93.       if not found then
  94.         table.insert(item_list, { name = item.name, count = item.count })
  95.       end
  96.     end
  97.   end
  98.   -- Coincidentally, the item list is already sorted "enough" here. We don't particularly care about the individual values, just that they are grouped together.
  99.  
  100.   -- We will need to loop through the item list, and for each item, we will need to greedily add it to the current list, then call this function again.
  101.   -- We will need to keep track of the best item list, and the best strength and efficiency.
  102.   local best_strength = current.strength
  103.   local best_efficiency = current.efficiency
  104.   local best_purity = current.purity
  105.   local best_list = {}
  106.  
  107.   for _, item in ipairs(item_list) do
  108.  
  109.     local new_strength, new_efficiency, new_purity = current.strength, current.efficiency, current.purity
  110.     local last_strength, last_efficiency = new_strength, new_efficiency
  111.     local added = 0
  112.     repeat
  113.       -- Check how much of this item remains
  114.       local remaining = item.count - (current.used[item.name] or 0)
  115.       local exit = false
  116.  
  117.       if remaining > 0 and LASER_VALUES[item.name] then
  118.  
  119.         -- Add this item to both lists.
  120.         table.insert(current.list, item.name)
  121.         current.used[item.name] = (current.used[item.name] or 0) + 1
  122.         added = added + 1
  123.  
  124.         -- Calculate the new strength, efficiency, and purity.
  125.         local laser_value = LASER_VALUES[item.name]
  126.  
  127.         -- If the values are above zero, we cannot go above the maximum.
  128.         -- If the values are below or equal to zero, we can go down essentially forever (to a minimum of zero)
  129.         -- We will also hard-cap each side at 100 and 0, just to ensure nothing goes crazy anywhere.
  130.  
  131.         if laser_value.strength > 0 then
  132.           new_strength = math.min(new_strength + laser_value.strength / 12, laser_value.max_strength, 100)
  133.         else
  134.           new_strength = math.max(new_strength + laser_value.strength / 12, laser_value.max_strength, 0)
  135.         end
  136.  
  137.         if laser_value.efficiency > 0 then
  138.           new_efficiency = math.min(new_efficiency + laser_value.efficiency / 12, laser_value.max_efficiency, 100)
  139.         else
  140.           new_efficiency = math.max(new_efficiency + laser_value.efficiency / 12, laser_value.max_efficiency, 0)
  141.         end
  142.  
  143.         if laser_value.purity > 0 then
  144.           new_purity = math.min(new_purity + laser_value.purity / 12, laser_value.max_purity, 100)
  145.         else
  146.           new_purity = math.max(new_purity + laser_value.purity / 12, laser_value.max_purity, 0)
  147.         end
  148.  
  149.         -- Check if the values are out of bounds.
  150.  
  151.         -- Check strength.
  152.         if new_strength >= laser_value.max_strength then
  153.           if last_strength < laser_value.max_strength then
  154.             -- We can keep this item, but we should exit immediately.
  155.             -- Leaving this empty block here for documentation.
  156.           else
  157.             -- We were over the max last time, and we are still over the max, so we should remove this item, then exit.
  158.             table.remove(current.list, #current.list)
  159.             current.used[item.name] = current.used[item.name] - 1
  160.             added = added - 1
  161.           end
  162.           exit = true
  163.         end
  164.  
  165.         -- Check efficiency.
  166.         if new_efficiency >= laser_value.max_efficiency then
  167.           if last_efficiency < laser_value.max_efficiency then
  168.             -- We can keep this item, but we should exit immediately.
  169.             -- Leaving this empty block here for documentation.
  170.           else
  171.             -- We were over the max last time, and we are still over the max, so we should remove this item, then exit.
  172.             table.remove(current.list, #current.list)
  173.             current.used[item.name] = current.used[item.name] - 1
  174.             added = added - 1
  175.           end
  176.           exit = true
  177.         end
  178.  
  179.         -- Check purity.
  180.         -- We will need to check if the purity is below 1%.
  181.         if new_purity <= 1.05 then
  182.           -- Purity cannot go below 1% whatsoever, so we will need to remove this item, then exit.
  183.           table.remove(current.list, #current.list)
  184.           current.used[item.name] = current.used[item.name] - 1
  185.           added = added - 1
  186.           exit = true
  187.         end
  188.       else -- No items left of this type (or we can't use this item in the laser), so we will need to exit.
  189.         exit = true
  190.       end
  191.     until remaining <= 0 or exit
  192.  
  193.     if x then
  194.       print(item.name, added)
  195.     end
  196.  
  197.     -- If the new strength and efficiency are better than the best, we will need to update the best.
  198.     -- However, if the purity is below or equal to 1%, we will discard this attempt.
  199.     if new_purity > 1 and new_strength >= best_strength then
  200.       -- If the new strength and efficiency are better than the best, we will need to update the best.
  201.       best_strength = new_strength
  202.       best_efficiency = new_efficiency
  203.       best_purity = new_purity
  204.       best_list = deep_copy(current.list)
  205.     end
  206.  
  207.     local new_current = deep_copy(current)
  208.     new_current.strength = new_strength
  209.     new_current.efficiency = new_efficiency
  210.     new_current.purity = new_purity
  211.  
  212.     -- To prevent excess looping, we exit if nothing was added.
  213.     if added > 0 then
  214.       -- Now we will recurse, with the new values and list.
  215.       local best_recursed_list, best_recursed_strength, best_recursed_efficiency, best_recursed_purity = best_item_combo_optimized(new_current, item_list)
  216.  
  217.       -- Then we will need to check if the recursed values are better than the current best.
  218.       -- We will only worry about purity and strength here, since strength determines total RF storage, and purity needs to remain above 1.
  219.       -- We will check for purity above 1.05, to ensure it never goes below 1 due to any rounding errors.
  220.       if best_recursed_purity > 1.05 and best_recursed_strength > best_strength then
  221.         best_strength = best_recursed_strength
  222.         best_efficiency = best_recursed_efficiency
  223.         best_purity = best_recursed_purity
  224.         best_list = best_recursed_list
  225.       end
  226.  
  227.       -- Now we can remove all the items we added
  228.       for i = 1, added do
  229.         table.remove(current.list, #current.list)
  230.         current.used[item.name] = current.used[item.name] - 1
  231.       end
  232.     end
  233.   end
  234.  
  235.   return best_list, best_strength, best_efficiency, best_purity
  236. end
Advertisement
Comments
Add Comment
Please, Sign In to add comment
Advertisement