-- 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 -- 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 = { 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.") 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