robathome icon

Basic mining turtle w/ remote

robathome | PRO | 10/27/25 09:41:25 PM UTC (Edited) | 0 ⭐ | 444 👁️ | Never ⏰ | []
text |

9.44 KB

|

None

|

0 👍

/

0 👎

-- turtle_mine_coords.lua  (CC:Tweaked)
-- Mine a rectangular volume defined by two GPS corners (x1,x2 then y1,y2 then z1,z2).
-- Uses GPS only to pick and reach the nearest corner, then mines with relative moves.
-- Slot 1 = fuel. Slots 2..16 = filler for water/lava. Rednet protocol tmine.v1.
 local PROTO = "tmine.v1"
 -- ---------- Modem / Rednet ----------
local function openAnyModem()
  for _,side in ipairs(rs.getSides()) do
    if peripheral.getType(side) == "modem" then
      local m = peripheral.wrap(side)
      if m and m.isWireless and m.isWireless() then rednet.open(side); return true end
    end
  end
  return false
end
assert(openAnyModem(), "No wireless modem found/opened")
 local function log(msg)
  print(msg)
  rednet.broadcast({id=os.getComputerID(), msg=msg, t=os.epoch("utc")}, PROTO)
end
 -- ---------- GPS ----------
local function gpsPos() local x,y,z = gps.locate(2.0); return x,y,z end
do local x,y,z=gpsPos(); assert(x and y and z,"GPS not available"); log(("GPS lock: (%.1f, %.1f, %.1f)"):format(x,y,z)) end
 -- ---------- Fuel ----------
local function refuel(minFuel)
  if turtle.getFuelLevel()=="unlimited" then return true end
  minFuel = minFuel or 400
  if turtle.getFuelLevel() >= minFuel then return true end
  local keep = turtle.getSelectedSlot()
  turtle.select(1)
  while turtle.getFuelLevel() < minFuel do
    if turtle.getItemCount(1)==0 then turtle.select(keep); log("Fuel low; slot1 empty"); return false end
    turtle.refuel(1)
  end
  turtle.select(keep); return true
end
 -- ---------- Liquids / Filler ----------
local function selectFillSlot()
  for s=2,16 do if turtle.getItemCount(s)>0 then turtle.select(s); return true end end
  return false
end
local function isLiquid(info) return info and info.name and (info.name:find("water") or info.name:find("lava")) end
local function damFront() local ok,d=turtle.inspect(); if ok and isLiquid(d) then if selectFillSlot() then if turtle.place() then log("Dam front") end end end end
local function damUp()    local ok,d=turtle.inspectUp(); if ok and isLiquid(d) then if selectFillSlot() then if turtle.placeUp() then log("Dam up") end end end end
local function damDown()  local ok,d=turtle.inspectDown(); if ok and isLiquid(d) then if selectFillSlot() then if turtle.placeDown() then log("Dam down") end end end end
 -- ---------- Dig-safe moves ----------
local function fwd()
  while true do
    damFront()
    local ok,d=turtle.inspect(); if ok and not isLiquid(d) then turtle.dig() end
    if turtle.forward() then assertInside("forward"); return true end
    sleep(0.1)
  end
end
 local function up()
  while true do
    damUp()
    local ok,d=turtle.inspectUp(); if ok and not isLiquid(d) then turtle.digUp() end
    if turtle.up() then assertInside("up"); return true end
    sleep(0.1)
  end
end
 local function down()
  while true do
    damDown()
    local ok,d=turtle.inspectDown(); if ok and not isLiquid(d) then turtle.digDown() end
    if turtle.down() then assertInside("down"); return true end
    sleep(0.1)
  end
end
 ---------- Heading control ----------
local heading = 0 -- 0=+X,1=+Z,2=-X,3=-Z
local function right() turtle.turnRight(); heading=(heading+1)%4 end
local function left()  turtle.turnLeft();  heading=(heading+3)%4 end
local function face(dir)
  local d=(dir-heading)%4
  if d==1 then right()
  elseif d==2 then right(); right()
  elseif d==3 then left()
  end
end
 -- ---------- Move to absolute GPS corner (one-time) ----------
local function moveAxis(axis, delta)
  if delta==0 then return end
  if axis=="x" then
    face(delta>0 and 0 or 2); for i=1,math.abs(delta) do refuel(200); fwd() end
  elseif axis=="z" then
    face(delta>0 and 1 or 3); for i=1,math.abs(delta) do refuel(200); fwd() end
  elseif axis=="y" then
    local step = delta>0 and up or down; for i=1,math.abs(delta) do refuel(200); step() end
  end
end
local function gotoXYZ(tx,ty,tz)
  local x,y,z = gpsPos(); assert(x,"GPS lost")
  moveAxis("x", math.floor(tx - x + 0.5))
  x,y,z = gpsPos()
  moveAxis("z", math.floor(tz - z + 0.5))
  x,y,z = gpsPos()
  moveAxis("y", math.floor(ty - y + 0.5))
end
 -- ---------- Vertical step actions ----------
local function step_3layer()
  damUp();   local okU,du=turtle.inspectUp();   if okU and not isLiquid(du) then turtle.digUp() end
  damDown(); local okD,dd=turtle.inspectDown(); if okD and not isLiquid(dd) then turtle.digDown() end
end
local function step_2layer()
  damDown(); local okD,dd=turtle.inspectDown(); if okD and not isLiquid(dd) then turtle.digDown() end
end
local function step_1layer() end
 -- ---------- Serpentine over XZ (relative, bounded) ----------
-- Start at the chosen origin corner on the current Y layer.
-- enterDirX: 0 for +X travel on first row, 2 for -X.
-- Directions based on chosen corner
local DIR_X_POS = (sx==1) and 0 or 2   -- face(+X in world)
local DIR_X_NEG = (sx==1) and 2 or 0   -- face(-X in world)
local DIR_Z_STEP= (sz==1) and 1 or 3   -- step toward interior along Z
local DIR_Z_BACK= (sz==1) and 3 or 1   -- return toward origin along Z
 -- enterDirX must be either DIR_X_POS or DIR_X_NEG
local function serpentine_pass(nx, nz, enterDirX, stepAction)
   -- First row
  face(enterDirX)
  stepAction()
  for i=2,nx do fwd(); stepAction() end
   -- Remaining rows
  local curDir = enterDirX
  for row=1,(nz-1) do
    -- advance one row along Z (toward interior)
    face(DIR_Z_STEP); fwd()
     -- flip X direction
    curDir = (curDir==DIR_X_POS) and DIR_X_NEG or DIR_X_POS
    face(curDir)
    stepAction()
    for i=2,nx do fwd(); stepAction() end
  end
   -- Return to origin corner in-plane
  if (nz % 2)==1 then
    -- We ended on the far X edge; go back along X to origin edge
    face((curDir==DIR_X_POS) and DIR_X_NEG or DIR_X_POS)
    for i=2,nx do fwd() end
  end
  -- Go back along Z to origin
  face(DIR_Z_BACK)
  for i=2,nz do fwd() end
end
 -- ---------- Input ----------
local function readNum(p) term.write(p); local s=read(); local n=tonumber(s); assert(n,"number"); return n end
term.clear(); term.setCursorPos(1,1)
print("Volume Miner by Coordinates (slot1=fuel; 2..16 filler)")
print("Enter X limits first, then Y, then Z. Any order allowed within each pair.")
local x1 = readNum("x1: "); local x2 = readNum("x2: ")
local y1 = readNum("y1: "); local y2 = readNum("y2: ")
local z1 = readNum("z1: "); local z2 = readNum("z2: ")
 local minX,maxX = math.floor(math.min(x1,x2)), math.floor(math.max(x1,x2))
local minY,maxY = math.floor(math.min(y1,y2)), math.floor(math.max(y1,y2))
local minZ,maxZ = math.floor(math.min(z1,z2)), math.floor(math.max(z1,z2))
local nx = maxX - minX + 1
local ny = maxY - minY + 1
local nz = maxZ - minZ + 1
assert(nx>0 and ny>0 and nz>0, "empty volume")
 local function assertInside(where)
  local x,y,z = gps.locate(2.0)
  if not x then error("GPS lost during "..where, 0) end
  if x < minX or x > maxX or y < minY or y > maxY or z < minZ or z > maxZ then
    error(("ABORT: left volume at %s (%.0f,%.0f,%.0f)"):format(where,x,y,z), 0)
  end
end
 -- Choose the nearest of the four bottom-layer corners (we’ll handle vertical later)
local cx,cy,cz = gpsPos(); assert(cx,"GPS lost")
local candidates = {
  {minX,minY,minZ}, {maxX,minY,minZ}, {minX,minY,maxZ}, {maxX,minY,maxZ},
}
local best,bd=nil,1e18
for _,c in ipairs(candidates) do
  local d=math.abs(c[1]-cx)+math.abs(c[2]-cy)+math.abs(c[3]-cz)
  if d<bd then bd=d; best=c end
end
local ox,oy,oz = table.unpack(best)
local sx = (ox==minX) and 1 or -1
local sz = (oz==minZ) and 1 or -1
local sy = 1 -- we will mine upward in chunks; oy is at minY
log(("Box X[%d..%d] Y[%d..%d] Z[%d..%d] -> %dx%dx%d"):format(minX,maxX,minY,maxY,minZ,maxZ,nx,ny,nz))
log(("Origin corner: (%d,%d,%d)  dir sx=%d sz=%d"):format(ox,oy,oz,sx,sz))
 -- Go to origin corner once
gotoXYZ(ox,oy,oz)
 -- Orient first-row X direction based on sx
local enterDirX = (sx==1) and DIR_X_POS or DIR_X_NEG 
 -- Before each pass, ensure we are at the plane origin corner (we already are after our return)
local currentY = oy
local remaining = ny
 -- Helper: raise/lower to specific absolute Y by relative move (no GPS during mining)
local function goToYAbs(targetY)
  local x,y,z = gpsPos(); assert(x,"GPS lost")
  local dy = targetY - y
  if dy>0 then for i=1,dy do up() end
  elseif dy<0 then for i=1,-dy do down() end end
end
   assertInside("start")
 -- Vertical policy loop
while remaining > 0 do
   refuel(nx*nz*math.min(remaining,3) + 300)
   if remaining >= 3 then
    -- Middle of the 3-layer chunk
    local midY = currentY + 1
    goToYAbs(midY)
    -- Serpentine on this layer, clearing up and down each cell
    serpentine_pass(nx, nz, enterDirX, step_3layer); assertInside("after 3-layer")
    currentY = currentY + 3
    remaining = remaining - 3
   elseif remaining == 2 then
    -- Upper of the 2-layer chunk
    local upperY = currentY + 1
    goToYAbs(upperY)
    serpentine_pass(nx, nz, enterDirX, step_2layer); assertInside("after 2-layer")
    currentY = currentY + 2
    remaining = remaining - 2
   else -- remaining == 1
    goToYAbs(currentY)
    serpentine_pass(nx, nz, enterDirX, step_1layer); assertInside("after 1-layer")
    currentY = currentY + 1
    remaining = remaining - 1
  end
  -- After each pass, we are returned to the same XZ origin corner by serpentine_pass.
end
 local ex,ey,ez = gpsPos()
log(("Complete. End GPS: (%.1f, %.1f, %.1f)"):format(ex or -1, ey or -1, ez or -1))
print("Mining complete.")
 

Comments