first canonical version of miner script

This commit is contained in:
Emerson Rosen-Jones 2025-07-17 23:05:32 -04:00
commit 4e25323753

314
mine.lua Normal file
View file

@ -0,0 +1,314 @@
-- Mine a hole of depth by width by heigth, starting from 0, 0, -1 relative to
-- current position and facing
-- +x = right of start, +y = forward of start, +z = up of start
local FORWARD, RIGHT, BACK, LEFT = 0, 1, 2, 3
local mode = { x = 0, y = 0, z = 0, facing = FORWARD }
mode.mine = { forward = true }
local block = {}
function mineSides ()
if mode.mine.left then
turtle.turnLeft()
turtle.dig()
turtle.turnRight()
end
if mode.mine.right then
turtle.turnRight()
turtle.dig()
turtle.turnLeft()
end
end
function moveInLine (delta)
mineSides()
while delta > 0 do
if mode.mine.forward then
turtle.dig()
end
turtle.forward()
mineSides()
delta = delta - 1
end
end
function moveUpDown (delta)
local delta = delta
while delta > 0 do
if mode.mine.forward then
turtle.digUp()
end
turtle.up()
delta = delta - 1
-- mineSides()
end
while delta < 0 do
if mode.mine.forward then
turtle.digDown()
end
turtle.down()
delta = delta + 1
-- mineSides()
end
end
function turnToFace (new_direction)
local delta = new_direction - mode.facing
if delta > 2 then
delta = delta - 4
elseif delta < -2 then
delta = delta + 4
end
while delta > 0 do
turtle.turnRight()
delta = delta - 1
end
while delta < 0 do
turtle.turnLeft()
delta = delta + 1
end
mode.facing = new_direction
end
-- move to a specific point
function moveAbs (x, y, z)
-- print(string.format("Moving to (%d, %d, %d)", x, y, z))
move(x - mode.x, y - mode.y, z - mode.z)
end
-- move relative to the turtle's current location
function move (x, y, z)
-- x
if x > 0 then
turnToFace(RIGHT)
moveInLine(x)
elseif x < 0 then
turnToFace(LEFT)
moveInLine(-x)
end
mode.x = mode.x + x
-- y
if y > 0 then
turnToFace(FORWARD)
moveInLine(y)
end
if y < 0 then
turnToFace(BACK)
moveInLine(-y)
end
mode.y = mode.y + y
-- z
moveUpDown(z)
mode.z = mode.z + z
end
function dropOffItems (go_back)
-- Turn off mining
local mine_state = mode.mine
mode.mine = {}
-- Note current position (assuming facing FORWARD)
local pos_state = { x = mode.x, y = mode.y, z = mode.z }
-- Return to origin, facing BACK
moveAbs(mode.x, mode.y, 0)
moveAbs(0, 0, 0)
turnToFace(BACK)
-- deposit items
for slot = 2, 16 do
turtle.select(slot)
turtle.drop()
end
turtle.select(1)
-- Return to current position, facing forward
if go_back then moveAbs(pos_state.x, pos_state.y, pos_state.z) end
-- Turn mining back on, if it was on
mode.mine = mine_state
end
function inventoryFull ()
-- leave a little extra space just in case
return turtle.getItemCount(15) > 0
end
function moveAndCheck (x, y, z)
move(x, y, z)
if inventoryFull() then dropOffItems(true) end
if turtle.getFuelLevel() < 100 then turtle.refuel(8) end
end
function generateNextSteps (w, l)
-- assumptions:
-- 0 for l or w means don't move in that axis
-- 1 for w means mine on right side, -1 means left side
-- any greater absolute value of w assumes that the turtle starts in a
-- column of three and can mine on both sides out of the gate
local DIRECTION = {}
if w < 0 then DIRECTION.X = -1 else DIRECTION.X = 1 end
if l < 0 then DIRECTION.Y = -1 else DIRECTION.Y = 1 end
local remaining_width = math.abs(w) + 1
local column_len = math.abs(l)
local step_buffer = {}
return function ()
local next_step = {}
if #step_buffer == 0 then
if remaining_width < 1 then return nil end
-- Algorithm:
-- 1. mine l blocks in the y-direction
next_step = { x = 0, y = DIRECTION.Y * column_len }
next_step.mine = { forward = true, left = true, right = true }
if remaining_width == 2 then
local delta = DIRECTION.Y + DIRECTION.X
if delta == 0 then
next_step.mine.right = false
else
next_step.mine.left = false
end
elseif remaining_width == 1 then
next_step.mine.left = false
next_step.mine.right = false
end
table.insert(step_buffer, next_step)
-- setup position for next minePlane
if remaining_width == 1 and math.abs(w) > 1 then
next_step = { x = -DIRECTION.X, y = 0 }
next_step.mine = {}
table.insert(step_buffer, next_step)
end
DIRECTION.Y = -DIRECTION.Y
remaining_width = remaining_width - 3
next_step = { x = 0, y = 0 }
next_step.mine = { forward = true }
if remaining_width >= 3 then
-- 2. go in x-direction to mine a 3-wide column
next_step.x = DIRECTION.X * 3
table.insert(step_buffer, next_step)
elseif remaining_width > 0 then
-- or move for a finishing pass
next_step.x = DIRECTION.X * 2
table.insert(step_buffer, next_step)
end
end
next_step = table.remove(step_buffer, 1)
return next_step.x, next_step.y, next_step.mine
end
end
function minePlane (w, l)
-- mine a plane starting from the current location l blocks in the
-- y-direction and w blocks in the x-direction
print(string.format("Mining a plane of %d by %d", w, l))
mode.mine = { forward = true }
for x, y, mine in generateNextSteps(w, l) do
mode.mine = mine
-- print(string.format("Moving %d, %d relative to current pos.",
-- x, y))
moveAndCheck(x, y, 0)
end
end
function mine (block)
-- fuel and go to starting corner
if turtle.getFuelLevel() < 100 then turtle.refuel(8) end
mode.mine = { forward = true }
moveAbs(block.x, block.y, block.z)
-- Set up for next plane
-- 1. move in if necessary
local width = math.abs(block.xoff) + 1
local x_dir
if block.xoff < 0 then x_dir = -1 else x_dir = 1 end
if width > 2 then
move(x_dir, 0, 0)
end
-- Start mining planes
local h_remaining = function ()
return math.abs(block.z + block.zoff - mode.z)
end
-- initial pass without moving down
minePlane(block.xoff, block.yoff)
local z_dir
if block.zoff > 1 then z_dir = 1 else z_dir = -1 end
while h_remaining() > 0 do
-- calculate orientation of next plane
local w, l
if mode.y == block.y then
turnToFace(FORWARD)
l = block.yoff
else
turnToFace(BACK)
l = -block.yoff
end
local diff_from_start = math.abs(mode.x - block.x)
-- print(string.format("Distance from start: %d", diff_from_start))
if diff_from_start > 1 and width > 3 then
w = -block.xoff
else
w = block.xoff
end
move(0, 0, z_dir)
minePlane(w, l)
end
end
function calculateBlock (x1, y1, z1, x2, y2, z2)
-- Using the coordinates, construct a block of certain dimensions, a
-- certain distance away.
local block = {}
local normalize = function (dim, c1, c2)
-- pick the closest point
-- offset goes to the other point
local corner, offset
if math.abs(c1) <= math.abs(c2) then
corner, offset = c1, c2 - c1
else
corner, offset = c2, c1 - c2
end
block[dim] = corner
block[dim .. "off"] = offset
end
normalize("x", x1, x2)
normalize("y", y1, y2)
normalize("z", z1, z2)
return block
end
function run (x1, y1, z1, x2, y2, z2)
local block = calculateBlock(x1, y1, z1, x2, y2, z2)
mine(block)
-- return to base
mode.mine = {}
dropOffItems()
turnToFace(FORWARD)
end
function usage ()
print("Usage: mine x1 y1 z1 x2 y2 z2 OR mine x1 y1 z1")
print("Mine from the first set of coordinates to the second in a \
rectangular prism.")
print("The coordinates are relative to the facing of the turtle at the \
start of the program.")
print("If invoked with only three arguments, act as if they are the last \
three arguments and substitute 0 0 -1 for the first three.")
end
function argsToNumbers ()
local num_args = {}
for i, v in ipairs(arg) do
num_args[i] = tonumber(v)
end
return num_args
end
local arg = argsToNumbers()
if #arg == 3 then
-- TODO make the 3 arg version the same as it used to be
-- i.e. `mine 2 3 1` digs a 2-wide, 3-long, 1-deep hole starting under the
-- bot
run(0, 0, -1, arg[1], arg[2], arg[3])
elseif #arg == 6 then
run(arg[1], arg[2], arg[3], arg[4], arg[5], arg[6])
else
usage()
end