daoek

SmartQuary V2

Jul 24th, 2025
610
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 16.82 KB | Software | 0 0
  1. local function TurtleState()
  2.     local x, y, z = 0, 0, 0
  3.     local dir = "n"
  4.     local path = "/data/turtleState.json"
  5.  
  6.     local function load()
  7.         if not fs.exists("/data") then
  8.             fs.makeDir("/data")
  9.         end
  10.  
  11.         if fs.exists(path) then
  12.             local file = fs.open(path, "r")
  13.             local data = textutils.unserializeJSON(file.readAll())
  14.             file.close()
  15.             x = data.x or 0
  16.             y = data.y or 0
  17.             z = data.z or 0
  18.             dir = data.dir or "n"
  19.         end
  20.     end
  21.  
  22.     local function save(newX, newY, newZ, newDir)
  23.         x = newX or x
  24.         y = newY or y
  25.         z = newZ or z
  26.         dir = newDir or dir
  27.  
  28.         local file = fs.open(path, "w")
  29.         file.write(textutils.serializeJSON({
  30.             x = x,
  31.             y = y,
  32.             z = z,
  33.             dir = dir
  34.         }))
  35.         file.close()
  36.     end
  37.  
  38.     local function get()
  39.         return x, y, z, dir
  40.     end
  41.  
  42.     load()
  43.  
  44.     return {
  45.         load = load,
  46.         save = save,
  47.         get = get
  48.     }
  49. end
  50.  
  51. dirIndex = { n = 0, e = 1, s = 2, w = 3 }
  52. dirNames = { "n", "e", "s", "w" }
  53.  
  54. turtleState = TurtleState()
  55. x, y, z, dir = turtleState.get()
  56.  
  57. local function refuelAll(limit)
  58.     if turtle.getFuelLevel() < limit then
  59.         for i = 1, 16, 1 do
  60.             turtle.select(i)
  61.             turtle.refuel()
  62.         end
  63.     end
  64. end
  65.  
  66. local function resetState()
  67.     x, y, z, dir = 0, 0, 0, "n"
  68.     turtleState.save(x, y, z, dir)
  69.     print("Turtle state reset to 0, 0, 0, facing north.")
  70. end
  71.  
  72. local function isOre(dir)
  73.     local inspectFn
  74.  
  75.     if dir == "" or dir == "forward" then
  76.         inspectFn = turtle.inspect
  77.     elseif dir == "up" then
  78.         inspectFn = turtle.inspectUp
  79.     elseif dir == "down" then
  80.         inspectFn = turtle.inspectDown
  81.     else
  82.         error("Invalid direction: expected '', 'forward', 'up', or 'down'", 2)
  83.     end
  84.  
  85.     local success, data = inspectFn()
  86.     if not success or not data.name then
  87.         return false
  88.     end
  89.  
  90.     local name = data.name
  91.  
  92.     local whiteList = {
  93.         "ore", "resources", "basis_block_core", "blockmetal"
  94.     }
  95.  
  96.     for _, good in ipairs(whiteList) do
  97.         if name:find(good) then
  98.             return true
  99.         end
  100.     end
  101.  
  102.     return false
  103. end
  104.  
  105. local function isInventoryFull()
  106.     for i = 1, 16 do
  107.         if turtle.getItemCount(i) == 0 then
  108.             return false
  109.         end
  110.     end
  111.     return true
  112. end
  113.  
  114. local function dumpInventory(dir)
  115.     local dropFn
  116.  
  117.     if dir == "" or dir == "forward" then
  118.         dropFn = turtle.drop
  119.     elseif dir == "up" then
  120.         dropFn = turtle.dropUp
  121.     elseif dir == "down" then
  122.         dropFn = turtle.dropDown
  123.     else
  124.         error("Invalid direction: must be '', 'up', or 'down'", 2)
  125.     end
  126.  
  127.     for i = 1, 16 do
  128.         turtle.select(i)
  129.         dropFn()
  130.     end
  131.  
  132.     turtle.select(1) -- Restore selection
  133. end
  134.  
  135. local function SmartDig(dir)
  136.  
  137.     local digFunction, inspectFunction, attempts
  138.  
  139.     if dir == "" or dir == "forward" then
  140.         digFunction = turtle.dig
  141.         inspectFunction = turtle.inspect
  142.     elseif dir == "up" then
  143.         digFunction = turtle.digUp
  144.         inspectFunction = turtle.inspectUp
  145.     elseif dir == "down" then
  146.         digFunction = turtle.digDown
  147.         inspectFunction = turtle.inspectDown
  148.     else
  149.         error("Invalid direction: expected '', 'forward', 'up', or 'down'", 2)
  150.     end
  151.  
  152.     attempts = 2
  153.  
  154.     local function DigFallingEntity()
  155.         while digFunction() do
  156.             os.sleep(0.5)
  157.         end
  158.     end
  159.  
  160.     local function DigNormal()
  161.         digFunction()
  162.     end
  163.  
  164.     while attempts > 0 do
  165.         local success, data = inspectFunction()
  166.         if not success then
  167.             return
  168.         end
  169.  
  170.         local name = data.name or ""
  171.         if name:find("gravel") or name:find("sand") then
  172.             DigFallingEntity()
  173.         elseif name:find("turtle") or name:find("lava") or name:find("water") or name:find("bedrock") then
  174.             return
  175.         else  
  176.             DigNormal()
  177.         end
  178.  
  179.         -- Check again in case something fell
  180.         local again, newData = inspectFunction()
  181.  
  182.         if again then
  183.             attempts = attempts - 1
  184.         else
  185.             return
  186.         end
  187.     end
  188. end
  189.  
  190. local function forward()
  191.     SmartDig("forward")
  192.  
  193.     if turtle.forward() then
  194.         if dir == "n" then
  195.             z = z - 1
  196.         elseif dir == "s" then
  197.             z = z + 1
  198.         elseif dir == "e" then
  199.             x = x + 1
  200.         elseif dir == "w" then
  201.             x = x - 1
  202.         end
  203.  
  204.         turtleState.save(x, y, z, dir)
  205.         return true
  206.     end
  207.  
  208.     return false
  209. end
  210.  
  211. local function back()
  212.     if turtle.back() then
  213.         if dir == "n" then
  214.             z = z + 1
  215.         elseif dir == "s" then
  216.             z = z - 1
  217.         elseif dir == "e" then
  218.             x = x - 1
  219.         elseif dir == "w" then
  220.             x = x + 1
  221.         end
  222.  
  223.         turtleState.save(x, y, z, dir)
  224.         return true
  225.     end
  226.  
  227.     return false
  228. end
  229.  
  230. local function up()
  231.     SmartDig("up")
  232.     if turtle.up() then
  233.         y = y + 1
  234.         turtleState.save(x, y, z, dir)
  235.         return true
  236.     end
  237.  
  238.     return false
  239. end
  240.  
  241. local function down()
  242.  
  243.     SmartDig("down")
  244.  
  245.     if turtle.down() then
  246.         y = y - 1
  247.         turtleState.save(x, y, z, dir)
  248.         return true
  249.     end
  250.  
  251.     return false
  252. end
  253.  
  254. local function turnLeft()
  255.     turtle.turnLeft()
  256.     local idx = (dirIndex[dir] - 1) % 4
  257.     dir = dirNames[idx + 1]
  258.     turtleState.save(x, y, z, dir)
  259. end
  260.  
  261. local function turnRight()
  262.     turtle.turnRight()
  263.     local idx = (dirIndex[dir] + 1) % 4
  264.     dir = dirNames[idx + 1]
  265.     turtleState.save(x, y, z, dir)
  266. end
  267.  
  268. local function turnToDirection(desiredDir)
  269.     if dir == desiredDir then return end
  270.  
  271.     local current = dirIndex[dir]
  272.     local target = dirIndex[desiredDir]
  273.     local diff = (target - current) % 4
  274.  
  275.     if diff == 1 then
  276.         turnRight()
  277.     elseif diff == 2 then
  278.         turnRight()
  279.         turnRight()
  280.     elseif diff == 3 then
  281.         turnLeft()
  282.     end
  283. end
  284.  
  285. local function moveToLocation(desiredX, desiredY, desiredZ)
  286.     -- Move vertically first (Y axis)
  287.     while y < desiredY do
  288.         if not up() then return false end
  289.     end
  290.     while y > desiredY do
  291.         if not down() then return false end
  292.     end
  293.  
  294.     -- Move along X axis
  295.     if desiredX > x then
  296.         turnToDirection("e")
  297.         while x < desiredX do
  298.             if not forward() then return false end
  299.         end
  300.     elseif desiredX < x then
  301.         turnToDirection("w")
  302.         while x > desiredX do
  303.             if not forward() then return false end
  304.         end
  305.     end
  306.  
  307.     -- Move along Z axis
  308.     if desiredZ > z then
  309.         turnToDirection("s")
  310.         while z < desiredZ do
  311.             if not forward() then return false end
  312.         end
  313.     elseif desiredZ < z then
  314.         turnToDirection("n")
  315.         while z > desiredZ do
  316.             if not forward() then return false end
  317.         end
  318.     end
  319.  
  320.     return true
  321. end
  322.  
  323. local function removeDataFromArray(array, data)
  324.     local foundIndex = -1
  325.    
  326.     for i, v in ipairs(array) do
  327.         if data == v then
  328.             foundIndex = i
  329.         end
  330.     end
  331.  
  332.     if foundIndex ~= -1 then
  333.         table.remove(array, foundIndex)
  334.     end
  335.  
  336. end
  337.  
  338. local function doesArrayContain(array, data)
  339.     for i, v in ipairs(array) do
  340.         if data == v then
  341.             return true
  342.         end
  343.     end
  344.  
  345.     return false
  346. end
  347.  
  348. local function createPositionKey(x, y, z)
  349.     return string.format("%d,%d,%d", x, y, z)
  350. end
  351.  
  352. local function getPositionKeyWithDirection(relativeDir)
  353.     local dx, dy, dz = 0, 0, 0
  354.  
  355.     if relativeDir == "up" then
  356.         dy = 1
  357.     elseif relativeDir == "down" then
  358.         dy = -1
  359.     elseif relativeDir == "forward" then
  360.         if dir == "n" then dz = -1
  361.         elseif dir == "s" then dz = 1
  362.         elseif dir == "e" then dx = 1
  363.         elseif dir == "w" then dx = -1 end
  364.     elseif relativeDir == "back" then
  365.         if dir == "n" then dz = 1
  366.         elseif dir == "s" then dz = -1
  367.         elseif dir == "e" then dx = -1
  368.         elseif dir == "w" then dx = 1 end
  369.     elseif relativeDir == "left" then
  370.         if dir == "n" then dx = -1
  371.         elseif dir == "s" then dx = 1
  372.         elseif dir == "e" then dz = -1
  373.         elseif dir == "w" then dz = 1 end
  374.     elseif relativeDir == "right" then
  375.         if dir == "n" then dx = 1
  376.         elseif dir == "s" then dx = -1
  377.         elseif dir == "e" then dz = 1
  378.         elseif dir == "w" then dz = -1 end
  379.     else
  380.         error("Invalid direction for getPositionKeyWithDirection: " .. tostring(relativeDir))
  381.     end
  382.  
  383.     return createPositionKey(x + dx, y + dy, z + dz)
  384. end
  385.  
  386. local function smartMineOreVeinWorker(noOreDetected, oreDetected, backTrackLog)
  387.  
  388.     local targetPos = getPositionKeyWithDirection("forward")
  389.     if not doesArrayContain(noOreDetected, targetPos) and not doesArrayContain(oreDetected, targetPos) then
  390.         if isOre("forward") then
  391.             table.insert(oreDetected, targetPos)
  392.         else
  393.             table.insert(noOreDetected, targetPos)
  394.         end
  395.     end
  396.  
  397.     targetPos = getPositionKeyWithDirection("down")
  398.     if not doesArrayContain(noOreDetected, targetPos) and not doesArrayContain(oreDetected, targetPos) then
  399.         if isOre("down") then
  400.             table.insert(oreDetected, targetPos)
  401.         else
  402.             table.insert(noOreDetected, targetPos)
  403.         end
  404.     end
  405.  
  406.     targetPos = getPositionKeyWithDirection("up")
  407.     if not doesArrayContain(noOreDetected, targetPos) and not doesArrayContain(oreDetected, targetPos) then
  408.         if isOre("up") then
  409.             table.insert(oreDetected, targetPos)
  410.         else
  411.             table.insert(noOreDetected, targetPos)
  412.         end
  413.     end
  414.  
  415.     targetPos = getPositionKeyWithDirection("right")
  416.     if not doesArrayContain(noOreDetected, targetPos) and not doesArrayContain(oreDetected, targetPos) then
  417.     turnRight()
  418.  
  419.         if isOre("forward") then
  420.             table.insert(oreDetected, targetPos)
  421.         else
  422.             table.insert(noOreDetected, targetPos)
  423.         end
  424.  
  425.     turnLeft()
  426.     end
  427.  
  428.     targetPos = getPositionKeyWithDirection("left")
  429.     if not doesArrayContain(noOreDetected, targetPos) and not doesArrayContain(oreDetected, targetPos) then
  430.         turnLeft()
  431.        
  432.         if isOre("forward") then
  433.             table.insert(oreDetected, targetPos)
  434.         else
  435.             table.insert(noOreDetected, targetPos)
  436.         end
  437.  
  438.         turnRight()
  439.     end
  440.  
  441.  
  442.  
  443.  
  444.     -- Mine down if there is ore
  445.     targetPos = getPositionKeyWithDirection("down")
  446.     if doesArrayContain(oreDetected, targetPos) then
  447.  
  448.         if down() then
  449.             table.insert(backTrackLog, "up")
  450.  
  451.             --remove ore and add to no ore list
  452.             removeDataFromArray(oreDetected,targetPos)
  453.             table.insert(noOreDetected, targetPos)
  454.  
  455.         else
  456.             return false
  457.         end
  458.         smartMineOreVeinWorker(noOreDetected,oreDetected,backTrackLog)
  459.     end
  460.  
  461.     -- Mine left if there is ore
  462.     targetPos = getPositionKeyWithDirection("left")
  463.     if doesArrayContain(oreDetected, targetPos) then
  464.         turnLeft()
  465.         table.insert(backTrackLog, "turnright")
  466.  
  467.         if forward() then
  468.             table.insert(backTrackLog, "back")
  469.  
  470.             --remove ore and add to no ore list
  471.             removeDataFromArray(oreDetected,targetPos)
  472.             table.insert(noOreDetected, targetPos)
  473.  
  474.         else
  475.             return false
  476.         end
  477.         smartMineOreVeinWorker(noOreDetected,oreDetected,backTrackLog)
  478.     end
  479.  
  480.     -- Mine forward if there is ore
  481.     targetPos = getPositionKeyWithDirection("forward")
  482.     if doesArrayContain(oreDetected, targetPos) then
  483.         if forward() then
  484.             table.insert(backTrackLog, "back")
  485.            
  486.             --remove ore and add to no ore list
  487.             removeDataFromArray(oreDetected,targetPos)
  488.             table.insert(noOreDetected, targetPos)
  489.  
  490.         else
  491.             return false
  492.         end
  493.         smartMineOreVeinWorker(noOreDetected,oreDetected,backTrackLog)
  494.     end
  495.  
  496.     -- Mine right if there is ore
  497.     targetPos = getPositionKeyWithDirection("right")
  498.     if doesArrayContain(oreDetected, targetPos) then
  499.         turnRight()
  500.         table.insert(backTrackLog, "turnleft")
  501.  
  502.         if forward() then
  503.             table.insert(backTrackLog, "back")
  504.  
  505.             --remove ore and add to no ore list
  506.             removeDataFromArray(oreDetected,targetPos)
  507.             table.insert(noOreDetected, targetPos)
  508.         else
  509.             return false
  510.         end
  511.         smartMineOreVeinWorker(noOreDetected,oreDetected,backTrackLog)
  512.     end
  513.  
  514.     -- Mine up if there is ore
  515.     targetPos = getPositionKeyWithDirection("up")
  516.     if doesArrayContain(oreDetected, targetPos) then
  517.  
  518.         if up() then
  519.             table.insert(backTrackLog, "down")
  520.  
  521.             --remove ore and add to no ore list
  522.             removeDataFromArray(oreDetected,targetPos)
  523.             table.insert(noOreDetected, targetPos)
  524.  
  525.         else
  526.             return false
  527.         end
  528.         smartMineOreVeinWorker(noOreDetected,oreDetected,backTrackLog)
  529.     end
  530.  
  531.     --no ores next to turtle need to backtrack if there are any ores left
  532.     if #oreDetected > 0 and #backTrackLog > 0 then
  533.         local action = table.remove(backTrackLog)
  534.  
  535.         --back tracked
  536.         if action == "turnright" then
  537.             turnRight()
  538.         elseif action == "turnleft" then
  539.             turnLeft()
  540.         elseif action == "back" then
  541.             back()
  542.         elseif action == "down" then
  543.             down()
  544.         elseif action == "up" then
  545.             up()
  546.         end
  547.  
  548.             --check backtracked location
  549.         smartMineOreVeinWorker(noOreDetected,oreDetected,backTrackLog)
  550.        
  551.  
  552.        
  553.  
  554.     else
  555.         return true
  556.     end
  557.  
  558. end
  559.  
  560. local function smartMineOreVein()
  561.  
  562.     local noOreDetected = {}
  563.     local oreDetected = {}
  564.     local backTrackLog = {}
  565.  
  566.     local startXPos, startYPos, startZPos, startDir = x, y, z, dir
  567.     smartMineOreVeinWorker(noOreDetected,oreDetected,backTrackLog, true)
  568.  
  569.     moveToLocation(startXPos,startYPos,startZPos)
  570.     turnToDirection(startDir)
  571. end
  572.  
  573. local function mineWellAndCollectOres()
  574.     local startXPos, startYPos, startZPos = x, y, z
  575.  
  576.     while down() do
  577.         for i = 1, 4, 1 do
  578.             turnLeft()
  579.             if isOre("forward") then
  580.                 smartMineOreVein()
  581.             end
  582.         end
  583.     end
  584.  
  585.     moveToLocation(startXPos,startYPos,startZPos)
  586. end
  587.  
  588. local function mineWellInGrid(width, depth)
  589.     local wellLocations = {}
  590.     local startXPos, startYPos, startZPos, startDir = x, y, z, dir
  591.  
  592.     -- Generate initial well positions
  593.     for z = 0, -(depth - 1), -1 do
  594.         for x = 0, (width - 1), 1 do
  595.             if z % 4 == 0 and x % 4 == 0 then
  596.                 table.insert(wellLocations, {x, y, z}) -- assumes y is global
  597.             end
  598.         end
  599.     end
  600.  
  601.     -- Duplicate with (2, 0, -2) offset
  602.     local originalCount = #wellLocations
  603.     for index = 1, originalCount do
  604.         local loc = wellLocations[index]
  605.         table.insert(wellLocations, {loc[1] + 2, loc[2], loc[3] - 2})
  606.     end
  607.  
  608.     -- Remove locations out of bounds
  609.     local i = 1
  610.     while i <= #wellLocations do
  611.         local x, _, z = table.unpack(wellLocations[i])
  612.         if x < 0 or x >= width or math.abs(z) > depth then
  613.             table.remove(wellLocations, i)
  614.         else
  615.             i = i + 1
  616.         end
  617.     end
  618.  
  619.     for i = 1, #wellLocations, 1 do
  620.        
  621.         moveToLocation(wellLocations[i][1], wellLocations[i][2], wellLocations[i][3])
  622.         mineWellAndCollectOres()
  623.        
  624.         moveToLocation(startXPos,startYPos,startZPos)
  625.         turnToDirection(startDir)
  626.  
  627.         turnLeft()
  628.         turnLeft()
  629.  
  630.         refuelAll(2000)
  631.        
  632.         dumpInventory("forward")
  633.     end
  634. end
  635.  
  636. --go to starting location when loaded again
  637. moveToLocation(0,0,0)
  638. turnToDirection("n")
  639.  
  640. local args = { ... }
  641.  
  642. if not args[1] then
  643.     print("Usage:")
  644.     print("mine reset (Reset turtle origin point)")
  645.     print("mine smartQuary <width> <depth> (Mine a grid of ore wells)")
  646.     return
  647.  
  648. elseif args[1] == "reset" then
  649.     resetState()
  650.     return
  651.  
  652. elseif args[1] == "smartQuary" then
  653.     local width = tonumber(args[2])
  654.     local depth = tonumber(args[3])
  655.  
  656.     if width and depth then
  657.         mineWellInGrid(width, depth)
  658.     else
  659.         print("Usage: mine smartQuary <width> <depth>")
  660.         print("Example: mine smartQuary 16 20")
  661.     end
  662.     return
  663.  
  664. else
  665.     print("Unknown subcommand: " .. tostring(args[1]))
  666.     print("Use one of the following:")
  667.     print("reset")
  668.     print("smartQuary <width> <depth>")
  669.     return
  670. end
  671.  
  672.  
  673.  
  674.  
  675.  
  676.  
  677.  
  678.  
  679.  
  680.  
  681.  
Advertisement
Add Comment
Please, Sign In to add comment