From 4f0876fb643f2302f196377b222e3bbf3ba231a5 Mon Sep 17 00:00:00 2001 From: Emerson Rosen-Jones Date: Mon, 1 Dec 2025 09:25:20 -0500 Subject: [PATCH] Start of mine.lua rewrite --- mine.lua | 336 +++++++++++++++++++++++++++++++------------------------ 1 file changed, 189 insertions(+), 147 deletions(-) diff --git a/mine.lua b/mine.lua index a3af8e8..c11955b 100644 --- a/mine.lua +++ b/mine.lua @@ -1,20 +1,81 @@ -- 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 +-- +x = right of start, +y = up of start, +z = forward 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 = { x = 0, y = 0, z = 0, facing = FORWARD } +local mode = { v = vector.new(0, 0, 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 +---------------------- 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) + -- TODO similar to "normalize" + error("not yet implemented") + 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 + end + 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 () if mode.mine.up then turtle.digUp() @@ -39,7 +100,6 @@ function moveInLine (delta) end function moveUpDown (delta) - local delta = delta while delta > 0 do if mode.mine.forward then turtle.digUp() @@ -78,47 +138,59 @@ function turnToFace (new_direction) mode.facing = new_direction end +function getCurrentPos() + return mode.v +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) +function moveAbs (v) + -- print(string.format("Moving to (%d, %d, %d)", v.x, v.y, v.z)) + move(v - getCurrentPos()) end -- move relative to the turtle's current location -function move (x, y, z) +function move (v) -- x - if x > 0 then + if v.x > 0 then turnToFace(RIGHT) - moveInLine(x) - elseif x < 0 then + moveInLine(v.x) + elseif v.x < 0 then turnToFace(LEFT) - moveInLine(-x) + moveInLine(-v.x) end - mode.x = mode.x + x + mode.v = mode.v + UNIT_X -- z - if z > 0 then + if v.z > 0 then turnToFace(FORWARD) - moveInLine(z) + moveInLine(v.z) end - if z < 0 then + if v.z < 0 then turnToFace(BACK) - moveInLine(-z) + moveInLine(-v.z) end - mode.z = mode.z + z + mode.v = mode.v + UNIT_Z -- y - moveUpDown(y) - mode.y = mode.y + y + moveUpDown(v.y) + mode.v = mode.v + UNIT_Y 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 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 } + local pos_state = vector.new(mode.v.x, mode.v.y, mode.v.z) -- Return to origin, facing BACK - moveAbs(mode.x, mode.y, 0) - moveAbs(0, 0, 0) + moveAbs(starting_point) + moveAbs(V_ZERO) turnToFace(BACK) -- deposit items for slot = 2, 16 do @@ -127,124 +199,83 @@ function dropOffItems (go_back) 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 + if go_back then + moveAbs(starting_point) + moveAbs(pos_state) + 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 + return turtle.getItemCount(FULL_CHECK_SLOT) > 0 end -function moveAndCheck (x, y, z) - move(x, y, z) - if inventoryFull() then dropOffItems(true) end +function moveAndCheck (v, starting_point) + move(v) + if inventoryFull() then dropOffItems(starting_point, 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 + -- TODO adjust for new paradigm + -- assumptions: block is mineable in a single pass + -- 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. refuel beforehand + -- 2. move to the ending point + -- 3. drop off items if necessary + move(start_v) + move(end_v) +end + +function canMine (block) + local notTooHigh = block.v2.y > 3 + -- we can only mine in a 1-wide strip at a time + local notTooWide = block.v2.x > 1 and block.v2.z > 1 + return not (tooHigh or tooWide) +end + +function splitHorizontal (block) + -- TODO make this less naive? + return block:take(1, "x") +end + +function split (block) + local tooHigh = function (block) + return block.v2.y > 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 + block = block:orient(getCurrentPos()) + if tooHigh(block) then + return block:take(3, "y") + else + return splitHorizontal(block) 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) + if canMine(working) then + 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 -- certain distance away. local block = {} @@ -260,30 +291,39 @@ function calculateBlock (x1, y1, z1, x2, y2, z2) block[dim] = corner block[dim .. "off"] = offset end - normalize("x", x1, x2) - normalize("y", y1, y2) - normalize("z", z1, z2) - return block + 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) + ) end -function run (x1, y1, z1, x2, y2, z2) - local block = calculateBlock(x1, y1, z1, x2, y2, z2) - mine(block) +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 }) -- return to base - mode.mine = {} - dropOffItems() + dropOffItems(starting_point) turnToFace(FORWARD) end 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 \ 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") + 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.") end function argsToNumbers () @@ -296,12 +336,14 @@ 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]) + run(V_ZERO, vector.new(arg[1], arg[2], arg[3])) 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 usage() end