------------------------------------------------------------
-- Advanced Chunk Miner (single-file)
-- - Turtle starts in the SOUTH-WEST corner, facing NORTH.
-- - Chest is directly SOUTH (behind the turtle) at (0, startY, 1).
-- - Prompts for number of layers to mine (C option).
-- Features:
-- * Tag-based ore detection (forge:ores) with name fallback
-- * Ore logging to "ore_log.txt"
-- * Robust drop-off & refuel routine (returns to chest, dumps, returns)
-- * State save/restore (resume) to "miner_state"
-- * Optional torch placement every TORCH_INTERVAL steps (0 to disable)
-- * Will attempt to bypass ore blocks (move up-forward-down) to preserve them
------------------------------------------------------------
-- ============ USER CONFIG =============
local WIDTH = 16
local LENGTH = 16
local TORCH_INTERVAL = 0 -- set >0 to place torch every N forward steps (placeUp)
local AUTO_CHEST = false -- not implemented auto-place; left as future hook
local STATE_FILE = "miner_state"
local ORE_LOG = "ore_log.txt"
local startY = 0
-- Turtle starts facing NORTH in SW corner
-- Coordinates system: x increases East, z increases South, y increases up
local x, y, z = 0, startY, 0
local dir = 0 -- 0 = north, 1 = east, 2 = south, 3 = west
-- Chest is directly SOUTH behind start: (0, startY, 1)
local chestX, chestY, chestZ = 0, startY, 1
local chestFaceDir = 0 -- to interact with chest we should face north (0) when at chest pos
-- ============ UTIL: persistence & logging ============
local function saveState(t)
local ok, err
local f = fs.open(STATE_FILE, "w")
if not f then
print("Warning: can't open state file for writing.")
return
end
f.write(textutils.serialize(t))
f.close()
end
local function loadState()
if not fs.exists(STATE_FILE) then return nil end
local f = fs.open(STATE_FILE, "r")
if not f then return nil end
local content = f.readAll()
f.close()
local ok, data = pcall(textutils.unserialize, content)
if ok then return data end
return nil
end
local function appendOreLog(s)
local f = fs.open(ORE_LOG, "a")
if not f then
print("Warning: couldn't open ore log.")
return
end
f.writeLine(s)
f.close()
end
-- ============ MOVEMENT HELPERS (update x,y,z,dir) ============
local function turnRight()
turtle.turnRight()
dir = (dir + 1) % 4
end
local function turnLeft()
turtle.turnLeft()
dir = (dir + 3) % 4
end
local function faceDirection(target)
while dir ~= target do turnRight() end
end
-- safer forward: tries to avoid digging ores by inspecting first.
-- if blocked by ore, attempts up(); forward(); down() bypass. If bypass fails, will dig non-ore blocks.
local function forwardSafe()
-- quick attempt
if turtle.forward() then
if dir == 0 then z = z - 1
elseif dir == 1 then x = x + 1
elseif dir == 2 then z = z + 1
else x = x - 1 end
return true
end
-- blocked: inspect the block ahead
local ok, data = turtle.inspect()
if ok then
local function isOreByData(d)
if not d then return false end
if d.tags and d.tags["forge:ores"] == true then return true end
if d.name and tostring(d.name):find("_ore") then return true end
return false
end
if isOreByData(data) then
-- try bypass: up, forward, down
print("Bypassing ore at forward: " .. (data.name or "unknown"))
if turtle.up() then
y = y + 1
if turtle.forward() then
if dir == 0 then z = z - 1
elseif dir == 1 then x = x + 1
elseif dir == 2 then z = z + 1
else x = x - 1 end
-- attempt to go back down
if turtle.down() then
y = y - 1
return true
else
-- can't go down: try to continue (still okay)
return true
end
else
-- couldn't forward after up: try to dig non-ore above and retry
local ok2, upData = turtle.inspectUp()
if ok2 and not isOreByData(upData) then
turtle.digUp()
if turtle.up() then
y = y + 1
if turtle.forward() then
if dir == 0 then z = z - 1
elseif dir == 1 then x = x + 1
elseif dir == 2 then z = z + 1
else x = x - 1 end
if turtle.down() then y = y - 1 end
return true
end
end
end
end
end
-- fallback: do not dig the ore. signal blocked.
return false
else
-- it's not an ore — dig until it's clear
while not turtle.forward() do
print("Digging non-ore forward...")
turtle.dig()
sleep(0.2)
end
if dir == 0 then z = z - 1
elseif dir == 1 then x = x + 1
elseif dir == 2 then z = z + 1
else x = x - 1 end
return true
end
else
-- couldn't inspect, try digging as last resort
while not turtle.forward() do
turtle.dig()
sleep(0.2)
end
if dir == 0 then z = z - 1
elseif dir == 1 then x = x + 1
elseif dir == 2 then z = z + 1
else x = x - 1 end
return true
end
end
local function upSafe()
while not turtle.up() do
local ok, d = turtle.inspectUp()
if ok and d then
-- if ore above, do not dig it; attempt to move by forward-first if possible
if (d.tags and d.tags["forge:ores"]) or (d.name and tostring(d.name):find("_ore")) then
-- can't go up through ore; abort
return false
else
turtle.digUp()
end
else
turtle.digUp()
end
sleep(0.2)
end
y = y + 1
return true
end
local function downSafe()
while not turtle.down() do
local ok, d = turtle.inspectDown()
if ok and d then
if (d.tags and d.tags["forge:ores"]) or (d.name and tostring(d.name):find("_ore")) then
return false
else
turtle.digDown()
end
else
turtle.digDown()
end
sleep(0.2)
end
y = y - 1
return true
end
-- absolute goTo using safe moves (vertical first)
local function goTo(tx, ty, tz)
-- vertical
while y < ty do
if not upSafe() then error("Cannot move up while going to target") end
end
while y > ty do
if not downSafe() then error("Cannot move down while going to target") end
end
-- X
if x < tx then
faceDirection(1)
while x < tx do forwardSafe() end
elseif x > tx then
faceDirection(3)
while x > tx do forwardSafe() end
end
-- Z
if z < tz then
faceDirection(2)
while z < tz do forwardSafe() end
elseif z > tz then
faceDirection(0)
while z > tz do forwardSafe() end
end
end
-- ============ INVENTORY & FUEL ============
local function refuel()
if turtle.getFuelLevel() == "unlimited" then return true end
for i = 1, 16 do
turtle.select(i)
if turtle.refuel(0) then turtle.refuel(1) end
end
return turtle.getFuelLevel() > 0
end
local function isInventoryFull()
for i = 1, 16 do
if turtle.getItemCount(i) == 0 then return false end
end
return true
end
local function dumpInventoryAtChest()
-- assume we are at chest location and facing chest facing north
for i = 1, 16 do
turtle.select(i)
turtle.drop()
end
end
-- dropOff: saves current position, goes to chest, dumps, refuels, returns, restores dir
local function dropOff()
print("Inventory full — returning to chest.")
local sx, sy, sz, sd = x, y, z, dir
-- go to chest coordinates
goTo(chestX, chestY, chestZ)
-- face chest (chest is SOUTH of start, when at chestX,chestY,chestZ we face NORTH to access it)
faceDirection(chestFaceDir)
dumpInventoryAtChest()
refuel()
-- return to saved spot
goTo(sx, sy, sz)
faceDirection(sd)
print("Returned to work location.")
end
-- ============ ORE DETECTION ============
local function isOreByData(d)
if not d then return false end
if d.tags and d.tags["forge:ores"] == true then return true end
if d.name and tostring(d.name):find("_ore") then return true end
return false
end
local function safeDigFrontAndLogIfOre()
local ok, data = turtle.inspect()
if ok and isOreByData(data) then
local msg = string.format("ORE FOUND (front) @ %d,%d,%d name=%s", x, y, z, tostring(data.name))
print(msg)
appendOreLog(msg)
return false
else
turtle.dig()
return true
end
end
local function safeDigUpAndLogIfOre()
local ok, data = turtle.inspectUp()
if ok and isOreByData(data) then
local msg = string.format("ORE FOUND (up) @ %d,%d,%d name=%s", x, y, z, tostring(data.name))
print(msg)
appendOreLog(msg)
return false
else
turtle.digUp()
return true
end
end
local function safeDigDownAndLogIfOre()
local ok, data = turtle.inspectDown()
if ok and isOreByData(data) then
local msg = string.format("ORE FOUND (down) @ %d,%d,%d name=%s", x, y, z, tostring(data.name))
print(msg)
appendOreLog(msg)
return false
else
turtle.digDown()
return true
end
end
-- ============ MINING LOGIC ============
local stepCounter = 0
local function maybePlaceTorch()
if TORCH_INTERVAL > 0 and (stepCounter % TORCH_INTERVAL) == 0 then
-- place torches up if possible (user should have torches in selected slot)
local ok, data = turtle.inspectUp()
if not ok then
turtle.placeUp() -- best-effort
end
end
end
local function mineLayer()
-- assumes starting in the SW corner facing north, will mine WIDTH x LENGTH area
for row = 1, WIDTH do
for col = 1, LENGTH - 1 do
if isInventoryFull() then dropOff() end
refuel()
-- dig the block in front unless it's an ore (we'll log ores)
safeDigFrontAndLogIfOre()
-- move forward safely (bypass ore if needed)
local moved = forwardSafe()
if not moved then
-- if forward blocked by ore and bypass failed, attempt to step right-left route:
-- try sidestep: right, forward, left. This is complex; we'll attempt one pattern.
print("Attempting sidestep around obstacle...")
turnRight()
if forwardSafe() then
turnLeft()
-- now continue
else
-- revert
turnLeft()
-- try left then right
turnLeft()
if forwardSafe() then
turnRight()
else
-- stuck: try to break non-ore blocks in front and continue
turnRight()
print("Stuck; attempting to dig forward (non-ore) until clear.")
while not forwardSafe() do
turtle.dig()
sleep(0.2)
end
end
end
end
stepCounter = stepCounter + 1
maybePlaceTorch()
end
-- end of row: move to next row if required
if row < WIDTH then
if (row % 2) == 1 then
-- turned approach: currently facing north; to move one block east and turn south
turnRight()
safeDigFrontAndLogIfOre()
forwardSafe()
turnRight()
else
turnLeft()
safeDigFrontAndLogIfOre()
forwardSafe()
turnLeft()
end
stepCounter = stepCounter + 1
maybePlaceTorch()
end
end
end
-- ============ MAIN CONTROL ============
-- Load saved state (if present)
local saved = loadState()
local targetLayers = nil
local currentLayer = 1
if saved then
-- saved may include: x,y,z,dir,currentLayer,targetLayers,stepCounter
if saved.targetLayers then
targetLayers = saved.targetLayers
currentLayer = saved.currentLayer or 1
x = saved.x or x; y = saved.y or y; z = saved.z or z; dir = saved.dir or dir
stepCounter = saved.stepCounter or stepCounter
print("Resuming saved run. Current layer:", currentLayer, "Target layers:", targetLayers)
else
-- old save format: ignore and start fresh
print("Found save but no target layers — starting fresh.")
end
end
-- if no targetLayers yet, prompt user
if not targetLayers then
print("How many layers would you like to mine? (enter a number, e.g. 4)")
local input = read()
local n = tonumber(input)
if n and n > 0 then
targetLayers = math.floor(n)
else
print("Invalid input. Defaulting to 1 layer.")
targetLayers = 1
end
currentLayer = 1
end
-- sanity check
if targetLayers < 1 then targetLayers = 1 end
print(string.format("Starting mining: %d layers (starting at layer %d).", targetLayers, currentLayer))
-- main loop: mine layer-by-layer
local success = true
while currentLayer <= targetLayers do
print(string.format("Mining layer %d / %d at y=%d", currentLayer, targetLayers, y))
-- mine current layer
mineLayer()
-- after finishing layer, attempt to move down to next layer
-- but first try safeDigDown — if it's an ore, we won't dig it and will try to bypass
local downOk, downData = turtle.inspectDown()
if downOk and isOreByData(downData) then
-- if there's ore immediately below the turtle's current position, try move forward then down to find a clear spot
print("Ore below turtle; attempting to find clear spot to descend...")
-- try to move to a known clear adjacent position and descend
local descended = false
-- try north
faceDirection(0)
if forwardSafe() and downSafe() then
descended = true
else
-- try east
faceDirection(1)
if forwardSafe() and downSafe() then
descended = true
else
-- try south
faceDirection(2)
if forwardSafe() and downSafe() then
descended = true
else
-- try west
faceDirection(3)
if forwardSafe() and downSafe() then
descended = true
end
end
end
end
if not descended then
print("Unable to find safe descend spot. Attempting to dig down if non-ore.")
if not safeDigDownAndLogIfOre() then
-- blocked by ore and cannot bypass: stop
print("Blocked by ore below and cannot bypass. Stopping.")
success = false
break
else
if not downSafe() then
print("Could not move down after digging. Stopping.")
success = false
break
end
end
end
else
-- no ore below — dig down and descend
if not safeDigDownAndLogIfOre() then
-- ore detected and logged, but safeDigDown returned false (we preserved ore)
-- attempt bypass: move forward then down etc (attempt a direct down)
if not downSafe() then
print("Cannot move down. Stopping.")
success = false
break
end
else
-- we dug down (or it was air) — now move down
if not downSafe() then
print("Can't move down; stopping.")
success = false
break
end
end
end
-- flip orientation to continue next layer in same pattern
-- we want turtle to face same direction to start the next layer sweep; rotate 180
turnRight() turnRight()
-- increment layer and save state
currentLayer = currentLayer + 1
saveState{ x = x, y = y, z = z, dir = dir, currentLayer = currentLayer, targetLayers = targetLayers, stepCounter = stepCounter }
end
-- finished or aborted: save final state
saveState{ x = x, y = y, z = z, dir = dir, currentLayer = currentLayer, targetLayers = targetLayers, stepCounter = stepCounter }
if success then
print("Mining complete for requested layers.")
else
print("Mining stopped prematurely. Check logs and environment.")
end
print("Final position:", x, y, z, "dir:", dir)