rerere284

voidresources.lua

Mar 3rd, 2018
87
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1.  
  2. local term = require("term")
  3. local serial = require("serialization")
  4. _G.recipes = _G.recipes or {}
  5.  
  6. local args = {...}
  7.  
  8.  
  9. local cmnd = args[1]
  10. table.remove(args,1)
  11. for i=1,#args do
  12.   if tonumber(args[i]) then
  13.     args[i] = tonumber(args[i])
  14.   end
  15. end
  16.  
  17.  
  18. --[[main actions:
  19.  
  20.  
  21.   get resources required for a craft/structure
  22.  
  23.   get crafting instructions for a craft
  24.  
  25.   get crafting instructions given you already have some resources
  26. ]]
  27.  
  28.  
  29. function addrecipe(name, outNum, ...)
  30.   local inp = {...}
  31.   local reqItems = {}
  32.   for i=1,#inp,2 do
  33.     table.insert(reqItems, { inp[i],inp[i+1] })
  34.   end
  35.   _G.recipes[name] = {outNum, reqItems}
  36.   print("added recipe for " .. name)
  37. end
  38.  
  39. function delrecipe(name)
  40.   _G.recipes[name] = nil
  41.   print("deleted recipe for " .. name)
  42. end
  43.  
  44. function addResources(...)
  45.   --add resource lists together
  46.   local inp = {...}
  47.   local final = {}
  48.   for i=1,#inp do--for each inputed list
  49.     for j=1,#inp[i] do--for each item
  50.       --collect a list 'final' of the amount of each resource totaled.
  51.       if final[ inp[i][j][1] ] then
  52.         final[ inp[i][j][1] ] = final[ inp[i][j][1] ] + inp[i][j][2]
  53.       else
  54.         final[ inp[i][j][1] ] = inp[i][j][2]
  55.       end
  56.     end
  57.   end
  58.   --convert 'final' to a normal format of a list of resources
  59.   local ret = {}
  60.   for k,v in pairs(final) do
  61.     table.insert(ret, {k, v})
  62.   end
  63.   return ret
  64. end
  65.  
  66. function addSetResources(reqA, ...)
  67.   --add resource lists to reqA
  68.   local inp = {...}
  69.   --make a map for reqA
  70.   local mp = {}
  71.   for i=1,#reqA do
  72.     mp[reqA[i][1]] = i
  73.   end
  74.   for i=1,#inp do--for each inputed list
  75.     for j=1,#inp[i] do--for each item
  76.       if mp[ inp[i][j][1] ] then--if we know where that resource is in reqA
  77.         --add to the amount of that resource
  78.         reqA[ mp[inp[i][j][1]] ][2] =
  79.           reqA[ mp[inp[i][j][1]] ][2] + inp[i][j][2]
  80.       else --add a new item to reqA
  81.         mp[ inp[i][j][1] ] = #reqA+1
  82.         reqA[#reqA+1] = {inp[i][j][1], inp[i][j][2]}
  83.       end
  84.     end
  85.   end
  86. end
  87.  
  88. function multResources(req, num)
  89.   --multiply resource amounts in req
  90.   for i=1,#req do
  91.     req[i][2] = req[i][2] * num
  92.   end
  93. end
  94.  
  95. function useSetResources(use, goal)
  96.   if not goal or #goal == 0 then return end
  97.   --make a map for use
  98.   local mpU = {}
  99.   for i=1,#use do
  100.     mpU[use[i][1]] = i
  101.   end
  102.   --make a map for goal
  103.   local mpG = {}
  104.   for i=1,#goal do
  105.     mpG[goal[i][1]] = i
  106.   end
  107.   --use the resources to craft goal
  108.   local remU, remG = {}, {}
  109.   for k,v in pairs(mpU) do
  110.     if mpG[k] then--for each resource in both
  111.       local nU, nG = use[mpU[k]][2], goal[mpG[k]][2]
  112.       if nG > nU then--if goal's resource > use's resource
  113.         --set goal's to goal's - use's
  114.         goal[mpG[k]][2] = goal[mpG[k]][2] - nU
  115.         table.insert(remU, k)
  116.         --table.remove(use, mpU[k])
  117.       elseif nG == nU then
  118.         --they cancel out equally
  119.         table.insert(remG, k)
  120.         --table.remove(goal, mpG[k])
  121.         table.insert(remU, k)
  122.         --table.remove(use, mpU[k])
  123.       else
  124.         --subtract that many from use
  125.         table.insert(remG, k)
  126.         --table.remove(goal, mpG[k])
  127.         use[mpU[k]][2] = use[mpU[k]][2] - nG
  128.       end
  129.     end
  130.   end
  131.   --remove spent stuff
  132.   for i=1,#remU do
  133.     for j=1,#use do
  134.       if use[j] and use[j][1] == remU[i] then
  135.         table.remove(use, j)
  136.       end
  137.     end
  138.   end
  139.   for i=1,#remG do
  140.     for j=1,#goal do
  141.       if goal[j] and goal[j][1] == remG[i] then
  142.         table.remove(goal, j)
  143.       end
  144.     end
  145.   end
  146. end
  147.  
  148. function calc(resource, amount, have)
  149.   amount = amount or 1
  150.   local requirements = {}
  151.   if _G.recipes[resource] then
  152.     local mat = _G.recipes[resource]
  153.     for i=1,#mat[2] do
  154.       local subReq = calc(mat[2][i][1], mat[2][i][2] * (amount/mat[1]), have)
  155.       useSetResources(subReq, have)
  156.       addSetResources(requirements, subReq)
  157.     end
  158.   else
  159.     local subReq = {{resource, amount}}
  160.     useSetResources(subReq, have)
  161.     addSetResources(requirements, subReq)
  162.   end
  163.   return requirements
  164. end
  165.  
  166. function oneCalc(resource, amount)
  167.   local requirements = {}
  168.   if _G.recipes[resource] then
  169.     local mat = _G.recipes[resource]
  170.     for i=1,#mat[2] do
  171.       local subReq = {mat[2][i][1], mat[2][i][2] * (amount/mat[1])}
  172.       addSetResources(requirements, subReq)
  173.     end
  174.   else
  175.     table.insert(requirements, {resource, amount})
  176.   end
  177.   return requirements
  178. end
  179.  
  180. local textY = 3
  181. function printLineWait(text)
  182.   print(text)
  183.   textY = textY + 1
  184.   local view = {term.getViewport()}
  185.   local h = view[2]
  186.   if textY > h then
  187.     term.read({ dobreak = true })
  188.     textY = 3
  189.   end
  190. end
  191.  
  192. function stackNumbers(num)
  193.   if type(num) ~= "number" then
  194.     if tonumber(num) then
  195.       num = tonumber(num)
  196.     else
  197.       print(num.." is not a number")
  198.     end
  199.   end
  200.   local ret = ""
  201.   if num > 64 then
  202.     for i=1,math.floor(num/64) do
  203.       ret = ret.."64".." "
  204.     end
  205.     ret = ret..(num%64)
  206.     if num%64 == 0 then
  207.       ret = string.sub(ret, 1, #ret-2)
  208.     end
  209.   else
  210.     ret = num
  211.   end
  212.   return ret
  213. end
  214.  
  215. function printResources(req)
  216.   if #req == 0 then
  217.     printLineWait("Resources: none.")
  218.     return
  219.   end
  220.   printLineWait("Resources:")
  221.   local enChar = ","
  222.   for i=1,#req do
  223.     if #req == 1 then enChar = ""
  224.     elseif #req == i then enChar = "." end
  225.     printLineWait(stackNumbers(req[i][2]) .. " " .. req[i][1]..enChar)
  226.   end
  227. end
  228.  
  229. function addSetCrafting(crfA, ...)
  230.   --add crafting lists to crfA
  231.   local inp = {...}
  232.   --make a map for crfA
  233.   local mp = {}
  234.   for i=1,#crfA do
  235.     mp[crfA[i][1]] = i
  236.   end
  237.   for i=1,#inp do--for each inputed list
  238.     for j=1,#inp[i] do--for each item
  239.       local ind = mp[ inp[i][j][1] ]
  240.       if ind then--if we know where that resource is in crfA
  241.         --add to the amount of that resource
  242.         crfA[ ind ][2] = crfA[ ind ][2] + inp[i][j][2]
  243.         if crfA[ ind ][3] < inp[i][j][3] then
  244.           --crfA gets highest tier for each material
  245.           crfA[ ind ][3] = inp[i][j][3]
  246.         end
  247.       else --add a new item to crfA
  248.         mp[ inp[i][j][1] ] = #crfA+1
  249.         crfA[#crfA+1] = {inp[i][j][1], inp[i][j][2], inp[i][j][3]}
  250.       end
  251.     end
  252.   end
  253. end
  254.  
  255. function calcCrafting(resource, amount, tier)
  256.   --[[
  257.     like calc(), but collects craftable items
  258.     items are given a tier
  259.     when merged, select higher tier
  260.   ]]
  261.   tier = tier or 1
  262.   local requirements = {}
  263.   if _G.recipes[resource] then--if this item has a recipe
  264.     --add itself to the requirements
  265.     addSetCrafting(requirements, {{resource, amount, tier}})
  266.     local mat = _G.recipes[resource]
  267.     for i=1,#mat[2] do--add its requirements to the requirements
  268.       local subReq = calcCrafting(mat[2][i][1],
  269.         mat[2][i][2] * (amount/mat[1]),
  270.         tier + 1)--later recipes have higher tier
  271.       addSetCrafting(requirements, subReq)
  272.     end
  273.   else--no recipe for this
  274.     requirements = {}
  275.   end
  276.   return requirements
  277. end
  278.  
  279. function printCrafting(crf)
  280.   --sort by largest tier first
  281.   table.sort(crf, function(a,b) return a[3] > b[3] end)
  282.   printLineWait("Crafting:")
  283.   --print crafting
  284.   local curTier = 0
  285.   for i=1,#crf do
  286.     if crf[i][3] ~= curTier then
  287.       curTier = crf[i][3]
  288.       printLineWait("Tier "..curTier..":")
  289.     end
  290.     printLineWait("craft "..stackNumbers(crf[i][2]).." "..crf[i][1])
  291.   end
  292. end
  293.  
  294. function listRecipes()
  295.   printLineWait("Recipes:")
  296.   for k,v in pairs(_G.recipes) do
  297.     printLineWait(k)
  298.     --printLineWait(v[1])--amount it crafts
  299.     --printLineWait(#v[2])--number of types of materials
  300.     --printResources(v[2])
  301.   end
  302. end
  303.  
  304. function recipeDetail(item)
  305.   if _G.recipes[item] then
  306.     printLineWait("Recipe: "..item)
  307.     printResources(_G.recipes[item][2])
  308.   else
  309.     printLineWait("I don't know about "..item..".")
  310.   end
  311. end
  312.  
  313. function stringSplit(inputstr, sep)
  314.   if sep == nil then
  315.     sep = "%s"
  316.   end
  317.   local t={}
  318.   for str in string.gmatch(inputstr..sep, "([^"..sep.."]*)"..sep) do
  319.     --print("\""..str.."\"")
  320.     table.insert(t,str)
  321.   end
  322.   return t
  323. end
  324.  
  325. function saveRecipes()
  326.   local file = io.open("craftingRecipes.txt","w")
  327.   file:write(serial.serialize(_G.recipes))
  328.   file:close()
  329. end
  330.  
  331. function loadRecipes()
  332.   local file = io.open("craftingRecipes.txt","r")
  333.   _G.recipes = serial.unserialize(file:read("*a"))
  334.   file:close()
  335. end
  336.  
  337.  
  338. cmdList = {}
  339. local function listCommands()
  340.   print("commands:")
  341.   for k,v in pairs(cmdList) do
  342.     print("  "..v)
  343.   end
  344. end
  345.  
  346. local commands = {
  347.   save = saveRecipes,
  348.   load = loadRecipes,
  349.   calculate = function(...)
  350.     local args = {...}
  351.     printResources( calc(args[1],args[2]) )
  352.     printCrafting( calcCrafting(args[1],args[2]) )
  353.   end,
  354.   fullcalculate = function(...)
  355.     local args = {...}
  356.     print("what do you have?")
  357.     local have = stringSplit(term.read(), ' ')
  358.     local haveItems = {}
  359.     for i=1,#have,2 do
  360.       table.insert(haveItems, { have[i],tonumber(have[i+1]) })
  361.     end
  362.     printResources(calc( args[1], args[2], haveItems ))
  363.     printCrafting(calcCrafting( args[1], args[2], haveItems ))
  364.   end,
  365.   setrecipe = addrecipe,
  366.   setstructure = function(name, ...)
  367.     addrecipe(name, 1, ...)
  368.   end,
  369.   delrecipe = delrecipe,
  370.   delstructure = delrecipie,
  371.   listrecipes = listRecipes,
  372.   recipedetail = recipeDetail,
  373.   commands = listCommands,
  374.   exit = function() end--dummy function, never called
  375. }
  376.  
  377. for k,v in pairs(commands) do--fill cmdList with list of commands
  378.   table.insert(cmdList, k)
  379. end
  380.  
  381. if cmnd and commands[cmnd] then--if a cmnd exists
  382.   --run it with args as inputs
  383.   commands[cmnd]( table.unpack(args) )
  384. else--no command, go into program loop
  385.   print("type \"commands\" for commands,")
  386.   print("type \"exit\" to exit.")
  387.  
  388.   local doExit = false
  389.   --while they haven't typed "exit", do this loop
  390.   while not doExit do
  391.     --take input of multiple items separated by spaces
  392.     local args = stringSplit(term.read(), "%s")
  393.     --print(#args)
  394.     if args[1] then--if they typed at least one thing
  395.       if args[1] == "exit" then break end
  396.       local cmnd = args[1]
  397.       table.remove(args,1)
  398.       if cmnd and commands[cmnd] then--if a cmnd exists
  399.         --run it with args as inputs
  400.         print("running "..cmnd)
  401.         commands[cmnd]( table.unpack(args) )
  402.       end
  403.     end
  404.   end
  405. end
RAW Paste Data