From 4e2532375367f294d49c2c9e9bed2eaf542c4fbe Mon Sep 17 00:00:00 2001 From: Emerson Rosen-Jones Date: Thu, 17 Jul 2025 23:05:32 -0400 Subject: [PATCH] first canonical version of miner script --- mine.lua | 314 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 314 insertions(+) create mode 100644 mine.lua diff --git a/mine.lua b/mine.lua new file mode 100644 index 0000000..1265810 --- /dev/null +++ b/mine.lua @@ -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