307 lines
8.4 KiB
Lua
307 lines
8.4 KiB
Lua
-- 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 FUEL_RESERVE = 800
|
|
|
|
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 refuelUntil (amt)
|
|
while turtle.getFuelLevel() < amt do
|
|
if not turtle.refuel(8) then break end
|
|
end
|
|
end
|
|
|
|
function mineSides ()
|
|
if mode.mine.up then
|
|
turtle.digUp()
|
|
end
|
|
if mode.mine.down then
|
|
turtle.digDown()
|
|
end
|
|
end
|
|
|
|
function moveInLine (delta)
|
|
mineSides()
|
|
while delta > 0 do
|
|
if mode.mine.forward then
|
|
turtle.dig()
|
|
end
|
|
local success = turtle.forward()
|
|
if success then
|
|
mineSides()
|
|
delta = delta - 1
|
|
end
|
|
end
|
|
end
|
|
|
|
function moveUpDown (delta)
|
|
local delta = delta
|
|
while delta > 0 do
|
|
if mode.mine.forward then
|
|
turtle.digUp()
|
|
end
|
|
local success = turtle.up()
|
|
if success then
|
|
delta = delta - 1
|
|
end
|
|
end
|
|
while delta < 0 do
|
|
if mode.mine.forward then
|
|
turtle.digDown()
|
|
end
|
|
local success = turtle.down()
|
|
if success then
|
|
delta = delta + 1
|
|
end
|
|
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
|
|
-- z
|
|
if z > 0 then
|
|
turnToFace(FORWARD)
|
|
moveInLine(z)
|
|
end
|
|
if z < 0 then
|
|
turnToFace(BACK)
|
|
moveInLine(-z)
|
|
end
|
|
mode.z = mode.z + z
|
|
-- y
|
|
moveUpDown(y)
|
|
mode.y = mode.y + y
|
|
end
|
|
|
|
function dropOffItems (go_back)
|
|
-- Turn off mining
|
|
local mine_state = mode.mine
|
|
mode.mine = { forward = true }
|
|
-- 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
|
|
refuelUntil(FUEL_RESERVE)
|
|
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 }
|
|
table.insert(step_buffer, next_step)
|
|
|
|
DIRECTION.Y = -DIRECTION.Y
|
|
|
|
remaining_width = remaining_width - 1
|
|
|
|
next_step = { x = 0, y = 0 }
|
|
if remaining_width > 0 then
|
|
-- 2. go in the x direction for the next y-sweep
|
|
next_step.x = DIRECTION.X
|
|
table.insert(step_buffer, next_step)
|
|
end
|
|
end
|
|
next_step = table.remove(step_buffer, 1)
|
|
return next_step.x, next_step.y
|
|
end
|
|
end
|
|
|
|
function minePlane (w, l, h)
|
|
-- 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 by %d", w, l, h))
|
|
mode.mine = { forward = true }
|
|
if h == 1 then
|
|
mode.mine.up = true
|
|
elseif h == -1 then
|
|
mode.mine.down = true
|
|
elseif h ~= 0 then
|
|
mode.mine.up = true
|
|
mode.mine.down = true
|
|
end
|
|
for x, y in generateNextSteps(w, l) do
|
|
-- 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
|
|
refuelUntil(FUEL_RESERVE)
|
|
mode.mine = { forward = true }
|
|
moveAbs(block.x, block.y, block.z)
|
|
local z_dir
|
|
if block.zoff > 1 then z_dir = 1 else z_dir = -1 end
|
|
local remaining_h = math.abs(block.z + block.zoff - mode.z) + 1
|
|
-- Initial pass; leave remaining_h at a nice multiple of 3
|
|
local excess = remaining_h % 3
|
|
if excess > 0 then
|
|
minePlane(block.xoff, block.yoff, (excess - 1) * z_dir)
|
|
if excess == 1 then
|
|
move(0, 0, -z_dir)
|
|
end
|
|
remaining_h = remaining_h - excess
|
|
else
|
|
move(0, 0, z_dir)
|
|
minePlane(block.xoff, block.yoff, 3)
|
|
remaining_h = remaining_h - 3
|
|
end
|
|
-- Start mining planes
|
|
while remaining_h > 0 do
|
|
-- calculate orientation of next plane
|
|
local w, l
|
|
if mode.y == block.y then
|
|
l = block.yoff
|
|
else
|
|
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 mode.x == block.x then
|
|
w = block.xoff
|
|
else
|
|
w = -block.xoff
|
|
end
|
|
-- move down into the new plane and mine it
|
|
move(0, 0, z_dir * 3)
|
|
minePlane(w, l, 3)
|
|
remaining_h = remaining_h - 3
|
|
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.")
|
|
print("Fuel goes in the top-left slot of the turtle's inventory")
|
|
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
|