| local component = require("component") |
| local computer = require("computer") |
| local robot = require("robot") |
| local shell = require("shell") |
| local sides = require("sides") |
| |
| if not component.isAvailable("robot") then |
| io.stderr:write("can only run on robots") |
| return |
| end |
| |
| local args, options = shell.parse(...) |
| if #args < 1 then |
| io.write("Usage: dig [-s] <size>\n") |
| io.write(" -s: shutdown when done.") |
| return |
| end |
| |
| local size = tonumber(args[1]) |
| if not size then |
| io.stderr:write("invalid size") |
| return |
| end |
| |
| local r = component.robot |
| local x, y, z, f = 0, 0, 0, 0 |
| local dropping = false -- avoid recursing into drop() |
| local delta = {[0] = function() x = x + 1 end, [1] = function() y = y + 1 end, |
| [2] = function() x = x - 1 end, [3] = function() y = y - 1 end} |
| |
| local function turnRight() |
| robot.turnRight() |
| f = (f + 1) % 4 |
| end |
| |
| local function turnLeft() |
| robot.turnLeft() |
| f = (f - 1) % 4 |
| end |
| |
| local function turnTowards(side) |
| if f == side - 1 then |
| turnRight() |
| else |
| while f ~= side do |
| turnLeft() |
| end |
| end |
| end |
| |
| local checkedDrop -- forward declaration |
| |
| local function clearBlock(side, cannotRetry) |
| while r.suck(side) do |
| checkedDrop() |
| end |
| local result, reason = r.swing(side) |
| if result then |
| checkedDrop() |
| else |
| local _, what = r.detect(side) |
| if cannotRetry and what ~= "air" and what ~= "entity" then |
| return false |
| end |
| end |
| return true |
| end |
| |
| local function tryMove(side) |
| side = side or sides.forward |
| local tries = 10 |
| while not r.move(side) do |
| tries = tries - 1 |
| if not clearBlock(side, tries < 1) then |
| return false |
| end |
| end |
| if side == sides.down then |
| z = z + 1 |
| elseif side == sides.up then |
| z = z - 1 |
| else |
| delta[f]() |
| end |
| return true |
| end |
| |
| local function moveTo(tx, ty, tz, backwards) |
| local axes = { |
| function() |
| while z > tz do |
| tryMove(sides.up) |
| end |
| while z < tz do |
| tryMove(sides.down) |
| end |
| end, |
| function() |
| if y > ty then |
| turnTowards(3) |
| repeat tryMove() until y == ty |
| elseif y < ty then |
| turnTowards(1) |
| repeat tryMove() until y == ty |
| end |
| end, |
| function() |
| if x > tx then |
| turnTowards(2) |
| repeat tryMove() until x == tx |
| elseif x < tx then |
| turnTowards(0) |
| repeat tryMove() until x == tx |
| end |
| end |
| } |
| if backwards then |
| for axis = 3, 1, -1 do |
| axes[axis]() |
| end |
| else |
| for axis = 1, 3 do |
| axes[axis]() |
| end |
| end |
| end |
| |
| function checkedDrop(force) |
| local empty = 0 |
| for slot = 1, 16 do |
| if robot.count(slot) == 0 then |
| empty = empty + 1 |
| end |
| end |
| if not dropping and empty == 0 or force and empty < 16 then |
| local ox, oy, oz, of = x, y, z, f |
| dropping = true |
| moveTo(0, 0, 0) |
| turnTowards(2) |
| |
| for slot = 1, 16 do |
| if robot.count(slot) > 0 then |
| robot.select(slot) |
| local wait = 1 |
| repeat |
| if not robot.drop() then |
| os.sleep(wait) |
| wait = math.min(10, wait + 1) |
| end |
| until robot.count(slot) == 0 |
| end |
| end |
| robot.select(1) |
| |
| dropping = false |
| moveTo(ox, oy, oz, true) |
| turnTowards(of) |
| end |
| end |
| |
| local function step() |
| clearBlock(sides.down) |
| if not tryMove() then |
| return false |
| end |
| clearBlock(sides.up) |
| return true |
| end |
| |
| local function turn(i) |
| if i % 2 == 1 then |
| turnRight() |
| else |
| turnLeft() |
| end |
| end |
| |
| local function digLayer() |
| --[[ We move in zig-zag lines, clearing three layers at a time. This means we |
| have to differentiate at the end of the last line between even and odd |
| sizes on which way to face for the next layer: |
| For either size we rotate once to the right. For even sizes this will |
| cause the next layer to be dug out rotated by ninety degrees. For odd |
| ones the return path is symmetrical, meaning we just turn around. |
| |
| Examples for two layers: |
| |
| s--x--x e--x--x s--x--x--x x--x x--x |
| | | | | | | | |
| x--x--x -> x--x--x x--x--x--x x x x x |
| | | | -> | | | | |
| x--x--e x--x--s x--x--x--x x x x x |
| | | | | | |
| e--x--x--x s x--x e |
| |
| Legend: s = start, x = a position, e = end, - = a move |
| ]] |
| for i = 1, size do |
| for j = 1, size - 1 do |
| if not step() then |
| return false |
| end |
| end |
| if i < size then |
| -- End of a normal line, move the "cap". |
| turn(i) |
| if not step() then |
| return false |
| end |
| turn(i) |
| else |
| turnRight() |
| if size % 2 == 1 then |
| turnRight() |
| end |
| for i = 1, 3 do |
| if not tryMove(sides.down) then |
| return false |
| end |
| end |
| end |
| end |
| return true |
| end |
| |
| repeat until not digLayer() |
| moveTo(0, 0, 0) |
| turnTowards(0) |
| checkedDrop(true) |
| |
| if options.s then |
| computer.shutdown() |
| end |