Compare commits
2 commits
457d7e1661
...
d0ab016dcf
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d0ab016dcf | ||
|
|
4f0876fb64 |
1 changed files with 220 additions and 150 deletions
368
mine.lua
368
mine.lua
|
|
@ -1,20 +1,91 @@
|
||||||
-- Mine a hole of depth by width by heigth, starting from 0, 0, -1 relative to
|
-- Mine a hole of depth by width by heigth, starting from 0, 0, -1 relative to
|
||||||
-- current position and facing
|
-- current position and facing
|
||||||
|
|
||||||
-- +x = right of start, +y = forward of start, +z = up of start
|
-- +x = right of start, +y = up of start, +z = forward of start
|
||||||
local FUEL_RESERVE = 800
|
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 FORWARD, RIGHT, BACK, LEFT = 0, 1, 2, 3
|
||||||
local mode = { x = 0, y = 0, z = 0, facing = FORWARD }
|
local mode = { v = vector.new(0, 0, 0), facing = FORWARD }
|
||||||
mode.mine = { forward = true }
|
mode.mine = { forward = true }
|
||||||
local block = {}
|
|
||||||
|
|
||||||
function refuelUntil (amt)
|
---------------------- BLOCK MATH ------------------------
|
||||||
while turtle.getFuelLevel() < amt do
|
|
||||||
if not turtle.refuel(8) then break end
|
function copy_v(v)
|
||||||
end
|
return vector.new(
|
||||||
|
v.x,
|
||||||
|
v.y,
|
||||||
|
v.z,
|
||||||
|
)
|
||||||
end
|
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),
|
||||||
|
)
|
||||||
|
end
|
||||||
|
}
|
||||||
|
|
||||||
|
bmetatable = {
|
||||||
|
__name = "Block",
|
||||||
|
__index = Block,
|
||||||
|
}
|
||||||
|
|
||||||
|
local new_block = function (v1, v2)
|
||||||
|
return setmetatable(
|
||||||
|
{ v1 = v1, v2 = v2 },
|
||||||
|
bmetatable
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
---------------------- BASIC MOVEMENT ---------------------
|
||||||
|
|
||||||
function mineSides ()
|
function mineSides ()
|
||||||
if mode.mine.up then
|
if mode.mine.up then
|
||||||
turtle.digUp()
|
turtle.digUp()
|
||||||
|
|
@ -39,7 +110,6 @@ function moveInLine (delta)
|
||||||
end
|
end
|
||||||
|
|
||||||
function moveUpDown (delta)
|
function moveUpDown (delta)
|
||||||
local delta = delta
|
|
||||||
while delta > 0 do
|
while delta > 0 do
|
||||||
if mode.mine.forward then
|
if mode.mine.forward then
|
||||||
turtle.digUp()
|
turtle.digUp()
|
||||||
|
|
@ -78,47 +148,58 @@ function turnToFace (new_direction)
|
||||||
mode.facing = new_direction
|
mode.facing = new_direction
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function getCurrentPos()
|
||||||
|
return mode.v
|
||||||
|
end
|
||||||
|
|
||||||
-- move to a specific point
|
-- move to a specific point
|
||||||
function moveAbs (x, y, z)
|
function moveAbs (v)
|
||||||
-- print(string.format("Moving to (%d, %d, %d)", x, y, z))
|
-- print(string.format("Moving to (%d, %d, %d)", v.x, v.y, v.z))
|
||||||
move(x - mode.x, y - mode.y, z - mode.z)
|
move(v - getCurrentPos())
|
||||||
end
|
end
|
||||||
|
|
||||||
-- move relative to the turtle's current location
|
-- move relative to the turtle's current location
|
||||||
function move (x, y, z)
|
function move (v)
|
||||||
-- x
|
-- x
|
||||||
if x > 0 then
|
if v.x > 0 then
|
||||||
turnToFace(RIGHT)
|
turnToFace(RIGHT)
|
||||||
moveInLine(x)
|
moveInLine(v.x)
|
||||||
elseif x < 0 then
|
elseif v.x < 0 then
|
||||||
turnToFace(LEFT)
|
turnToFace(LEFT)
|
||||||
moveInLine(-x)
|
moveInLine(-v.x)
|
||||||
end
|
end
|
||||||
mode.x = mode.x + x
|
mode.v = mode.v + UNIT_X
|
||||||
-- z
|
-- z
|
||||||
if z > 0 then
|
if v.z > 0 then
|
||||||
turnToFace(FORWARD)
|
turnToFace(FORWARD)
|
||||||
moveInLine(z)
|
moveInLine(v.z)
|
||||||
end
|
end
|
||||||
if z < 0 then
|
if v.z < 0 then
|
||||||
turnToFace(BACK)
|
turnToFace(BACK)
|
||||||
moveInLine(-z)
|
moveInLine(-v.z)
|
||||||
end
|
end
|
||||||
mode.z = mode.z + z
|
mode.v = mode.v + UNIT_Z
|
||||||
-- y
|
-- y
|
||||||
moveUpDown(y)
|
moveUpDown(v.y)
|
||||||
mode.y = mode.y + y
|
mode.v = mode.v + UNIT_Y
|
||||||
end
|
end
|
||||||
|
|
||||||
function dropOffItems (go_back)
|
-------------- 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)
|
||||||
-- Turn off mining
|
-- Turn off mining
|
||||||
local mine_state = mode.mine
|
|
||||||
mode.mine = { forward = true }
|
mode.mine = { forward = true }
|
||||||
-- Note current position (assuming facing FORWARD)
|
-- Note current position (assuming facing FORWARD)
|
||||||
local pos_state = { x = mode.x, y = mode.y, z = mode.z }
|
local pos_state = vector.new(mode.v.x, mode.v.y, mode.v.z)
|
||||||
-- Return to origin, facing BACK
|
-- Return to origin, facing BACK
|
||||||
moveAbs(mode.x, mode.y, 0)
|
moveAbs(starting_point)
|
||||||
moveAbs(0, 0, 0)
|
moveAbs(V_ZERO)
|
||||||
turnToFace(BACK)
|
turnToFace(BACK)
|
||||||
-- deposit items
|
-- deposit items
|
||||||
for slot = 2, 16 do
|
for slot = 2, 16 do
|
||||||
|
|
@ -127,124 +208,102 @@ function dropOffItems (go_back)
|
||||||
end
|
end
|
||||||
turtle.select(1)
|
turtle.select(1)
|
||||||
-- Return to current position, facing forward
|
-- Return to current position, facing forward
|
||||||
if go_back then moveAbs(pos_state.x, pos_state.y, pos_state.z) end
|
if go_back then
|
||||||
-- Turn mining back on, if it was on
|
moveAbs(starting_point)
|
||||||
mode.mine = mine_state
|
moveAbs(pos_state)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function inventoryFull ()
|
function inventoryFull ()
|
||||||
-- leave a little extra space just in case
|
-- leave a little extra space just in case
|
||||||
return turtle.getItemCount(15) > 0
|
return turtle.getItemCount(FULL_CHECK_SLOT) > 0
|
||||||
end
|
end
|
||||||
|
|
||||||
function moveAndCheck (x, y, z)
|
function checkAndDropOff(starting_point)
|
||||||
move(x, y, z)
|
if inventoryFull() then dropOffItems(starting_point, true) end
|
||||||
if inventoryFull() then dropOffItems(true) end
|
|
||||||
refuelUntil(FUEL_RESERVE)
|
refuelUntil(FUEL_RESERVE)
|
||||||
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 }
|
|
||||||
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)
|
function mine (block)
|
||||||
-- fuel and go to starting corner
|
-- assumptions: block is mineable in a single pass and oriented to the
|
||||||
refuelUntil(FUEL_RESERVE)
|
-- currentPos
|
||||||
mode.mine = { forward = true }
|
-- rough algo draft:
|
||||||
moveAbs(block.x, block.y, block.z)
|
-- 1. go to "starting point" at one end of block
|
||||||
local z_dir
|
-- a. don't move vertically if you don't have to
|
||||||
if block.zoff > 1 then z_dir = 1 else z_dir = -1 end
|
-- b. set mining mode beforehand
|
||||||
local remaining_h = math.abs(block.z + block.zoff - mode.z) + 1
|
-- 2. move to the ending point
|
||||||
-- Initial pass; leave remaining_h at a nice multiple of 3
|
local height = block.v2.y
|
||||||
local excess = remaining_h % 3
|
if height % 3 == 0 then
|
||||||
if excess > 0 then
|
mode.mine = { up = true, forward = true, down = true }
|
||||||
minePlane(block.xoff, block.yoff, (excess - 1) * z_dir)
|
elseif height == 2 then
|
||||||
if excess == 1 then
|
mode.mine = { forward = true, up = true }
|
||||||
move(0, 0, -z_dir)
|
elseif height == -2 then
|
||||||
|
mode.mine = { forward = true, down = true }
|
||||||
end
|
end
|
||||||
remaining_h = remaining_h - excess
|
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
|
else
|
||||||
move(0, 0, z_dir)
|
return splitHorizontal(block)
|
||||||
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
|
||||||
end
|
end
|
||||||
|
|
||||||
function calculateBlock (x1, y1, z1, x2, y2, z2)
|
function process (stack, starting_point)
|
||||||
|
-- START code taken from `mine`
|
||||||
|
-- fuel and go to starting point
|
||||||
|
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)
|
||||||
|
else
|
||||||
|
local new, remainder = split(working, mode.v)
|
||||||
|
table.insert(stack, remainder)
|
||||||
|
table.insert(stack, new)
|
||||||
|
end
|
||||||
|
return process (stack)
|
||||||
|
end
|
||||||
|
|
||||||
|
function calculateBlock (v1, v2)
|
||||||
-- Using the coordinates, construct a block of certain dimensions, a
|
-- Using the coordinates, construct a block of certain dimensions, a
|
||||||
-- certain distance away.
|
-- certain distance away.
|
||||||
local block = {}
|
local block = {}
|
||||||
|
|
@ -260,30 +319,39 @@ function calculateBlock (x1, y1, z1, x2, y2, z2)
|
||||||
block[dim] = corner
|
block[dim] = corner
|
||||||
block[dim .. "off"] = offset
|
block[dim .. "off"] = offset
|
||||||
end
|
end
|
||||||
normalize("x", x1, x2)
|
normalize("x", v1.x, v2.x)
|
||||||
normalize("y", y1, y2)
|
normalize("y", v1.y, v2.y)
|
||||||
normalize("z", z1, z2)
|
normalize("z", v1.z, v2.z)
|
||||||
return block
|
return new_block(
|
||||||
|
vector.new(block.x, block.y, block.z)
|
||||||
|
vector.new(block.xoff, block.yoff, block.zoff)
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
function run (x1, y1, z1, x2, y2, z2)
|
function run (v1, v2)
|
||||||
local block = calculateBlock(x1, y1, z1, x2, y2, z2)
|
-- TODO calculate starting_point, the place turtle will move to before
|
||||||
mine(block)
|
-- moving to the first corner of block
|
||||||
|
local block = new_block(v1, v2 - v1)
|
||||||
|
process({ block })
|
||||||
-- return to base
|
-- return to base
|
||||||
mode.mine = {}
|
dropOffItems(starting_point)
|
||||||
dropOffItems()
|
|
||||||
turnToFace(FORWARD)
|
turnToFace(FORWARD)
|
||||||
end
|
end
|
||||||
|
|
||||||
function usage ()
|
function usage ()
|
||||||
print("Usage: mine x1 y1 z1 x2 y2 z2 OR mine x1 y1 z1")
|
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("Mine from the first set of coordinates to the second in a \
|
print("Mine from the first set of coordinates to the second in a \
|
||||||
rectangular prism.")
|
rectangular prism.")
|
||||||
print("The coordinates are relative to the facing of the turtle at the \
|
print("The coordinates are relative to the facing of the turtle at the \
|
||||||
start of the program.")
|
start of the program.")
|
||||||
print("If invoked with only three arguments, act as if they are the last \
|
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.")
|
three arguments and substitute 0 0 0 for the first three.")
|
||||||
print("Fuel goes in the top-left slot of the turtle's inventory")
|
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.")
|
||||||
end
|
end
|
||||||
|
|
||||||
function argsToNumbers ()
|
function argsToNumbers ()
|
||||||
|
|
@ -296,12 +364,14 @@ end
|
||||||
|
|
||||||
local arg = argsToNumbers()
|
local arg = argsToNumbers()
|
||||||
if #arg == 3 then
|
if #arg == 3 then
|
||||||
-- TODO make the 3 arg version the same as it used to be
|
run(V_ZERO, vector.new(arg[1], arg[2], arg[3]))
|
||||||
-- 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
|
elseif #arg == 6 then
|
||||||
run(arg[1], arg[2], arg[3], arg[4], arg[5], arg[6])
|
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)
|
||||||
else
|
else
|
||||||
usage()
|
usage()
|
||||||
end
|
end
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue