Skip to content

Instantly share code, notes, and snippets.

@UlisseMini
Created August 9, 2019 22:14
Show Gist options
  • Save UlisseMini/0f6e6ff7047ab8edd8da9236ec5ba7e9 to your computer and use it in GitHub Desktop.
Save UlisseMini/0f6e6ff7047ab8edd8da9236ec5ba7e9 to your computer and use it in GitHub Desktop.
---------
-- Module for managing coordanites in opencomputers.
-- @module coords
-- @author Ulisse Mini
-- @license MIT
local r = require('robot')
--- The entire API lives in here.
local t = {}
--- Our current coordanites.
local c = {
x = 0, -- Current X
y = 0, -- Current Y
z = 0, -- Current Z
ori = 0, -- Current orientation, 0-3
}
-- The delta for different orientations.
local delta = {
[0] = function() c.z = c.z - 1 end,
[1] = function() c.x = c.x + 1 end,
[2] = function() c.z = c.z + 1 end,
[3] = function() c.x = c.x - 1 end
}
function t.turnRight()
r.turnRight()
c.ori = (c.ori + 1) % 4
end
function t.turnLeft()
r.turnLeft()
c.ori = (c.ori - 1) % 4
end
--- Create a new move function.
-- Afterwards the return value of moveFn will be returned.
-- @tparam function moveFn A function that returns a bool after moving the t.
-- @tparam function fn The function to be called if moveFn returns true.
local function move(moveFn, fn)
return function(...)
local b = moveFn(...)
if b then fn() end
return b
end
end
--- Move the r forward.
-- @treturn bool success
-- @function t.forward
t.forward = move(r.forward, function()
delta[c.ori]()
end)
--- Move the r backward.
-- @treturn bool success
-- @function t.back
t.back = move(r.back, function()
delta[(c.ori + 2) % 4]()
end)
--- Move the r upwards.
-- @treturn bool success
-- @function t.up
t.up = move(r.up, function() c.y = c.y + 1 end)
--- Move the r upwards.
-- if it succeeds, increment our y coordanite.
-- @treturn bool success
-- @function t.down
t.down = move(r.down, function() c.y = c.y - 1 end)
--- Needed for converting the orientation back and forth to strings.
-- if a key does not exist an error is thrown.
local oris = {
["north"] = 0,
["east"] = 1,
["south"] = 2,
["west"] = 3
}
--- Look a direction,
-- @param direction can be a string or number
-- if it is a string then it will be converted to a number based
-- on the oris table.
function t.look(direction)
if type(direction) == "string" then
if oris[direction] == nil then
error(direction .. ' is not in the orientations table')
end
direction = oris[direction]
end
-- Now we turn to the correct orientation
if direction == c.ori then return end
if (direction - c.ori) % 2 == 0 then
t.turnLeft()
t.turnLeft()
elseif (direction - c.ori) % 4 == 1 then
t.turnRight()
else
t.turnLeft()
end
end
--- Helper for t.moveTo,
-- move will be called, every time it fails
-- swing will be called until its return value is false.
local function moveWith(move, swing)
while not move() do
while swing() do end
end
end
--- Helper for t.moveTo. is the same as
-- moveWith(t.forward, r.swing)
local function moveForward()
moveWith(t.forward, r.swing)
end
--- Move to a set of coordanites.
-- TODO: More efficent, turns when it could just move back.
-- @tparam number xT Target X coordanite
-- @tparam number yT Target Y coordanite
-- @tparam number zT Target Z coordanite
-- @tparam number,string oriT orientation target [optional].
function t.moveTo(xT, yT, zT, oriT)
oriT = oriT or c.ori
-- check for nil arguments
if (not xT or not yT or not zT) then
error(
([[t.moveTo Invalid arguments
xT = %q (want number)
yT = %q (want number)
zT = %q (want number)
oriT = %q (want number or string)
]]):format(xT, yT, zT, oriT))
end
while yT < c.y do
moveWith(t.down, r.swingDown)
end
while yT > c.y do
moveWith(t.up, r.swingUp)
end
if xT < c.x then
t.look('west')
while xT < c.x do moveForward() end
end
if xT > c.x then
t.look('east')
while xT > c.x do moveForward() end
end
if zT < c.z then
t.look('north')
while zT < c.z do moveForward() end
end
if zT > c.z then
t.look('south')
while zT > c.z do moveForward() end
end
t.look(oriT)
end
t.c = c
return t
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment