Compare commits
No commits in common. "d0ab016dcf6eaa6c4b7dc2c0c450782deb838f09" and "457d7e16618baa3e00d5e276e0f25caaab46019a" have entirely different histories.
d0ab016dcf
...
457d7e1661
1 changed files with 147 additions and 217 deletions
364
mine.lua
364
mine.lua
|
|
@ -1,91 +1,20 @@
|
|||
-- 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 = up of start, +z = forward of start
|
||||
-- +x = right of start, +y = forward of start, +z = up of start
|
||||
local FUEL_RESERVE = 800
|
||||
local FUEL_REFUEL_UNIT = 8 -- how many items to refuel with at a time
|
||||
local FULL_CHECK_SLOT = 14 -- slot to check for "fullness"
|
||||
|
||||
local V_ZERO = vector.new(0, 0, 0)
|
||||
local UNIT_X = vector.new(1, 0, 0)
|
||||
local UNIT_Y = vector.new(0, 1, 0)
|
||||
local UNIT_Z = vector.new(0, 0, 1)
|
||||
|
||||
local FORWARD, RIGHT, BACK, LEFT = 0, 1, 2, 3
|
||||
local mode = { v = vector.new(0, 0, 0), facing = FORWARD }
|
||||
local mode = { x = 0, y = 0, z = 0, facing = FORWARD }
|
||||
mode.mine = { forward = true }
|
||||
local block = {}
|
||||
|
||||
---------------------- BLOCK MATH ------------------------
|
||||
|
||||
function copy_v(v)
|
||||
return vector.new(
|
||||
v.x,
|
||||
v.y,
|
||||
v.z,
|
||||
)
|
||||
end
|
||||
|
||||
local bmetatable
|
||||
-- what is this? a type that holds a starting position and a dimention as
|
||||
-- two vectors
|
||||
-- TODO learn about metatables
|
||||
local Block = {
|
||||
-- orient our corner and offset to a vector
|
||||
orient = function (self, pos)
|
||||
local dims = {
|
||||
x = { self.v1.x, self.v1.x + self.v2.x }
|
||||
y = { self.v1.y, self.v1.y + self.v2.y }
|
||||
z = { self.v1.z, self.v1.z + self.v2.z }
|
||||
}
|
||||
for dim, points in pairs(dims) do
|
||||
-- pick the closer point
|
||||
-- return to point-offset format
|
||||
local point, offset
|
||||
if math.abs(points[1]) <= math.abs(points[2]) then
|
||||
point = points[1]
|
||||
offset = points[2] - points[1]
|
||||
else
|
||||
point = points[2]
|
||||
offset = points[1] - points[2]
|
||||
end
|
||||
self.v1[dim] = point
|
||||
self.v2[dim] = offset
|
||||
end
|
||||
return self
|
||||
end,
|
||||
take = function (self, amt, dir)
|
||||
-- TODO
|
||||
if dir ~= "x" and dir ~= "y" and dir ~= "z" then return nil end
|
||||
|
||||
local new, remainder = self:copy(), self
|
||||
new.v1[dir] = amt
|
||||
remainder.v1[dir] = remainder.v1[dir] + amt
|
||||
remainder.v2[dir] = remainder.v2[dir] - amt
|
||||
|
||||
return new, remainder
|
||||
end,
|
||||
copy = function (self)
|
||||
return Block.new(
|
||||
vector.new(self.v1.x, self.v1.y, self.v1.z),
|
||||
vector.new(self.v2.x, self.v2.y, self.v2.z),
|
||||
)
|
||||
function refuelUntil (amt)
|
||||
while turtle.getFuelLevel() < amt do
|
||||
if not turtle.refuel(8) then break end
|
||||
end
|
||||
}
|
||||
|
||||
bmetatable = {
|
||||
__name = "Block",
|
||||
__index = Block,
|
||||
}
|
||||
|
||||
local new_block = function (v1, v2)
|
||||
return setmetatable(
|
||||
{ v1 = v1, v2 = v2 },
|
||||
bmetatable
|
||||
)
|
||||
end
|
||||
|
||||
---------------------- BASIC MOVEMENT ---------------------
|
||||
|
||||
function mineSides ()
|
||||
if mode.mine.up then
|
||||
turtle.digUp()
|
||||
|
|
@ -110,6 +39,7 @@ function moveInLine (delta)
|
|||
end
|
||||
|
||||
function moveUpDown (delta)
|
||||
local delta = delta
|
||||
while delta > 0 do
|
||||
if mode.mine.forward then
|
||||
turtle.digUp()
|
||||
|
|
@ -148,58 +78,47 @@ function turnToFace (new_direction)
|
|||
mode.facing = new_direction
|
||||
end
|
||||
|
||||
function getCurrentPos()
|
||||
return mode.v
|
||||
end
|
||||
|
||||
-- move to a specific point
|
||||
function moveAbs (v)
|
||||
-- print(string.format("Moving to (%d, %d, %d)", v.x, v.y, v.z))
|
||||
move(v - getCurrentPos())
|
||||
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 (v)
|
||||
function move (x, y, z)
|
||||
-- x
|
||||
if v.x > 0 then
|
||||
if x > 0 then
|
||||
turnToFace(RIGHT)
|
||||
moveInLine(v.x)
|
||||
elseif v.x < 0 then
|
||||
moveInLine(x)
|
||||
elseif x < 0 then
|
||||
turnToFace(LEFT)
|
||||
moveInLine(-v.x)
|
||||
moveInLine(-x)
|
||||
end
|
||||
mode.v = mode.v + UNIT_X
|
||||
mode.x = mode.x + x
|
||||
-- z
|
||||
if v.z > 0 then
|
||||
if z > 0 then
|
||||
turnToFace(FORWARD)
|
||||
moveInLine(v.z)
|
||||
moveInLine(z)
|
||||
end
|
||||
if v.z < 0 then
|
||||
if z < 0 then
|
||||
turnToFace(BACK)
|
||||
moveInLine(-v.z)
|
||||
moveInLine(-z)
|
||||
end
|
||||
mode.v = mode.v + UNIT_Z
|
||||
mode.z = mode.z + z
|
||||
-- y
|
||||
moveUpDown(v.y)
|
||||
mode.v = mode.v + UNIT_Y
|
||||
moveUpDown(y)
|
||||
mode.y = mode.y + y
|
||||
end
|
||||
|
||||
-------------- DROPPING OFF AND REFUELING -------------------
|
||||
|
||||
function refuelUntil (amt)
|
||||
while turtle.getFuelLevel() < amt do
|
||||
if not turtle.refuel(FUEL_REFUEL_UNIT) then break end
|
||||
end
|
||||
end
|
||||
|
||||
function dropOffItems (starting_point, go_back)
|
||||
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 = vector.new(mode.v.x, mode.v.y, mode.v.z)
|
||||
local pos_state = { x = mode.x, y = mode.y, z = mode.z }
|
||||
-- Return to origin, facing BACK
|
||||
moveAbs(starting_point)
|
||||
moveAbs(V_ZERO)
|
||||
moveAbs(mode.x, mode.y, 0)
|
||||
moveAbs(0, 0, 0)
|
||||
turnToFace(BACK)
|
||||
-- deposit items
|
||||
for slot = 2, 16 do
|
||||
|
|
@ -208,102 +127,124 @@ function dropOffItems (starting_point, go_back)
|
|||
end
|
||||
turtle.select(1)
|
||||
-- Return to current position, facing forward
|
||||
if go_back then
|
||||
moveAbs(starting_point)
|
||||
moveAbs(pos_state)
|
||||
end
|
||||
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(FULL_CHECK_SLOT) > 0
|
||||
return turtle.getItemCount(15) > 0
|
||||
end
|
||||
|
||||
function checkAndDropOff(starting_point)
|
||||
if inventoryFull() then dropOffItems(starting_point, true) 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)
|
||||
-- assumptions: block is mineable in a single pass and oriented to the
|
||||
-- currentPos
|
||||
-- rough algo draft:
|
||||
-- 1. go to "starting point" at one end of block
|
||||
-- a. don't move vertically if you don't have to
|
||||
-- b. set mining mode beforehand
|
||||
-- 2. move to the ending point
|
||||
local height = block.v2.y
|
||||
if height % 3 == 0 then
|
||||
mode.mine = { up = true, forward = true, down = true }
|
||||
elseif height == 2 then
|
||||
mode.mine = { forward = true, up = true }
|
||||
elseif height == -2 then
|
||||
mode.mine = { forward = true, down = true }
|
||||
end
|
||||
local start_v = copy_v(block.v1)
|
||||
local end_v = block.v1 + block.v2
|
||||
if height > 2 then
|
||||
start_v = start_v + UNIT_Y
|
||||
end_v = end_v + UNIT_Y
|
||||
elseif height < -2 then
|
||||
start_v = start_v - UNIT_Y
|
||||
end_v = end_v - UNIT_Y
|
||||
end
|
||||
move(start_v)
|
||||
move(end_v)
|
||||
end
|
||||
|
||||
function canMine (block)
|
||||
local tooHigh = block.v2.y > 3
|
||||
-- we can only mine in a 1-wide strip at a time
|
||||
local tooWide = block.v2.x > 1 and block.v2.z > 1
|
||||
return not (tooHigh or tooWide)
|
||||
end
|
||||
|
||||
function splitHorizontal (block)
|
||||
-- TODO make this less naive?
|
||||
-- Future work: potentially split a large block into smaller blocks
|
||||
-- based on currentPos (think splitting down the middle instead of
|
||||
-- splitting off of one end)
|
||||
-- Future work: decide whether to take a slice off of the x or z direction
|
||||
-- (criteria?)
|
||||
return block:take(1, "x")
|
||||
end
|
||||
|
||||
function split (block)
|
||||
local tooHigh = function (block)
|
||||
return block.v2.y > 3
|
||||
end
|
||||
block = block:orient(getCurrentPos())
|
||||
if tooHigh(block) then
|
||||
return block:take(3, "y")
|
||||
else
|
||||
return splitHorizontal(block)
|
||||
end
|
||||
end
|
||||
|
||||
function process (stack, starting_point)
|
||||
-- START code taken from `mine`
|
||||
-- fuel and go to starting point
|
||||
-- fuel and go to starting corner
|
||||
refuelUntil(FUEL_RESERVE)
|
||||
mode.mine = { forward = true }
|
||||
moveAbs(starting_point)
|
||||
-- END
|
||||
-- TODO
|
||||
if #stack == 0 then return nil end
|
||||
local working = table.remove(stack):orient(getCurrentPos())
|
||||
if canMine(working) then
|
||||
checkAndDropOff(starting_point)
|
||||
mine(working)
|
||||
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
|
||||
local new, remainder = split(working, mode.v)
|
||||
table.insert(stack, remainder)
|
||||
table.insert(stack, new)
|
||||
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
|
||||
return process (stack)
|
||||
end
|
||||
|
||||
function calculateBlock (v1, v2)
|
||||
function calculateBlock (x1, y1, z1, x2, y2, z2)
|
||||
-- Using the coordinates, construct a block of certain dimensions, a
|
||||
-- certain distance away.
|
||||
local block = {}
|
||||
|
|
@ -319,39 +260,30 @@ function calculateBlock (v1, v2)
|
|||
block[dim] = corner
|
||||
block[dim .. "off"] = offset
|
||||
end
|
||||
normalize("x", v1.x, v2.x)
|
||||
normalize("y", v1.y, v2.y)
|
||||
normalize("z", v1.z, v2.z)
|
||||
return new_block(
|
||||
vector.new(block.x, block.y, block.z)
|
||||
vector.new(block.xoff, block.yoff, block.zoff)
|
||||
)
|
||||
normalize("x", x1, x2)
|
||||
normalize("y", y1, y2)
|
||||
normalize("z", z1, z2)
|
||||
return block
|
||||
end
|
||||
|
||||
function run (v1, v2)
|
||||
-- TODO calculate starting_point, the place turtle will move to before
|
||||
-- moving to the first corner of block
|
||||
local block = new_block(v1, v2 - v1)
|
||||
process({ block })
|
||||
function run (x1, y1, z1, x2, y2, z2)
|
||||
local block = calculateBlock(x1, y1, z1, x2, y2, z2)
|
||||
mine(block)
|
||||
-- return to base
|
||||
dropOffItems(starting_point)
|
||||
mode.mine = {}
|
||||
dropOffItems()
|
||||
turnToFace(FORWARD)
|
||||
end
|
||||
|
||||
function usage ()
|
||||
print("Usage: mine x1 y1 z1 x2 y2 z2 OR mine x1 y1 z1 OR mine x1 y1 z1
|
||||
x2 y2 z2 x_turtle y_turtle z_turtle.")
|
||||
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 0 for the first three.")
|
||||
print("If invoked with nine arguments, interpret the first two sets as
|
||||
world coordinates of the rectangular prism and the third set as
|
||||
the coordinates of the turtle's starting position,
|
||||
ASSUMING FACING NORTH.")
|
||||
print("Fuel goes in the top-left slot of the turtle's inventory.")
|
||||
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 ()
|
||||
|
|
@ -364,14 +296,12 @@ end
|
|||
|
||||
local arg = argsToNumbers()
|
||||
if #arg == 3 then
|
||||
run(V_ZERO, vector.new(arg[1], arg[2], arg[3]))
|
||||
-- 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(vector.new(arg[1], arg[2], arg[3]), vector.new(arg[4], arg[5], arg[6]))
|
||||
elseif #arg == 9 then
|
||||
local turtle_pos = vector.new(arg[7], arg[8], arg[9])
|
||||
local v1, v2 = vector.new(arg[1], arg[2], arg[3])
|
||||
, vector.new(arg[4], arg[5], arg[6])
|
||||
run(v1 - turtle_pos, v2 - turtle_pos)
|
||||
run(arg[1], arg[2], arg[3], arg[4], arg[5], arg[6])
|
||||
else
|
||||
usage()
|
||||
end
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue