Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- local function TurtleState()
- local x, y, z = 0, 0, 0
- local dir = "n"
- local path = "/data/turtleState.json"
- local function load()
- if not fs.exists("/data") then
- fs.makeDir("/data")
- end
- if fs.exists(path) then
- local file = fs.open(path, "r")
- local data = textutils.unserializeJSON(file.readAll())
- file.close()
- x = data.x or 0
- y = data.y or 0
- z = data.z or 0
- dir = data.dir or "n"
- end
- end
- local function save(newX, newY, newZ, newDir)
- x = newX or x
- y = newY or y
- z = newZ or z
- dir = newDir or dir
- local file = fs.open(path, "w")
- file.write(textutils.serializeJSON({
- x = x,
- y = y,
- z = z,
- dir = dir
- }))
- file.close()
- end
- local function get()
- return x, y, z, dir
- end
- load()
- return {
- load = load,
- save = save,
- get = get
- }
- end
- dirIndex = { n = 0, e = 1, s = 2, w = 3 }
- dirNames = { "n", "e", "s", "w" }
- turtleState = TurtleState()
- x, y, z, dir = turtleState.get()
- local function refuelAll(limit)
- if turtle.getFuelLevel() < limit then
- for i = 1, 16, 1 do
- turtle.select(i)
- turtle.refuel()
- end
- end
- end
- local function resetState()
- x, y, z, dir = 0, 0, 0, "n"
- turtleState.save(x, y, z, dir)
- print("Turtle state reset to 0, 0, 0, facing north.")
- end
- local function isOre(dir)
- local inspectFn
- if dir == "" or dir == "forward" then
- inspectFn = turtle.inspect
- elseif dir == "up" then
- inspectFn = turtle.inspectUp
- elseif dir == "down" then
- inspectFn = turtle.inspectDown
- else
- error("Invalid direction: expected '', 'forward', 'up', or 'down'", 2)
- end
- local success, data = inspectFn()
- if not success or not data.name then
- return false
- end
- local name = data.name
- local blacklist = {
- "grass", "stone", "dirt", "gravel",
- "obsidian", "water", "lava", "bedrock", "turtle", "chest", "sand", "cactus"
- }
- for _, bad in ipairs(blacklist) do
- if name:find(bad) then
- return false
- end
- end
- return true
- end
- local function isInventoryFull()
- for i = 1, 16 do
- if turtle.getItemCount(i) == 0 then
- return false
- end
- end
- return true
- end
- local function dumpInventory(dir)
- local dropFn
- if dir == "" or dir == "forward" then
- dropFn = turtle.drop
- elseif dir == "up" then
- dropFn = turtle.dropUp
- elseif dir == "down" then
- dropFn = turtle.dropDown
- else
- error("Invalid direction: must be '', 'up', or 'down'", 2)
- end
- for i = 1, 16 do
- turtle.select(i)
- dropFn()
- end
- turtle.select(1) -- Restore selection
- end
- local function SmartDig(dir)
- local digFunction, inspectFunction, attempts
- if dir == "" or dir == "forward" then
- digFunction = turtle.dig
- inspectFunction = turtle.inspect
- elseif dir == "up" then
- digFunction = turtle.digUp
- inspectFunction = turtle.inspectUp
- elseif dir == "down" then
- digFunction = turtle.digDown
- inspectFunction = turtle.inspectDown
- else
- error("Invalid direction: expected '', 'forward', 'up', or 'down'", 2)
- end
- attempts = 2
- local function DigFallingEntity()
- while digFunction() do
- os.sleep(0.5)
- end
- end
- local function DigNormal()
- digFunction()
- end
- while attempts > 0 do
- local success, data = inspectFunction()
- if not success then
- return
- end
- local name = data.name or ""
- if name:find("gravel") or name:find("sand") then
- DigFallingEntity()
- elseif name:find("turtle") or name:find("lava") or name:find("water") or name:find("bedrock") then
- return
- else
- DigNormal()
- end
- -- Check again in case something fell
- local again, newData = inspectFunction()
- if again then
- attempts = attempts - 1
- else
- return
- end
- end
- end
- local function forward()
- SmartDig("forward")
- if turtle.forward() then
- if dir == "n" then
- z = z - 1
- elseif dir == "s" then
- z = z + 1
- elseif dir == "e" then
- x = x + 1
- elseif dir == "w" then
- x = x - 1
- end
- turtleState.save(x, y, z, dir)
- return true
- end
- return false
- end
- local function back()
- if turtle.back() then
- if dir == "n" then
- z = z + 1
- elseif dir == "s" then
- z = z - 1
- elseif dir == "e" then
- x = x - 1
- elseif dir == "w" then
- x = x + 1
- end
- turtleState.save(x, y, z, dir)
- return true
- end
- return false
- end
- local function up()
- SmartDig("up")
- if turtle.up() then
- y = y + 1
- turtleState.save(x, y, z, dir)
- return true
- end
- return false
- end
- local function down()
- SmartDig("down")
- if turtle.down() then
- y = y - 1
- turtleState.save(x, y, z, dir)
- return true
- end
- return false
- end
- local function turnLeft()
- turtle.turnLeft()
- local idx = (dirIndex[dir] - 1) % 4
- dir = dirNames[idx + 1]
- turtleState.save(x, y, z, dir)
- end
- local function turnRight()
- turtle.turnRight()
- local idx = (dirIndex[dir] + 1) % 4
- dir = dirNames[idx + 1]
- turtleState.save(x, y, z, dir)
- end
- local function turnToDirection(desiredDir)
- if dir == desiredDir then return end
- local current = dirIndex[dir]
- local target = dirIndex[desiredDir]
- local diff = (target - current) % 4
- if diff == 1 then
- turnRight()
- elseif diff == 2 then
- turnRight()
- turnRight()
- elseif diff == 3 then
- turnLeft()
- end
- end
- local function moveToLocation(desiredX, desiredY, desiredZ)
- -- Move vertically first (Y axis)
- while y < desiredY do
- if not up() then return false end
- end
- while y > desiredY do
- if not down() then return false end
- end
- -- Move along X axis
- if desiredX > x then
- turnToDirection("e")
- while x < desiredX do
- if not forward() then return false end
- end
- elseif desiredX < x then
- turnToDirection("w")
- while x > desiredX do
- if not forward() then return false end
- end
- end
- -- Move along Z axis
- if desiredZ > z then
- turnToDirection("s")
- while z < desiredZ do
- if not forward() then return false end
- end
- elseif desiredZ < z then
- turnToDirection("n")
- while z > desiredZ do
- if not forward() then return false end
- end
- end
- return true
- end
- local function removeDataFromArray(array, data)
- local foundIndex = -1
- for i, v in ipairs(array) do
- if data == v then
- foundIndex = i
- end
- end
- if foundIndex ~= -1 then
- table.remove(array, foundIndex)
- end
- end
- local function doesArrayContain(array, data)
- for i, v in ipairs(array) do
- if data == v then
- return true
- end
- end
- return false
- end
- local function createPositionKey(x, y, z)
- return string.format("%d,%d,%d", x, y, z)
- end
- local function getPositionKeyWithDirection(relativeDir)
- local dx, dy, dz = 0, 0, 0
- if relativeDir == "up" then
- dy = 1
- elseif relativeDir == "down" then
- dy = -1
- elseif relativeDir == "forward" then
- if dir == "n" then dz = -1
- elseif dir == "s" then dz = 1
- elseif dir == "e" then dx = 1
- elseif dir == "w" then dx = -1 end
- elseif relativeDir == "back" then
- if dir == "n" then dz = 1
- elseif dir == "s" then dz = -1
- elseif dir == "e" then dx = -1
- elseif dir == "w" then dx = 1 end
- elseif relativeDir == "left" then
- if dir == "n" then dx = -1
- elseif dir == "s" then dx = 1
- elseif dir == "e" then dz = -1
- elseif dir == "w" then dz = 1 end
- elseif relativeDir == "right" then
- if dir == "n" then dx = 1
- elseif dir == "s" then dx = -1
- elseif dir == "e" then dz = 1
- elseif dir == "w" then dz = -1 end
- else
- error("Invalid direction for getPositionKeyWithDirection: " .. tostring(relativeDir))
- end
- return createPositionKey(x + dx, y + dy, z + dz)
- end
- local function smartMineOreVeinWorker(noOreDetected, oreDetected, backTrackLog)
- local targetPos = getPositionKeyWithDirection("forward")
- if not doesArrayContain(noOreDetected, targetPos) and not doesArrayContain(oreDetected, targetPos) then
- if isOre("forward") then
- table.insert(oreDetected, targetPos)
- else
- table.insert(noOreDetected, targetPos)
- end
- end
- targetPos = getPositionKeyWithDirection("down")
- if not doesArrayContain(noOreDetected, targetPos) and not doesArrayContain(oreDetected, targetPos) then
- if isOre("down") then
- table.insert(oreDetected, targetPos)
- else
- table.insert(noOreDetected, targetPos)
- end
- end
- targetPos = getPositionKeyWithDirection("up")
- if not doesArrayContain(noOreDetected, targetPos) and not doesArrayContain(oreDetected, targetPos) then
- if isOre("up") then
- table.insert(oreDetected, targetPos)
- else
- table.insert(noOreDetected, targetPos)
- end
- end
- targetPos = getPositionKeyWithDirection("right")
- if not doesArrayContain(noOreDetected, targetPos) and not doesArrayContain(oreDetected, targetPos) then
- turnRight()
- if isOre("forward") then
- table.insert(oreDetected, targetPos)
- else
- table.insert(noOreDetected, targetPos)
- end
- turnLeft()
- end
- targetPos = getPositionKeyWithDirection("left")
- if not doesArrayContain(noOreDetected, targetPos) and not doesArrayContain(oreDetected, targetPos) then
- turnLeft()
- if isOre("forward") then
- table.insert(oreDetected, targetPos)
- else
- table.insert(noOreDetected, targetPos)
- end
- turnRight()
- end
- -- Mine down if there is ore
- targetPos = getPositionKeyWithDirection("down")
- if doesArrayContain(oreDetected, targetPos) then
- if down() then
- table.insert(backTrackLog, "up")
- --remove ore and add to no ore list
- removeDataFromArray(oreDetected,targetPos)
- table.insert(noOreDetected, targetPos)
- else
- return false
- end
- smartMineOreVeinWorker(noOreDetected,oreDetected,backTrackLog)
- end
- -- Mine left if there is ore
- targetPos = getPositionKeyWithDirection("left")
- if doesArrayContain(oreDetected, targetPos) then
- turnLeft()
- table.insert(backTrackLog, "turnright")
- if forward() then
- table.insert(backTrackLog, "back")
- --remove ore and add to no ore list
- removeDataFromArray(oreDetected,targetPos)
- table.insert(noOreDetected, targetPos)
- else
- return false
- end
- smartMineOreVeinWorker(noOreDetected,oreDetected,backTrackLog)
- end
- -- Mine forward if there is ore
- targetPos = getPositionKeyWithDirection("forward")
- if doesArrayContain(oreDetected, targetPos) then
- if forward() then
- table.insert(backTrackLog, "back")
- --remove ore and add to no ore list
- removeDataFromArray(oreDetected,targetPos)
- table.insert(noOreDetected, targetPos)
- else
- return false
- end
- smartMineOreVeinWorker(noOreDetected,oreDetected,backTrackLog)
- end
- -- Mine right if there is ore
- targetPos = getPositionKeyWithDirection("right")
- if doesArrayContain(oreDetected, targetPos) then
- turnRight()
- table.insert(backTrackLog, "turnleft")
- if forward() then
- table.insert(backTrackLog, "back")
- --remove ore and add to no ore list
- removeDataFromArray(oreDetected,targetPos)
- table.insert(noOreDetected, targetPos)
- else
- return false
- end
- smartMineOreVeinWorker(noOreDetected,oreDetected,backTrackLog)
- end
- -- Mine up if there is ore
- targetPos = getPositionKeyWithDirection("up")
- if doesArrayContain(oreDetected, targetPos) then
- if up() then
- table.insert(backTrackLog, "down")
- --remove ore and add to no ore list
- removeDataFromArray(oreDetected,targetPos)
- table.insert(noOreDetected, targetPos)
- else
- return false
- end
- smartMineOreVeinWorker(noOreDetected,oreDetected,backTrackLog)
- end
- --no ores next to turtle need to backtrack if there are any ores left
- if #oreDetected > 0 and #backTrackLog > 0 then
- local action = table.remove(backTrackLog)
- --back tracked
- if action == "turnright" then
- turnRight()
- elseif action == "turnleft" then
- turnLeft()
- elseif action == "back" then
- back()
- elseif action == "down" then
- down()
- elseif action == "up" then
- up()
- end
- --check backtracked location
- smartMineOreVeinWorker(noOreDetected,oreDetected,backTrackLog)
- else
- return true
- end
- end
- local function smartMineOreVein()
- local noOreDetected = {}
- local oreDetected = {}
- local backTrackLog = {}
- local startXPos, startYPos, startZPos, startDir = x, y, z, dir
- smartMineOreVeinWorker(noOreDetected,oreDetected,backTrackLog, true)
- moveToLocation(startXPos,startYPos,startZPos)
- turnToDirection(startDir)
- end
- local function mineWellAndCollectOres()
- local startXPos, startYPos, startZPos = x, y, z
- while down() do
- for i = 1, 4, 1 do
- turnLeft()
- if isOre("forward") then
- smartMineOreVein()
- end
- end
- end
- moveToLocation(startXPos,startYPos,startZPos)
- end
- local function mineWellInGrid(width, depth)
- local wellLocations = {}
- local startXPos, startYPos, startZPos, startDir = x, y, z, dir
- -- Generate initial well positions
- for z = 0, -(depth - 1), -1 do
- for x = 0, (width - 1), 1 do
- if z % 4 == 0 and x % 4 == 0 then
- table.insert(wellLocations, {x, y, z}) -- assumes y is global
- end
- end
- end
- -- Duplicate with (2, 0, -2) offset
- local originalCount = #wellLocations
- for index = 1, originalCount do
- local loc = wellLocations[index]
- table.insert(wellLocations, {loc[1] + 2, loc[2], loc[3] - 2})
- end
- -- Remove locations out of bounds
- local i = 1
- while i <= #wellLocations do
- local x, _, z = table.unpack(wellLocations[i])
- if x < 0 or x >= width or math.abs(z) > depth then
- table.remove(wellLocations, i)
- else
- i = i + 1
- end
- end
- for i = 1, #wellLocations, 1 do
- moveToLocation(wellLocations[i][1], wellLocations[i][2], wellLocations[i][3])
- mineWellAndCollectOres()
- moveToLocation(startXPos,startYPos,startZPos)
- turnToDirection(startDir)
- turnLeft()
- turnLeft()
- refuelAll(2000)
- dumpInventory("forward")
- end
- end
- --go to starting location when loaded again
- moveToLocation(0,0,0)
- turnToDirection("n")
- local args = { ... }
- if not args[1] then
- print("Usage:")
- print("mine reset (Reset turtle origin point)")
- print("mine smartQuary <width> <depth> (Mine a grid of ore wells)")
- return
- elseif args[1] == "reset" then
- resetState()
- return
- elseif args[1] == "smartQuary" then
- local width = tonumber(args[2])
- local depth = tonumber(args[3])
- if width and depth then
- mineWellInGrid(width, depth)
- else
- print("Usage: mine smartQuary <width> <depth>")
- print("Example: mine smartQuary 16 20")
- end
- return
- else
- print("Unknown subcommand: " .. tostring(args[1]))
- print("Use one of the following:")
- print("reset")
- print("smartQuary <width> <depth>")
- return
- end
Advertisement
Add Comment
Please, Sign In to add comment