Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -- Advanced Mining Path Optimizer
- -- Optimizes mining paths based on room dimensions to minimize turns
- -- Position tracking
- local currentX = 0
- local currentY = 0
- local currentZ = 0
- local facing = 0 -- 0=forward(away from chest), 1=right, 2=back(toward chest), 3=left
- local resumePos = {x=0, y=0, z=0, facing=0}
- -- Essential items to keep
- local ESSENTIAL_ITEMS = {
- ["minecraft:torch"] = 64,
- ["minecraft:cobblestone"] = 128,
- ["minecraft:dirt"] = 128,
- ["minecraft:cobbled_deepslate"] = 128
- }
- -- Utility function to find an item in inventory
- local function findItem(itemName)
- for slot = 1, 16 do
- local item = turtle.getItemDetail(slot)
- if item and item.name == itemName then
- turtle.select(slot)
- return true
- end
- end
- return false
- end
- -- Check if there's space in inventory
- local function hasSpace()
- for slot = 1, 16 do
- if turtle.getItemCount(slot) == 0 then
- return true
- end
- end
- return false
- end
- -- Handle liquid blocks by placing a solid block
- local function handleLiquid(direction)
- if findItem("minecraft:cobblestone") or findItem("minecraft:dirt") or findItem("minecraft:cobbled_deepslate") then
- if direction == "up" then
- turtle.placeUp()
- elseif direction == "down" then
- turtle.placeDown()
- else
- turtle.place()
- end
- sleep(0.5)
- return true
- end
- return false
- end
- -- Turn to face specific direction optimally
- local function turnToFacingOptimal(targetFacing)
- local currentFacing = facing
- local rightTurns = (targetFacing - currentFacing) % 4
- local leftTurns = (currentFacing - targetFacing) % 4
- if rightTurns <= leftTurns then
- -- Turn right is shorter or equal
- for i = 1, rightTurns do
- turtle.turnRight()
- facing = (facing + 1) % 4
- end
- else
- -- Turn left is shorter
- for i = 1, leftTurns do
- turtle.turnLeft()
- facing = (facing - 1) % 4
- end
- end
- end
- -- Try to move with obstacle handling
- local function tryMove(moveFunc, digFunc, direction)
- -- First check if there's a liquid
- local detectFunc
- if direction == "up" then
- detectFunc = turtle.detectUp
- elseif direction == "down" then
- detectFunc = turtle.detectDown
- else
- detectFunc = turtle.detect
- end
- -- Maximum attempts to handle falling blocks
- local maxAttempts = 10
- local attempts = 0
- while attempts < maxAttempts do
- attempts = attempts + 1
- if detectFunc() then
- -- Handle liquid first
- if handleLiquid(direction) then
- digFunc()
- if moveFunc() then
- break
- end
- else
- digFunc()
- if moveFunc() then
- break
- end
- end
- else
- if moveFunc() then
- break
- else
- -- If movement failed but no block detected, try handling liquid
- if handleLiquid(direction) then
- if moveFunc() then
- break
- end
- end
- end
- end
- -- If we're still here after an attempt, brief pause before next try
- -- This helps with falling blocks settling
- sleep(0.2)
- -- If we've tried several times and still can't move, it might be an infinite fall
- if attempts == maxAttempts then
- print("Warning: Possible falling blocks causing obstruction")
- return false
- end
- end
- -- Update position after successful move
- if attempts < maxAttempts then -- Only update if we actually moved
- if moveFunc == turtle.forward then
- if facing == 0 then currentY = currentY - 1
- elseif facing == 1 then currentX = currentX + 1
- elseif facing == 2 then currentY = currentY + 1
- else currentX = currentX - 1 end
- elseif moveFunc == turtle.up then
- currentZ = currentZ + 1
- elseif moveFunc == turtle.down then
- currentZ = currentZ - 1
- end
- return true
- end
- return false
- end
- -- Return to the chest position
- local function returnToChest()
- local pathFound = false
- -- Try multiple vertical levels to find an open path
- local function tryPathAtLevel(targetZ)
- -- Move to target Z level first
- while currentZ > targetZ do
- if not turtle.down() then return false end
- currentZ = currentZ - 1
- end
- while currentZ < targetZ do
- if not turtle.up() then return false end
- currentZ = currentZ + 1
- end
- -- Face toward chest (facing 2)
- turnToFacingOptimal(2)
- -- Try Y movement without digging
- local initialY = currentY
- while currentY < 0 do
- if not turtle.forward() then
- -- If blocked, restore position and return false
- while currentY < initialY do
- turtle.back()
- currentY = currentY + 1
- end
- return false
- end
- currentY = currentY + 1
- end
- -- Try X movement without digging
- if currentX ~= 0 then
- if currentX > 0 then
- turnToFacingOptimal(3) -- face left
- else
- turnToFacingOptimal(1) -- face right
- end
- local initialX = currentX
- while currentX ~= 0 do
- if not turtle.forward() then
- -- If blocked, restore position and return false
- while currentX ~= initialX do
- turtle.back()
- currentX = currentX + (currentX > 0 and 1 or -1)
- end
- return false
- end
- currentX = currentX + (currentX > 0 and -1 or 1)
- end
- end
- return true
- end
- -- Try paths at different levels, starting with levels we expect to be clear
- local levelsToTry = {
- 0, -- Ground level (where chest is)
- -1, -- One below ground
- 1, -- One above ground
- currentZ, -- Current level
- }
- -- Add intermediate levels if we're far from 0
- if math.abs(currentZ) > 1 then
- table.insert(levelsToTry, math.floor(currentZ/2))
- end
- -- Try each level until we find a clear path
- for _, targetZ in ipairs(levelsToTry) do
- if tryPathAtLevel(targetZ) then
- pathFound = true
- break
- end
- end
- -- If no clear path found, fall back to original digging behavior
- if not pathFound then
- -- Original digging behavior
- while currentZ > 0 do
- if not tryMove(turtle.down, turtle.digDown, "down") then
- print("Can't move down to Z=0")
- return false
- end
- end
- while currentZ < 0 do
- if not tryMove(turtle.up, turtle.digUp, "up") then
- print("Can't move up to Z=0")
- return false
- end
- end
- turnToFacingOptimal(2)
- while currentY < 0 do
- if not tryMove(turtle.forward, turtle.dig, "forward") then
- print("Obstruction while returning on Y axis")
- return false
- end
- end
- if currentX ~= 0 then
- if currentX > 0 then
- turnToFacingOptimal(3)
- else
- turnToFacingOptimal(1)
- end
- while currentX ~= 0 do
- if not tryMove(turtle.forward, turtle.dig, "forward") then
- print("Obstruction while returning on X axis")
- return false
- end
- end
- end
- end
- -- Final position verification and facing correction
- if currentX ~= 0 or currentY ~= 0 or currentZ ~= 0 then
- print("Failed to reach chest position!")
- return false
- end
- -- Ensure we're facing the chest (facing 2) at the end
- turnToFacingOptimal(2)
- return true
- end
- -- Dump inventory while preserving essential items
- local function dumpInventory()
- -- Store current position
- resumePos.x = currentX
- resumePos.y = currentY
- resumePos.z = currentZ
- resumePos.facing = facing
- -- Return to chest
- print("Inventory full! Returning to chest...")
- if not returnToChest() then return false end
- -- Track preserved quantities
- local preserved = {
- ["minecraft:torch"] = 0,
- ["minecraft:cobblestone"] = 0,
- ["minecraft:dirt"] = 0,
- ["minecraft:cobbled_deepslate"] = 0
- }
- -- First pass: Calculate total preserved items
- for slot = 1, 16 do
- local item = turtle.getItemDetail(slot)
- if item and ESSENTIAL_ITEMS[item.name] then
- preserved[item.name] = preserved[item.name] + item.count
- end
- end
- -- Second pass: Drop excess items
- for slot = 1, 16 do
- turtle.select(slot)
- local item = turtle.getItemDetail(slot)
- if item then
- local itemName = item.name
- if ESSENTIAL_ITEMS[itemName] then
- local maxKeep = ESSENTIAL_ITEMS[itemName]
- local alreadyPreserved = preserved[itemName]
- if alreadyPreserved > maxKeep then
- -- Drop excess from this slot
- local toDrop = math.min(alreadyPreserved - maxKeep, item.count)
- turtle.drop(toDrop)
- preserved[itemName] = preserved[itemName] - toDrop
- end
- else
- -- Drop all non-essential items
- turtle.drop()
- end
- end
- end
- -- Return to mining position with optimized movement
- -- Move vertically first
- while currentZ ~= resumePos.z do
- if currentZ < resumePos.z then
- tryMove(turtle.up, turtle.digUp, "up")
- else
- tryMove(turtle.down, turtle.digDown, "down")
- end
- end
- -- Optimize Y movement
- if currentY ~= resumePos.y then
- if currentY > resumePos.y then
- turnToFacingOptimal(0) -- Face mining direction
- else
- turnToFacingOptimal(2) -- Face chest direction
- end
- while currentY ~= resumePos.y do
- tryMove(turtle.forward, turtle.dig, "forward")
- end
- end
- -- Optimize X movement
- if currentX ~= resumePos.x then
- if currentX < resumePos.x then
- turnToFacingOptimal(1) -- Face right
- else
- turnToFacingOptimal(3) -- Face left
- end
- while currentX ~= resumePos.x do
- tryMove(turtle.forward, turtle.dig, "forward")
- end
- end
- -- Return to original facing
- turnToFacingOptimal(resumePos.facing)
- return true
- end
- -- Dump all inventory at the end of mining
- local function dumpAllInventory()
- -- Return to chest if not already there
- if currentX ~= 0 or currentY ~= 0 or currentZ ~= 0 then
- if not returnToChest() then
- print("Failed to return to chest!")
- return false
- end
- end
- -- Ensure facing chest
- turnToFacingOptimal(2)
- -- Small delay to ensure stable chest interaction
- sleep(0.5)
- -- Dump everything from inventory
- for slot = 1, 16 do
- turtle.select(slot)
- -- Drop entire stack, regardless of item type
- turtle.drop()
- end
- return true
- end
- -- Calculate required torches
- local function calculateTorches(length, width)
- return math.ceil(length/4) * math.ceil(width/4)
- end
- -- Move vertically based on direction
- local function moveVertical(verticalDir)
- if verticalDir == "up" then
- return turtle.up, turtle.digUp, "up"
- else
- return turtle.down, turtle.digDown, "down"
- end
- end
- -- Execute the generated path
- local function executePath(path)
- local torchCounter = 0
- for i, step in ipairs(path) do
- -- Check inventory space
- if not hasSpace() then
- if not dumpInventory() then
- print("Aborting mining operation")
- return false
- end
- end
- if step.action == "mine" then
- -- Mine and move forward
- if not tryMove(turtle.forward, turtle.dig, "forward") then
- print("Obstruction detected at position " .. step.x .. "," .. step.y)
- return false
- end
- -- Place torch periodically
- torchCounter = torchCounter + 1
- if torchCounter % 4 == 0 and findItem("minecraft:torch") then
- turtle.placeDown()
- end
- elseif step.action == "turn_right" then
- turtle.turnRight()
- facing = (facing + 1) % 4
- elseif step.action == "turn_left" then
- turtle.turnLeft()
- facing = (facing - 1) % 4
- end
- end
- return true
- end
- -- Generate an improved serpentine pattern for even×even dimensions
- local function generateSerpentinePath(length, width)
- local path = {}
- -- Start at position 1,1
- table.insert(path, {x=1, y=1, action="mine"})
- for row = 1, width do
- local isEvenRow = (row % 2 == 0)
- for col = 2, length do
- local x = isEvenRow and (length - col + 1) or col
- table.insert(path, {x=x, y=row, action="mine"})
- end
- -- Move to next row if not the last row
- if row < width then
- local x = isEvenRow and 1 or length
- -- Add turn
- table.insert(path, {x=x, y=row, action="turn_right"})
- -- Add move down
- table.insert(path, {x=x, y=row+1, action="mine"})
- -- Add turn to prepare for next row
- if isEvenRow then
- table.insert(path, {x=x, y=row+1, action="turn_right"})
- else
- table.insert(path, {x=x, y=row+1, action="turn_left"})
- end
- end
- end
- return path
- end
- -- Generate a spiral pattern for odd×odd dimensions
- local function generateSpiralPath(length, width)
- local path = {}
- local x, y = 1, 1
- local minX, maxX = 1, length
- local minY, maxY = 1, width
- local dir = 0 -- 0=right, 1=down, 2=left, 3=up
- -- Track visited blocks
- local visited = {}
- for i = 1, length do
- visited[i] = {}
- for j = 1, width do
- visited[i][j] = false
- end
- end
- visited[x][y] = true
- table.insert(path, {x=x, y=y, action="mine"})
- while true do
- local nextX, nextY = x, y
- if dir == 0 then -- right
- nextX = x + 1
- if nextX > maxX or visited[nextX][y] then
- dir = (dir + 1) % 4
- minY = minY + 1
- nextX, nextY = x, y + 1
- end
- elseif dir == 1 then -- down
- nextY = y + 1
- if nextY > maxY or visited[x][nextY] then
- dir = (dir + 1) % 4
- maxX = maxX - 1
- nextX, nextY = x - 1, y
- end
- elseif dir == 2 then -- left
- nextX = x - 1
- if nextX < minX or visited[nextX][y] then
- dir = (dir + 1) % 4
- maxY = maxY - 1
- nextX, nextY = x, y - 1
- end
- else -- up
- nextY = y - 1
- if nextY < minY or visited[x][nextY] then
- dir = (dir + 1) % 4
- minX = minX + 1
- nextX, nextY = x + 1, y
- end
- end
- -- Add turn if direction changed
- if x ~= nextX or y ~= nextY then
- if nextX < 1 or nextX > length or nextY < 1 or nextY > width or visited[nextX][nextY] then
- -- We've completed the spiral
- break
- end
- -- Add turn if needed
- if dir == 0 and facing ~= 1 then
- table.insert(path, {x=x, y=y, action="turn_right"})
- elseif dir == 1 and facing ~= 2 then
- table.insert(path, {x=x, y=y, action="turn_right"})
- elseif dir == 2 and facing ~= 3 then
- table.insert(path, {x=x, y=y, action="turn_right"})
- elseif dir == 3 and facing ~= 0 then
- table.insert(path, {x=x, y=y, action="turn_right"})
- end
- -- Add move
- table.insert(path, {x=nextX, y=nextY, action="mine"})
- visited[nextX][nextY] = true
- x, y = nextX, nextY
- else
- -- No more moves possible
- break
- end
- end
- return path
- end
- -- Generate an adaptive pattern for mixed dimensions (odd×even or even×odd)
- local function generateAdaptivePath(length, width)
- local path = {}
- -- Start at position 1,1
- table.insert(path, {x=1, y=1, action="mine"})
- for row = 1, width do
- local isEvenRow = (row % 2 == 0)
- for col = 2, length do
- local x = isEvenRow and (length - col + 1) or col
- table.insert(path, {x=x, y=row, action="mine"})
- end
- -- Move to next row if not the last row
- if row < width then
- local x = isEvenRow and 1 or length
- -- Add turn
- table.insert(path, {x=x, y=row, action="turn_right"})
- -- Add move down
- table.insert(path, {x=x, y=row+1, action="mine"})
- -- Add turn to prepare for next row
- if isEvenRow then
- table.insert(path, {x=x, y=row+1, action="turn_right"})
- else
- table.insert(path, {x=x, y=row+1, action="turn_left"})
- end
- end
- end
- -- Add optimized return path for mixed dimensions
- -- This is particularly important for odd×even dimensions
- if width % 2 == 0 then
- -- We ended at the bottom left, which is good for returning
- -- No need to optimize
- else
- -- We ended at the bottom right, optimize return path
- local endPos = path[#path]
- if endPos.x == length and endPos.y == width then
- -- Add path to get closer to start
- table.insert(path, {x=length, y=width, action="turn_left"})
- table.insert(path, {x=length, y=width, action="turn_left"})
- -- Move up a few steps
- for i = 1, math.min(3, width-1) do
- table.insert(path, {x=length, y=width-i, action="mine"})
- end
- -- Turn left toward start
- table.insert(path, {x=length, y=width-3, action="turn_left"})
- -- Move left a few steps
- for i = 1, math.min(3, length-1) do
- table.insert(path, {x=length-i, y=width-3, action="mine"})
- end
- end
- end
- return path
- end
- -- Generate a specialized pattern for mining a chunk (16×16 or larger)
- local function generateChunkPattern(length, width)
- local path = {}
- -- Calculate quadrant sizes
- local quadWidth = math.floor(width / 2)
- local quadLength = math.floor(length / 2)
- -- First quadrant (top-left)
- local q1 = generateSerpentinePath(quadLength, quadWidth)
- for _, move in ipairs(q1) do
- table.insert(path, move)
- end
- -- Add bridge to second quadrant (top-right)
- local lastPos = q1[#q1]
- if not lastPos then
- -- Error handling if q1 is empty (should not happen)
- print("Error: Failed to generate path for first quadrant")
- return generateSerpentinePath(length, width) -- Fallback to simple pattern
- end
- table.insert(path, {x=lastPos.x, y=lastPos.y, action="turn_right"})
- -- Move to second quadrant
- for i = 1, (length - lastPos.x) do
- table.insert(path, {x=lastPos.x + i, y=lastPos.y, action="mine"})
- end
- -- Second quadrant (top-right)
- local q2 = generateSerpentinePath(quadLength, quadWidth)
- for _, move in ipairs(q2) do
- -- Adjust coordinates for this quadrant
- local adjusted = {
- x = move.x + quadLength,
- y = move.y,
- action = move.action
- }
- table.insert(path, adjusted)
- end
- -- Add bridge to third quadrant (bottom-right)
- local lastPos2 = {x = q2[#q2].x + quadLength, y = q2[#q2].y}
- table.insert(path, {x=lastPos2.x, y=lastPos2.y, action="turn_right"})
- -- Move to third quadrant
- for i = 1, (width - lastPos2.y) do
- table.insert(path, {x=lastPos2.x, y=lastPos2.y + i, action="mine"})
- end
- -- Third quadrant (bottom-right)
- local q3 = generateSerpentinePath(quadLength, quadWidth)
- for _, move in ipairs(q3) do
- -- Adjust coordinates for this quadrant
- local adjusted = {
- x = move.x + quadLength,
- y = move.y + quadWidth,
- action = move.action
- }
- table.insert(path, adjusted)
- end
- -- Add bridge to fourth quadrant (bottom-left)
- local lastPos3 = {x = q3[#q3].x + quadLength, y = q3[#q3].y + quadWidth}
- table.insert(path, {x=lastPos3.x, y=lastPos3.y, action="turn_right"})
- -- Move to fourth quadrant
- for i = 1, (lastPos3.x - 1) do
- table.insert(path, {x=lastPos3.x - i, y=lastPos3.y, action="mine"})
- end
- -- Fourth quadrant (bottom-left)
- local q4 = generateSerpentinePath(quadLength, quadWidth)
- for _, move in ipairs(q4) do
- -- Adjust coordinates for this quadrant
- local adjusted = {
- x = move.x,
- y = move.y + quadWidth,
- action = move.action
- }
- table.insert(path, adjusted)
- end
- return path
- end
- -- Generate path for a square or rectangular room
- local function generatePath(length, width)
- local path = {}
- -- Determine the best path strategy based on dimensions
- if length == width and length % 2 == 1 then
- -- Square with odd dimensions - use spiral
- print("Using spiral pattern for square with odd dimensions")
- return generateSpiralPath(length, width)
- elseif length >= 16 and width >= 16 then
- -- Large area (chunk size) - use chunk pattern
- print("Using optimized chunk mining pattern")
- return generateChunkPattern(length, width)
- elseif length % 2 == 0 and width % 2 == 0 then
- -- Even x Even - use serpentine
- print("Using improved serpentine for even×even dimensions")
- return generateSerpentinePath(length, width)
- else
- -- Mixed dimensions - use adaptive pattern
- print("Using adaptive pattern for mixed dimensions")
- return generateAdaptivePath(length, width)
- end
- end
- -- Main Program
- local args = {...}
- if #args < 3 then
- print("Usage: digRoom <length> <width> <height> [horizontal] [vertical]")
- print("horizontal: left/right (default: right)")
- print("vertical: up/down (default: up)")
- return
- end
- local length = tonumber(args[1])
- local width = tonumber(args[2])
- local height = tonumber(args[3])
- local horizontalDir = args[4] or "right"
- local verticalDir = args[5] or "up"
- if not (length and width and height) or length < 1 or width < 1 or height < 1 then
- print("Invalid dimensions!")
- return
- end
- if horizontalDir ~= "left" and horizontalDir ~= "right" then
- print("Invalid horizontal direction! Use 'left' or 'right'")
- return
- end
- if verticalDir ~= "up" and verticalDir ~= "down" then
- print("Invalid vertical direction! Use 'up' or 'down'")
- return
- end
- -- Calculate required resources
- local totalBlocks = length * width * height
- -- Add extra margin for fuel based on path complexity
- local fuelNeeded = totalBlocks * 1.2
- local requiredTorches = height > 1 and calculateTorches(length, width) or 0
- -- Check fuel
- if turtle.getFuelLevel() < fuelNeeded then
- print(string.format("Need %d fuel, have %d", fuelNeeded, turtle.getFuelLevel()))
- return
- end
- -- Check torches if needed
- if requiredTorches > 0 then
- local torchCount = 0
- for slot = 1, 16 do
- local item = turtle.getItemDetail(slot)
- if item and item.name == "minecraft:torch" then
- torchCount = torchCount + turtle.getItemCount(slot)
- end
- end
- if torchCount < requiredTorches then
- print(string.format("Need %d torches, have %d", requiredTorches, torchCount))
- return
- end
- end
- -- Check for blocking material
- local hasBlockingMaterial = false
- for slot = 1, 16 do
- local item = turtle.getItemDetail(slot)
- if item and (item.name == "minecraft:cobblestone" or item.name == "minecraft:dirt" or item.name == "minecraft:cobbled_deepslate") then
- hasBlockingMaterial = true
- break
- end
- end
- if not hasBlockingMaterial then
- print("Warning: No blocks available for liquid handling")
- print("Recommend having cobblestone, dirt, or cobbled deepslate")
- print("Continue anyway? (y/n)")
- local response = read():lower()
- if response ~= "y" then
- return
- end
- end
- print(string.format("Mining room %d×%d×%d using optimized algorithm", length, width, height))
- -- Mine each layer
- for layer = 1, height do
- print("Mining layer " .. layer .. " of " .. height)
- -- Generate optimized path for this layer
- local path = generatePath(length, width)
- -- Execute the path
- if not executePath(path) then
- print("Mining operation aborted at layer " .. layer)
- break
- end
- if layer < height then
- -- Move up/down to next layer
- local moveFunc, digFunc, direction = moveVertical(verticalDir)
- if not tryMove(moveFunc, digFunc, direction) then
- print("Warning: Unable to move " .. verticalDir .. " (possible liquid)")
- print("Try again? (y/n)")
- local response = read():lower()
- if response ~= "y" then
- break
- end
- end
- end
- end
- -- Final return and dump all inventory
- print("Mining complete! Returning to chest...")
- if dumpAllInventory() then
- print("All items deposited in chest.")
- turnToFacingOptimal(0)
- else
- print("Failed to deposit all items!")
- end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement