Created
February 14, 2025 23:35
-
-
Save z1haze/651ff4be21d748ab0c705545b7dd8620 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- Aware turtle module that tracks location and provides movement methods | |
local Aware = {} | |
---Creates a new Aware turtle instance with location tracking and movement capabilities | |
---@return table instance A new turtle instance with the following methods: | |
--- | |
--- Movement Methods: | |
---@field forward fun(distance?: number, canDig?: boolean): boolean Move forward by specified distance | |
---@field back fun(distance?: number, canDig?: boolean): boolean Move backward by specified distance | |
---@field up fun(distance?: number, canDig?: boolean): boolean Move up by specified distance | |
---@field down fun(distance?: number, canDig?: boolean): boolean Move down by specified distance | |
---@field moveTo fun(x: number, y: number, z: number, f?: number, canDig?: boolean, order?: string): boolean Move to specific coordinates. order defaults to "yxz" | |
--- | |
--- Rotation Methods: | |
---@field turnLeft fun(): boolean Turn 90 degrees left | |
---@field turnRight fun(): boolean Turn 90 degrees right | |
---@field turnAround fun(): boolean Turn 180 degrees | |
---@field turnTo fun(n: number|string): boolean Turn to face direction. Accepts numbers 1-4 or strings "x", "-x", "z", "-z" | |
--- | |
--- Location Methods: | |
---@field getLocation fun(): table Returns current location {x: number, y: number, z: number, f: number} | |
--- | |
--- Checkpoint Methods: | |
---@field checkpoints table Checkpoint management | |
---@field checkpoints.points table[] Array of saved location checkpoints | |
---@field checkpoints.add fun() Save current location as checkpoint | |
---@field checkpoints.pop fun(): table|nil Remove and return last checkpoint | |
---@field checkpoints.removeLastN fun(n: number): table[] Remove last n checkpoints and return them | |
function Aware.create() | |
local instance = {} | |
-- Private state | |
local location = {x = 0, y = 0, z = 0, f = 1} | |
instance.checkpoints = { | |
points = {}, | |
add = function() | |
table.insert(instance.checkpoints.points, { | |
x = location.x, | |
y = location.y, | |
z = location.z, | |
f = location.f | |
}) | |
end, | |
pop = function() | |
if #instance.checkpoints.points > 0 then | |
return table.remove(instance.checkpoints.points) | |
end | |
return nil | |
end, | |
removeLastN = function(n) | |
if type(n) ~= "number" then | |
return false, "Invalid arguments. n must be a number" | |
end | |
-- Ensure we don't try to remove more elements than exist | |
local count = math.min(n, #instance.checkpoints.points) | |
local removed = {} | |
for _ = 1, count do | |
table.insert(removed, table.remove(instance.checkpoints.points)) | |
end | |
return removed | |
end | |
} | |
-- Get current location | |
function instance.getLocation() | |
return { | |
x = location.x, | |
y = location.y, | |
z = location.z, | |
f = location.f | |
} | |
end | |
--- =============================================================== | |
--- MOVEMENT METHODS | |
--- =============================================================== | |
local function move(direction, distance, canDig) | |
-- default direction | |
if not direction then | |
direction = "forward" | |
end | |
-- default distance of 1 | |
if not distance then | |
distance = 1 | |
end | |
-- ensure valid direction | |
if direction ~= "forward" and direction ~= "back" and direction ~= "up" and direction ~= "down" then | |
error("invalid direction") | |
end | |
-- for each distance | |
for _ = 1, distance do | |
-- attempt to move turtle in direction | |
while not turtle[direction]() do | |
local detectMethod = "detect" | |
local digMethod = "dig" | |
local attackMethod = "attack" | |
local fail = false | |
-- if direction is back we need to turn around and face that block | |
if direction == "back" then | |
turtle.turnLeft() | |
turtle.turnLeft() | |
end | |
-- update methods if up or down | |
if direction == "up" or direction == "down" then | |
detectMethod = detectMethod .. string.upper(string.sub(direction, 1, 1)) .. string.sub(direction, 2) | |
digMethod = digMethod .. string.upper(string.sub(direction, 1, 1)) .. string.sub(direction, 2) | |
attackMethod = attackMethod .. string.upper(string.sub(direction, 1, 1)) .. string.sub(direction, 2) | |
end | |
-- detect a block | |
if turtle[detectMethod]() then | |
if canDig then | |
-- dig the detected block | |
if not turtle[digMethod]() then | |
fail = true | |
end | |
else | |
-- fail because we dont have permission to dig the block | |
error("I need to dig, but I'm not allowed") | |
end | |
else | |
-- since we didnt move, and we didnt detect a block, and we're not out of fuel, must be some entity in the way, attack it! | |
turtle[attackMethod]() | |
end | |
if direction == "back" then | |
turtle.turnLeft() | |
turtle.turnLeft() | |
end | |
if fail then | |
return false | |
end | |
end | |
-- update stored location | |
if direction == "up" or direction == "down" then | |
location.y = direction == "down" and location.y - 1 or location.y + 1 | |
elseif direction == "forward" or direction == "back" then | |
if location.f == 1 then | |
location.z = direction == "back" and location.z + 1 or location.z - 1 | |
elseif location.f == 2 then | |
location.x = direction == "back" and location.x - 1 or location.x + 1 | |
elseif location.f == 3 then | |
location.z = direction == "back" and location.z - 1 or location.z + 1 | |
elseif location.f == 4 then | |
location.x = direction == "back" and location.x + 1 or location.x - 1 | |
end | |
end | |
os.queueEvent("location_updated") | |
end | |
return true | |
end | |
function instance.forward(distance, canDig) | |
return move("forward", distance, canDig) | |
end | |
function instance.back() | |
return move("back", distance, canDig) | |
end | |
function instance.up() | |
return move("up", distance, canDig) | |
end | |
function instance.down() | |
return move("down", distance, canDig) | |
end | |
local function moveToZ(z, canDig) | |
if location.z == z then | |
return true | |
end | |
if location.z < z then | |
instance.turnTo("z") | |
return instance.forward(z - location.z, canDig) | |
elseif location.z > z then | |
instance.turnTo("-z") | |
return instance.forward(location.z - z, canDig) | |
end | |
return false | |
end | |
local function moveToX(x, canDig) | |
if location.x == x then | |
return true | |
end | |
if location.x < x then | |
instance.turnTo("x") | |
return instance.forward(x - location.x, canDig) | |
elseif location.x > x then | |
instance.turnTo("-x") | |
return instance.forward(location.x - x, canDig) | |
end | |
return false | |
end | |
local function moveToY(y, canDig) | |
if instance.y == y then | |
return true | |
end | |
if instance.y < y then | |
return instance.up(y - instance.y, canDig) | |
elseif instance.y > y then | |
return instance.down(instance.y - y, canDig) | |
end | |
return false | |
end | |
function instance.moveTo(x, y, z, f, canDig, order) | |
if not order then | |
order = "yxz" -- Default movement order | |
end | |
if string.len(order) ~= 3 then | |
error("invalid order length") | |
end | |
-- Create a mapping for the coordinates | |
local coords = { | |
x = x, | |
y = y, | |
z = z | |
} | |
for i = 1, #order do | |
local char = order:sub(i, i) | |
local success | |
if char == "x" then | |
success = moveToX(coords[char], canDig) | |
elseif char == "y" then | |
success = moveToY(coords[char], canDig) | |
elseif char == "z" then | |
success = moveToZ(coords[char], canDig) | |
end | |
if not success then | |
return false | |
end | |
end | |
return instance.turnTo(f) | |
end | |
--- =============================================================== | |
--- ROTATION METHODS | |
--- =============================================================== | |
function instance.turnLeft() | |
if turtle.turnLeft() then | |
location.f = location.f == 1 and 4 or location.f - 1 | |
os.queueEvent("location_updated") | |
return true | |
end | |
return false | |
end | |
function instance.turnRight() | |
if turtle.turnRight() then | |
location.f = location.f == 4 and 1 or location.f + 1 | |
os.queueEvent("location_updated") | |
return true | |
end | |
return false | |
end | |
function instance.turnAround() | |
turtle.turnLeft() | |
location.f = location.f == 1 and 4 or location.f - 1 | |
turtle.turnLeft() | |
location.f = location.f == 1 and 4 or location.f - 1 | |
os.queueEvent("location_updated") | |
return true | |
end | |
function instance.turnTo(n) | |
-- for both relative and cardinal directions, these axis always map to correct values | |
if type(n) == "string" then | |
if n == "x" then | |
n = 2 | |
elseif n == "-x" then | |
n = 4 | |
elseif n == "-z" then | |
n = 1 | |
elseif n == "z" then | |
n = 3 | |
else | |
error("Invalid direction string. Must be x, -x, z, or -z") | |
end | |
end | |
if type(n) ~= "number" then | |
error("Invalid arguments. n must be a number") | |
end | |
-- if the calculated face is the same face the turtle is facing, just return | |
if n == location.f then | |
return false | |
end | |
local diff = location.f - n | |
while n ~= location.f do | |
if diff == 1 or diff == -3 then | |
turtle.turnLeft() | |
location.f = location.f == 1 and 4 or location.f - 1 | |
else | |
turtle.turnRight() | |
location.f = location.f == 4 and 1 or location.f + 1 | |
end | |
end | |
os.queueEvent("location_updated") | |
return true | |
end | |
return instance | |
end | |
return Aware |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment