Advertisement
kssr3951

autoCraft (2018/05/20 unfinished version)

May 20th, 2018
186
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 18.30 KB | None | 0 0
  1. -- ===========================
  2. -- == autoCraft (2018/05/20 unfinished version)
  3. -- ===========================
  4. -- -----------------------
  5. -- config
  6. -- -----------------------
  7. DATA_FILE_NAME = "atCra.dat"
  8. -- -----------------------
  9. -- utility
  10. -- -----------------------
  11. local function fileReadAll(filePath)
  12.   local hFile = fs.open(filePath, "r")
  13.   if nil == hFile then
  14.     return ""
  15.   end
  16.   local txt = hFile.readAll()
  17.   hFile.close()
  18.   return txt
  19. end
  20. local function fileOverwrite(fileName, text)
  21.   local hFile = fs.open(fileName, "w")
  22.   hFile.writeLine(text)
  23.   hFile.close()
  24. end
  25. -- ---------------
  26. -- Logger
  27. -- ---------------
  28. -- do logging?
  29. DEBUG__DO_LOGGING           = true
  30. -- local log
  31. DEBUG__LOCAL_ENABLED        = true
  32. DEBUG__LOCAL_LOG_FILE_NAME  = "debug.log"
  33. -- remote log
  34. DEBUG__REMOTE_ENABLED       = false
  35. DEBUG__REMOTE_ADDR          = 20
  36. DEBUG__REMOTE_MODEM_DIR     = "right"
  37. function debug(txt)
  38.   if DEBUG__DO_LOGGING then
  39.     if DEBUG__LOCAL_ENABLED then
  40.       local hFile
  41.       if fs.exists(DEBUG__LOCAL_LOG_FILE_NAME) then
  42.         hFile = fs.open(DEBUG__LOCAL_LOG_FILE_NAME, "a");
  43.       else
  44.         hFile = fs.open(DEBUG__LOCAL_LOG_FILE_NAME, "w");
  45.       end
  46.       hFile.writeLine(txt);
  47.       hFile.close();
  48.     end
  49.     if DEBUG__REMOTE_ENABLED then
  50.       rednet.open(DEBUG__REMOTE_MODEM_DIR)
  51.       rednet.send(DEBUG__REMOTE_ADDR, txt)
  52.       rednet.close()
  53.     end
  54.   end
  55. end
  56. -- -----------------------
  57. -- application data
  58. -- -----------------------
  59. local ingredientsList
  60. -- -----------------------
  61. -- application
  62. -- -----------------------
  63. -- ---------------
  64. -- saveData
  65. -- ---------------
  66. local function saveData(the_db)
  67.   fileOverwrite(DATA_FILE_NAME, textutils.serialize(the_db))
  68. end
  69. -- ---------------
  70. -- loadData
  71. -- ---------------
  72. local function loadData()
  73.   return textutils.unserialize(fileReadAll(DATA_FILE_NAME))
  74. end
  75. -- ---------------
  76. -- makeKey
  77. -- ---------------
  78. function makeKey(name, damage)
  79.   return name .. "@" .. damage
  80. end
  81. -- ---------------
  82. -- check
  83. -- ---------------
  84. function check()
  85.   for _, v in pairs({ 4,8,12,13,14,15,16 }) do
  86.     if 0 < turtle.getItemCount(v) then
  87.       print("Don't use slot 4,8,12,13,14,15,16.")
  88.       return false
  89.     end
  90.   end
  91.   if false == turtle.craft(0) then
  92.     print("not craftable.")
  93.     return false
  94.   end
  95.   return true
  96. end
  97. -- ---------------
  98. -- doCraft
  99. -- ---------------
  100. function doCraft()
  101.   local bfr = { }
  102.   for i = 1, 16 do
  103.     bfr[i] = turtle.getItemDetail(i)
  104.   end
  105.   turtle.craft(1)
  106.   local aft = { }
  107.   for i = 1, 16 do
  108.     aft[i] = turtle.getItemDetail(i)
  109.   end
  110.   return bfr, aft
  111. end
  112. -- ---------------
  113. -- getDetail
  114. -- ---------------
  115. function getDetail(bfr, aft)
  116.   local crafted_idx = { }
  117.   local ingredients_idx = { }
  118.   for i = 1, 16 do
  119.     if nil ~= aft[i]
  120.       and (nil == bfr[i] or (aft[i].name ~= bfr[i].name or aft[i].damage ~= bfr[i].damage)) then
  121.       table.insert(crafted_idx, i)
  122.     end
  123.     if nil ~= bfr[i] then
  124.       table.insert(ingredients_idx, i)
  125.     end
  126.   end
  127.   -- ------------------------------------
  128.   local crafted = { }
  129.   for _, idx in ipairs(crafted_idx) do
  130.     local key = makeKey(aft[idx].name, aft[idx].damage)
  131.     if nil == crafted[key] then
  132.       crafted[key] = { }
  133.       crafted[key].name   = aft[idx].name
  134.       crafted[key].damage = aft[idx].damage
  135.       crafted[key].count  = 0
  136.     end
  137.     crafted[key].count = crafted[key].count + aft[idx].count
  138.   end
  139.   -- ------------------------------------
  140.   local ingredients = { }
  141.   local symbols = { "A","B","C","D","E","F","G","H","I" }
  142.   local symbol_index = 0
  143.   local count
  144.   for _, idx in ipairs(ingredients_idx) do
  145.     local key = makeKey(bfr[idx].name, bfr[idx].damage)
  146.     if nil == ingredients[key] then
  147.       ingredients[key] = { }
  148.       ingredients[key].name   = bfr[idx].name
  149.       ingredients[key].damage = bfr[idx].damage
  150.       ingredients[key].count  = 0
  151.       symbol_index = symbol_index + 1
  152.       ingredients[key].symbol = symbols[symbol_index]
  153.     end
  154.     if nil == aft[idx] then
  155.       count = bfr[idx].count
  156.     elseif aft[idx].name ~= bfr[idx].name or aft[idx].damage ~= bfr[idx].damage then
  157.       count = bfr[idx].count
  158.     elseif aft[idx].name == bfr[idx].name and aft[idx].damage == bfr[idx].damage then
  159.       count = bfr[idx].count - aft[idx].count
  160.     end
  161.     ingredients[key].count = ingredients[key].count + count
  162.     bfr[idx].symbol = ingredients[key].symbol
  163.   end
  164.   return ingredients, crafted
  165. end
  166. -- ---------------
  167. -- horizontalCheck
  168. -- ---------------
  169. function horizontalCheck(recipe, y)
  170.   for x = 1, 3 do
  171.     if "-" ~= recipe[y][x] then
  172.       return true
  173.     end
  174.   end
  175.   return false
  176. end
  177. -- ---------------
  178. -- verticalCheck
  179. -- ---------------
  180. function verticalCheck(recipe, x)
  181.   for y = 1, 3 do
  182.     if "-" ~= recipe[y][x] then
  183.       return true
  184.     end
  185.   end
  186.   return false
  187. end
  188. -- ---------------
  189. -- getRecipe
  190. -- ---------------
  191. local function getRecipe(bfr)
  192.   local recipe = { }
  193.   for i = 0, 2 do
  194.     local line = { }
  195.     for j = 0, 2 do
  196.       local idx = i * 4 + j + 1
  197.       if nil ~= bfr[idx] then
  198.         line[j + 1] = bfr[idx].symbol
  199.       else
  200.         line[j + 1] = "-"
  201.       end
  202.     end
  203.     recipe[i+1] = line
  204.   end
  205.   local crop_top = 1
  206.   local crop_bottom = 3
  207.   local crop_left = 1
  208.   local crop_right = 3
  209.   for x = 1, 3 do
  210.     if verticalCheck(recipe, x) then
  211.       crop_left = x
  212.       break
  213.     end
  214.   end
  215.   for x = 3, 1, -1 do
  216.     if verticalCheck(recipe, x) then
  217.       crop_right = x
  218.       break
  219.     end
  220.   end
  221.   for y = 1, 3 do
  222.     if horizontalCheck(recipe, y) then
  223.       crop_top = y
  224.       break
  225.     end
  226.   end
  227.   for y = 3, 1, -1 do
  228.     if horizontalCheck(recipe, y) then
  229.       crop_bottom = y
  230.       break
  231.     end
  232.   end
  233.   local recipe_slim = { }
  234.   for y = crop_top, crop_bottom do
  235.     i = y - crop_top + 1
  236.     local line = { }
  237.     for x = crop_left, crop_right do
  238.       j = x - crop_left + 1
  239.       line[j] = recipe[y][x]
  240.     end
  241.     recipe_slim[i] = line
  242.   end
  243.   return recipe, recipe_slim
  244. end
  245. -- ---------------
  246. -- regist detail
  247. -- ---------------
  248. local function registDetail(the_db, ingredients_or_crafted, mark)
  249.   local new_count = 0
  250.   for k, v in pairs(ingredients_or_crafted) do
  251.     local dat = the_db[k]
  252.     print("[" .. mark .. "]" .. k)
  253.     if nil == dat then
  254.       term.write("Input alias (or blank) > ")
  255.       line = read()
  256.       if "" ~= line then
  257.         alias = line
  258.       else
  259.         alias = "(no alias)"
  260.         print("no alias")
  261.       end
  262.       the_db[k] = {}
  263.       the_db[k].name   = v.name
  264.       the_db[k].damage = v.damage
  265.       the_db[k].alias  = alias
  266.       new_count = new_count + 1
  267.     else
  268.       print("alias = [" .. dat.alias .. "]")
  269.     end
  270.   end
  271.   return new_count
  272. end
  273. -- ---------------
  274. -- compareIngredients()
  275. -- ---------------
  276. local function compareIngredients(ingredients_A, ingredients_B)
  277.   for key_A, dat_A in pairs(ingredients_A) do
  278.     local dat_B = ingredients_B[key_A]
  279.     if nil == dat_B then
  280.       return false
  281.     end
  282.     if dat_A.count ~= dat_B.count then
  283.       return false
  284.     end
  285.   end
  286.   return true
  287. end
  288. -- ---------------
  289. -- copyIngredients
  290. -- ---------------
  291. local function copyIngredients(ingredients)
  292.   local ret = { }
  293.   for k, v in pairs(ingredients) do
  294.     local dat = { }
  295.     dat.name = v.name
  296.     dat.damage = v.damage
  297.     dat.symbol = v.symbol
  298.     dat.count = v.count
  299.     ret[k] = dat
  300.   end
  301.   return ret
  302. end
  303. -- ---------------
  304. -- copyRecipe
  305. -- ---------------
  306. local function copyRecipe(recipe)
  307.   local ret = { }
  308.   for i, v in ipairs(recipe) do
  309.     local line = { }
  310.     for j, vv in ipairs(v) do
  311.       table.insert(line, vv)
  312.     end
  313.     table.insert(ret, line)
  314.   end
  315.   return ret
  316. end
  317. -- ---------------
  318. -- makeRecipeData
  319. -- ---------------
  320. local function makeCraftData(registered_recipes, new_ingredients, new_recipe_slim)
  321.   local is_new_uniq_recipe = true
  322.   for _, registerd_r in pairs(registered_recipes) do
  323.     if "craft" == registerd_r.type then
  324.       local rslt_A = compareIngredients(registerd_r.ingredients, new_ingredients)
  325.       local rslt_B = compareIngredients(new_ingredients, registerd_r.ingredients)
  326.       if true == (rslt_A and rslt_B) then
  327.         is_new_uniq_recipe = false
  328.         break
  329.       end
  330.     end
  331.   end
  332.   if true == is_new_uniq_recipe then
  333.     local data = {}
  334.     data.type = "craft"
  335.     --[x] data.ingredients = new_ingredients
  336.     --[x] data.recipe_slim = new_recipe_slim
  337.     --[x] data.ingredients = { unpack(new_ingredients) }
  338.     --[x] data.recipe_slim = { unpack(new_recipe_slim) }
  339.     data.ingredients = copyIngredients(new_ingredients)
  340.     data.recipe_slim = copyRecipe(new_recipe_slim)
  341.     return data
  342.   else
  343.     return nil
  344.   end
  345. end
  346. -- ---------------
  347. -- craft
  348. -- ---------------
  349. local function craft(the_db)
  350.   debug("craft -----------------------------")
  351.   if false == check() then
  352.     return
  353.   end
  354.   local bfr, aft = doCraft()
  355.   local ingredients, crafted = getDetail(bfr, aft)
  356.   local recipe, recipe_slim = getRecipe(bfr)
  357.   debug("ingredients = " .. textutils.serialize(ingredients))
  358.   debug("crafted = " .. textutils.serialize(crafted))
  359.   debug("recipe = " .. textutils.serialize(recipe))
  360.   debug("recipe_slim = " .. textutils.serialize(recipe_slim))
  361.   registDetail(the_db, ingredients, "I")
  362.   registDetail(the_db, crafted, "C")
  363.   local data
  364.   for k, v in pairs(crafted) do
  365.     local re = the_db[k].recipes
  366.     if nil == re then
  367.       the_db[k].recipes = { }
  368.     end
  369.     data = makeCraftData(the_db[k].recipes, ingredients, recipe_slim)
  370.     if nil ~= data then
  371.       table.insert(the_db[k].recipes, data)
  372.     end
  373.   end
  374.   saveData(the_db)
  375. end
  376. -- ---------------
  377. -- promptLearn
  378. -- ---------------
  379. local function promptLearn(the_db)
  380.   while true do
  381.     term.clear()
  382.     term.setCursorPos(1, 1)
  383.     print([[autoCraft ~ [learn craft]
  384. 1 : [c]raft
  385. 2 : smelt
  386. 3 : dig
  387. 4 : bucket
  388. 5 : spill
  389. b : back to main menu
  390. x : e[x]it]])
  391.     term.write("input and hit enter key.>")
  392.     input = read()
  393.     if "1" == input or "c" == input then
  394.       craft(the_db)
  395.     elseif "b" == input then
  396.       return true
  397.     elseif "x" == input then
  398.       return false
  399.     else
  400.       print("wrong input.")
  401.     end
  402.   end
  403. end
  404. -- =================================
  405. -- ingredients
  406. -- =================================
  407. local detailCountList = { }
  408. local currentReadyIsPrimaryChest = true
  409. local primaryChest = { }
  410. primaryChest.suckFunc = turtle.suck
  411. primaryChest.dropFunc = turtle.drop
  412. local secondaryChest = { }
  413. secondaryChest.suckFunc = turtle.suckDown
  414. secondaryChest.dropFunc = turtle.dropDown
  415. -- ---------------
  416. -- existsBlankSlot
  417. -- ---------------
  418. local function existsBlankSlot()
  419.   for i = 1, 16 do
  420.     if 0 == turtle.getItemCount(i) then
  421.       return true
  422.     end
  423.   end
  424.   return false
  425. end
  426. -- ---------------
  427. -- clearTurtleSlot
  428. -- ---------------
  429. local function clearTurtleSlot(toChest, detailCountList)
  430.   if nil == detailCountList then
  431.     detailCountList = { }
  432.   end
  433.   for i = 1, 16 do
  434.     local beforeCount = turtle.getItemCount(i)
  435.     if 0 < beforeCount then
  436.       local det = turtle.getItemDetail(i)
  437.       local key = makeKey(det.name, det.damage)
  438.       if nil == detailCountList[key] then
  439.         detailCountList[key] = 0
  440.       end
  441.       turtle.select(i)
  442.       local rslt = toChest.dropFunc()
  443.       local afterCount = turtle.getItemCount(i)
  444.       detailCountList[key] = detailCountList[key] + beforeCount - afterCount
  445.       if false == rslt then
  446.         turtle.select(1)
  447.         return false
  448.       end
  449.     end
  450.   end
  451.   turtle.select(1)
  452.   return true
  453. end
  454. -- ---------------
  455. -- doMoveItems
  456. -- ---------------
  457. local function doMoveItems(fromChest, toChest, pickupList)
  458.   local detailCountList = { }
  459.   while true do
  460.     local rslt = fromChest.suckFunc()
  461.     if false == rslt then
  462.       if existsBlankSlot() then
  463.         break
  464.       else
  465.         rslt = clearTurtleSlot(toChest, detailCountList)
  466.         if false == rslt then
  467.           return false, detailCountList
  468.         end
  469.       end
  470.     end
  471.   end
  472.   local rslt = clearTurtleSlot(toChest, detailCountList)
  473.   if false == rslt then
  474.     return false, detailCountList
  475.   else
  476.     return true, detailCountList
  477.   end
  478. end
  479. -- ---------------
  480. -- moveItems
  481. -- ---------------
  482. local function moveItems(fromChest, toChest)
  483.   return doMoveItems(fromChest, toChest, nil)
  484. end
  485. -- ---------------
  486. -- pickupItems
  487. -- ---------------
  488. local function pickupItems(fromChest, toChest, pickupList)
  489.   return doMoveItems(fromChest, toChest, pickupList)
  490. end
  491. -- ---------------
  492. -- updateIngredientsInfo
  493. -- ---------------
  494. local function updateIngredientsInfo()
  495.   local rslt = clearTurtleSlot(secondaryChest)
  496.   if false == rslt then
  497.     print("too many items.(1)")
  498.   end
  499.   rslt = moveItems(primaryChest, secondaryChest)
  500.   if false == rslt then
  501.     print("too many items.(2)")
  502.   end
  503.   rslt, list = moveItems(secondaryChest, primaryChest)
  504.   if false == rslt then
  505.     print("too many items.(3)")
  506.   end
  507.   return list
  508. end
  509. -- ---------------
  510. -- makeList
  511. -- ---------------
  512. local function makeList(associativerray)
  513.   local list = { }
  514.   for k, v in pairs(associativerray) do
  515.     local dat = { }
  516.     dat.key = k
  517.     dat.value = v
  518.     table.insert(list, dat)
  519.   end
  520.   return list
  521. end
  522. -- ---------------
  523. -- getAlias
  524. -- ---------------
  525. local function getAlias(the_db, key)
  526.   local dat = the_db[key]
  527.   if nil == dat then
  528.     return key
  529.   end
  530.   if nil == dat.alias then
  531.     return key
  532.   end
  533.   return dat.alias
  534. end
  535. -- ---------------
  536. -- promptListIngredients
  537. -- ---------------
  538. local function promptListIngredients(the_db)
  539.   local currentPage = 1
  540.   local w, h = term.getSize()
  541.   local pageSize = h - 5
  542.   local ingreList = makeList(ingredientsList)
  543.   while true do
  544.     term.clear()
  545.     term.setCursorPos(1, 1)
  546.     local pageTotal = math.ceil(#ingreList / pageSize)
  547.     print("[list ingredients] page " .. currentPage .. " of " .. pageTotal)
  548.     local firstItem = (currentPage - 1) * pageSize + 1
  549.     local lastItem = math.min(firstItem + pageSize - 1, #ingreList)
  550.     for i = firstItem, lastItem do
  551.       local dat = ingreList[i]
  552.       local alias = getAlias(the_db, dat.key)
  553.       print("[" .. i .. "] / " .. alias .. " / " .. dat.value)
  554.     end
  555.     print([[u : update list
  556. [n]ext / [p]revious page
  557. [b]ack to main menu / e[x]it]])
  558.     term.write("input number and hit enter key.>")
  559.     local input = read()
  560.     if "u" == input then
  561.       ingredientsList = updateIngredientsInfo()
  562.       ingreList = makeList(ingredientsList)
  563.     elseif "n" == input then
  564.       currentPage = math.min(currentPage + 1, pageTotal)
  565.     elseif "p" == input then
  566.       currentPage = math.max(currentPage - 1, 1)
  567.     elseif "b" == input then
  568.       return true
  569.     elseif "x" == input then
  570.       return false
  571.     else
  572.       print("wrong input.")
  573.     end
  574.   end
  575. end
  576. -- =================================
  577. -- autoCraft
  578. -- =================================
  579. -- ---------------
  580. -- makeCraftList
  581. -- ---------------
  582. local function makeCraftList(the_db)
  583.   local list = { }
  584.   for key, val in pairs(the_db) do
  585.     if nil ~= val.recipes then
  586.       local dat = { }
  587.       dat.key = key
  588.       dat.alias = val.alias
  589.       table.insert(list, dat)
  590.     end
  591.   end
  592.   return list
  593. end
  594. -- ---------------
  595. -- promptAutoCraft
  596. -- ---------------
  597. local function promptAutoCraft(the_db)
  598.   local craftList = makeCraftList(the_db)
  599.   local currentPage = 1
  600.   local w, h = term.getSize()
  601.   local pageSize = h - 5
  602.   while true do
  603.     term.clear()
  604.     term.setCursorPos(1, 1)
  605.     local pageTotal = math.ceil(#craftList / pageSize)
  606.     local firstItem = (currentPage - 1) * pageSize + 1
  607.     local lastItem = math.min(firstItem + pageSize - 1, #craftList)
  608.     print("[auto craft] page " .. currentPage .. " of " .. pageTotal)
  609.     for i = firstItem, lastItem do
  610.       local dat = craftList[i]
  611.       print("[" .. i .. "] " .. dat.alias)
  612.     end
  613.     print([[[n]ext / [p]revious page
  614. [b]ack to main menu / e[x]it]])
  615.     term.write("input number and hit enter key.>")
  616.     local input = read()
  617.     if "n" == input then
  618.       currentPage = math.min(currentPage + 1, pageTotal)
  619.     elseif "p" == input then
  620.       currentPage = math.max(currentPage - 1, 1)
  621.     elseif "b" == input then
  622.       return true
  623.     elseif "x" == input then
  624.       return false
  625.     else
  626.       print("wrong input.")
  627.     end
  628.   end
  629. end
  630.  
  631. -- =================================
  632. -- main menu
  633. -- =================================
  634. -- ---------------
  635. -- promptMainMenu
  636. -- ---------------
  637. local function promptMainMenu(the_db, ingredientsList)
  638.   while true do
  639.     term.clear()
  640.     term.setCursorPos(1, 1)
  641.     print([[autoCraft ~ [main menu]
  642. 1 : auto [c]raft
  643. 2 : list [i]ngredients
  644. 3 : [l]earn
  645. 4 : [e]dit data
  646. x : e[x]it]])
  647.     term.write("input number and hit enter key.>")
  648.     input = read()
  649.     if "1" == input or "c" == input then
  650.       if false == promptAutoCraft(the_db) then
  651.         return false
  652.       end
  653.     elseif "2" == input or "i" == input then
  654.       if false == promptListIngredients(the_db) then
  655.         return false
  656.       end
  657.     elseif "3" == input or "l" == input then
  658.       if false == promptLearn(the_db) then
  659.         return false
  660.       end
  661.     elseif "x" == input then
  662.       return
  663.     else
  664.       print("wrong input.")
  665.     end
  666.   end
  667. end
  668. -- ---------------
  669. -- listItems
  670. -- ---------------
  671. local function listItems()
  672.   while true do
  673.     print([[autoCraft ~ [list items]
  674.     n : [n]ext page
  675.     p : [p]revious page
  676.     b : [b]ack to main menu
  677.     x : e[x]it]])
  678.     term.write("input number and hit enter key.>")
  679.     input = read()
  680.     if nil ~= string.find("/u/b/x/", "/" .. input .. "/") then
  681.       return input
  682.     else
  683.       print("wrong input.")
  684.     end
  685.   end
  686. end
  687. -- ---------------
  688. -- isChest
  689. -- ---------------
  690. local function isChest(inspectFunction)
  691.   rslt, data = inspectFunction()
  692.   if nil == data then
  693.     return false
  694.   end
  695.   if "minecraft:chest" == data.name or "minecraft:trapped_chest" == data.name then
  696.     return true
  697.   else
  698.     return false
  699.   end
  700. end
  701. -- =======================================================
  702. -- main
  703. -- =======================================================
  704. --if false == (isChest(turtle.inspect) and isChest(turtle.inspectDown)) then
  705. --  error("place chests (front and bottom).")
  706. --end
  707. the_db = loadData()
  708. if nil == the_db then
  709.   the_db = { }
  710. end
  711. ingredientsList = { }
  712. promptMainMenu(the_db, ingredientsList)
  713. saveData(the_db)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement