So
Usage: go <list of commands>, where commands are mostly 1-char wide and sometimes have prefixes.
For example, `go f100` will move turtle forward for 100 blocks. And `go mflmam` will: mine block (dig), go forward, turn left, mine block, turn around and mine one more block, having 3 blocks mined in total. This utility is extremely handy for turtle micropositioning and it command language can be used in user programs.
Okay, let's look at command language.
1) Language is concatenative, commands are executed from left to right, unknown commands are ignored.
2) Basic moves:
- f b u d – move forward, backward, up and down respectivly
- l r a – turn left, turn right, turn around
3) Advanced moves
- F B U D – similar to f b u d, but will loop while block not detected. So `go F` will simply send turtle to the wall in front.
4) Digging (mining)
- m – mine block
- M – mine block until mined. This command is designed to mine gravel and sand, but it has 0.4s delay time.
- _m – mine block down
- ^m ^M – mine block up
You can also use >m for mining block in front or _M for mining down block, but there is little sense, in my opinion.
5) Placing
- >NUMBER – place block from slot NUMBER in front
- _NUMBER – place block from slot NUMBER down
- ^NUMBER – place block from slot NUMBER up
6) Loops
- commandNUMBER – repeat command NUMBER times. eg f100, r4.
- [commands]NUMBER – repeat list of commands NUMBER times. Eg [M^Mf]15 will dig 2-height tunnel of length 15
- [commands] – repeat commands while last command returns `true` (success). Command `go [fm]` will dig until emptyspace reached and then stop. Use this feature carefully, because of possible infinite loops
Loops support nesting. So, you can build block tower 2x2x10 with this command: `go [u[_1fl]4]10bD`. Last two chars will send turtle back to ground.
CODE v1 (canonical pastebin at http://pastebin.com/6aFnnJtx):
Spoiler
-- Block actions combinators v1 (go)
--
-- f b u d l r -- Move forward, backward, up, down, turn left, turn right
-- F B U D -- same moves, but move until block detected
-- m M -- mine block, mine blocks while block present (usefull for gravel mining)
-- [commands lastcommand] -- loop while lastcommand returns success
-- commandNUMBER -- loop command NUMBER times
-- [commands]NUMBER -- loop commands list NUMBER times
-- >DIGIT -- place block from DIGIT slot. When DIGIT == 0, place first available
-- ^DIGIT -- place block up
-- _DIGIT -- place block down
local tArgs = { ... }
if #tArgs ~= 1 then
print("Usage: go <list of commands>")
return
end
-- CAPS-letter commands evaluator, move-only
-- Remove code duplication by encapsulating common pattern in function
local function mdMove(command, detector)
while detector() == false do
command()
end
end
-- CAPS-letter commands evaluator, dig-only
-- Remove code duplication by encapsulating common pattern in function
local function mdDig(command, detector)
while detector() do
command()
sleep(0.4)
end
end
-- Evaluate prefix commands
local function runPrefixCmd(ch, digCmd, detectCmd, placeCmd)
local chCode = string.byte(ch, 1) - 48
if false then
elseif ch == 'm' then return true, digCmd()
elseif ch == 'M' then mdDig(digCmd, detectCmd); return true, false -- todo: better result return
elseif ch == '0' then return true, placeCmd()
elseif chCode > 0 and chCode < 10 then
turtle.select(chCode)
res = placeCmd()
return true, res
end
return false, false
end
-- Lua specific array length
local function lngth(lst)
if lst == nil then return 0 else return #lst end
end
local function parseNumber(st)
_, _, num, rest = string.find(st, "^(%d+)(.*)$")
return num, lngth(st) - lngth(rest)
end
local function parseLoop(st)
_, _, loop, rest = string.find(st, "^(%b[])(.*)$")
if loop ~= nil and loop ~= '' then
return loop:sub(2,-2), lngth(st) - lngth(rest)
elseif st:sub(1,1) == '[' then return nil, 1
else return nil, 0
end
end
function go(command)
local i = 1
local prevCommand = ''
local result = false
while i <= #command do
local ch = command:sub(i, i)
local nextCh = i == #command and '' or command:sub(i+1, i+1)
local number, nLen = parseNumber(command:sub(i))
local loop, lLen = parseLoop(command:sub(i))
-- if we found number, repeat last command number times
if number ~= nil then
number = tonumber(number)
while number > 1 do
go(prevCommand)
number = number - 1
end
i = i + nLen - 1
-- if we found loop, parse possible number and evaluate expression
elseif loop ~= nil then
local number, nLen = parseNumber(command:sub(i + lLen))
if number ~= nil then
number = tonumber(number)
while number > 0 do
go(loop)
number = number - 1
end
i = i + nLen
else
while go(loop) do end
end
i = i + lLen - 1
elseif ch == 'f' then result = turtle.forward()
elseif ch == 'b' then result = turtle.back()
elseif ch == 'u' then result = turtle.up()
elseif ch == 'd' then result = turtle.down()
elseif ch == 'F' then mdMove(turtle.forward, turtle.detect)
elseif ch == 'B' then go("aFa") -- this is not primitive
elseif ch == 'U' then mdMove(turtle.up, turtle.detectUp)
elseif ch == 'D' then mdMove(turtle.down, turtle.detectDown)
elseif ch == 'l' then turtle.turnLeft()
elseif ch == 'r' then turtle.turnRight()
elseif ch == 'a' then go("ll")
elseif ch == 'm' then result = turtle.dig()
elseif ch == 'M' then mdDig(turtle.dig, turtle.detect)
elseif ch == '>' then
local result1,result2 = runPrefixCmd(nextCh, turtle.dig, turtle.detect, turtle.place)
if result1 then
i = i + 1 -- todo: better prefix parsing
end
result = result2
elseif ch == '^' then
local result1,result2 = runPrefixCmd(nextCh, turtle.digUp, turtle.detectUp, turtle.placeUp)
if result1 then
i = i + 1
end
result = result2
elseif ch == '_' then
local result1,result2 = runPrefixCmd(nextCh, turtle.digDown, turtle.detectDown, turtle.placeDown)
if result1 then
i = i + 1
end
result = result2
end
prevCommand = ch
i = i + 1
end
return result
end
go(tArgs[1])
TODOs (todos will be done only on requests):
- Ctrl-C support
- Wireless support
- More usefull commands (what commands?)
- print runtime errors and warnings, print current iteration
- better help, more examples
- code cleanup
- bugs elimination
- position tracking
- pauseresume mode
- support new CC version (attacks, drops)