My suspicion: I'm probably using the coroutines dead wrong. I apologize - I am learning. I've checked the lua tutorials on coroutine .. I think I understand the single-thread concept… I think I understand yield - but I haven't used it in my program because I assume sleep and turtle movements yield until completed (which I've concluded on my own during troubleshooting)
What is my application? My application is a replacement for the go application. I call it 'work'. Calling work f10 r2 f10 will cause the turtle to go forward 10, right 2 turns then forward 10 again. Alternative it can read the commands from a text file (although I haven't tested this functionality). Once I get it working I also plan to have an interactive "training" mode where I can input the commands one at a time and it'll record them to a text file. The aim is to walk a turtle through a process once (ie. tilling the field) .. then be able to recall and re-execute that process anytime in the future.
Other thoughts: I realize that one solution is to simply remove the coroutines and manually check for fuel - I can do that for sure, but I'd like to learn why its failing under this design. Also I am running ComputerCraft 1.5.2 on a Minecraft 1.5.1 server (which is running on an Ubuntu box in my livingroom) Other than the default Forge mods and ComputerCraft, no other mods are installed.
The Code: (Pastebin Link)
local fuelMatchSlot=16 -- Slot holding Fuel
local fuelMin = 10 -- Fuel leverl to trigger refuel
local fuelRefill = 50 -- Refuel to this amount
local seedMatchSlot=15 -- Slot holding Seed to plant
-- Determine Mode and start coroutines
function main( tArgs )
local fHandler
local cmds = ""
local coGo
local coFuel
local status
local yy
-- Verify Command Line Arguments were correct
if #tArgs < 1 then
print( "Usage: work <routefile> -or-" )
print( " work <command> <command> ... etc -or-")
print( " work program")
return false
end
if #tArgs == 2 and tArgs[1] == "program" then
interactiveMode(tArgs[2])
return
end
-- test if we have a filename or a command
if fs.exists(tArgs[1]) then
fileOrCmds = "file"
else
fileOrCmds = "cmds"
end
-- Read in our command list from the file
if fileOrCmds == "file" then
if fs.exists(tArgs[1]) then
fHandler = fs.open(tArgs[1],"r")
if fHandler then
cmds = fHandler.readAll
end
end
else -- Read in our commands from the command line
-- Convert from a table into a space separated list
for i,v in ipairs(tArgs) do
if cmds == "" then
cmds = v
else
cmds = cmds .. " " .. v
end
end
end
-- Create our Coroutines
coGo = coroutine.create(go)
coFuel = coroutine.create(fuelManager)
-- Continuously resume coroutines in sequence as they yield
while true do
-- Start/Resume our Go coroutine
yy = coroutine.resume(coGo,cmds)
if yy == false then
print("Coroutine Go Reports error")
print("Status: " .. coroutine.status(coGo))
end
-- If the coroutine has terminated, then exit our loop
if coroutine.status(coGo) == "dead" then
break
end
-- Start/Resume our Fuel coroutine
yy = coroutine.resume(coFuel)
if yy == false then
print("Coroutine Fuel Reports error")
print("Status: " .. coroutine.status(coFuel))
end
-- If the coroutine has terminated, then exit our loop
if coroutine.status(coFuel) == "dead" then
print("Out of Fuel")
break
end
end
return true
end
-- Interactive Mode
function interactiveMode(saveFile)
term.clear()
print("Welcome to Interactive Mode")
print("Instructions enter one command per line, followed by the enter key.")
print("The turtle will execute the instructions and the instructions will")
print("be recorded to the file '" .. saveFile .. "'.")
print("")
print("Enter the command 'end' to stop")
print("")
local fHandler = fs.open(saveFile,"a")
while true do
write("Command: ")
cmd = io.read()
if go(cmd) then
if string.lower(cmd) == "end" then
break
end
fHandler.writeLine(cmd)
end
end
fHandler.close()
end
-- Checks fuel status on predictable intervals
function fuelManager()
local currentFuelLevel = 0
local avgFuelConsumptionPerSecond = 1
local estFuelLife = 0
--- Keep this function active continously
while true do
--- Assess current Fuel Level
currentFuelLevel = turtle.getFuelLevel()
--- If fuel near Min level, then we need to refuel up to refuel level
if currentFuelLevel <= fuelMin then
return false
end
--- Calculate approximate time until earliest fuel low warning
estFuelLife = (currentFuelLevel * avgFuelConsumptionPerSecond)
--- Sleep for half that time (coroutine should yield here)
os.sleep(math.floor(estFuelLife/2))
end -- endless loop
end
-- Processes a series of instructions
function go(cmds)
local tArgs = { }
local cmd = ""
local nPos = 1
local nCmd = 1
local c = ""
-- Convert List of cmds into a table
while nPos < #cmds do
c = string.sub(cmds,nPos,nPos)
if c == " " then
if cmd ~= "" then
tArgs[nCmd] = cmd
cmd = ""
nCmd = nCmd + 1
end
else
cmd = cmd .. c
end
nPos = nPos + 1
end
if cmd ~= "" then
tArgs[nCmd] = cmd
end
-- If no commands were found in the table then exit
if #tArgs < 1 then
print("No arguments given to go")
return false
end
-- These are our defined handlers. Each handler is defined with a condition and an action.
-- before an action is executed, a condition must be met
-- successful actions, will deducated distance values.
-- Failed conditions or actions will set distance to 0
local tHandlers = {
-- Forward, Back, Up, Down
["F"] = { condition=function() return true end, action=turtle.forward },
["B"] = { condition=function() return true end, action=turtle.back },
["U"] = { condition=function() return true end, action=turtle.up },
["D"] = { condition=function() return true end, action=turtle.down },
-- Left, Right
["L"] = { condition=function() return true end, action=turtle.turnLeft },
["R"] = { condition=function() return true end, action=turtle.turnRight },
-- Dig Over, Dig uNder
["O"] = { condition=turtle.detect, action=turtle.digUp },
["N"] = { condition=turtle.detect, action=turtle.digDown },
-- Plant, Eject
["P"] = { condition=function() return not(turtle.detectDown()) end, action=plantSeed },
["E"] = { condition=function() return true end, action=dropExtras }
}
-- Iterate for each command present
local nArg = 1
local sCmd = ""
for nArg,sCmd in ipairs(tArgs) do
local nDistance = 1
-- Determine the Distance for the command
if #sCmd > 1 then
local num = tonumber(string.sub(sCmd, 2))
if num then
nDistance = num
else
nDistance = 1
end
else
nDistance = 1
end
sOperation = string.sub(sCmd,1,1)
-- Use the function handler that corresponds with the command
local fnHandler = tHandlers[string.upper(sOperation)]
if fnHandler then
-- Set our condition and action functions
local condition = fnHandler["condition"]
local action = fnHandler["action"]
-- Repeat based on distance
while nDistance > 0 do
local status = false -- whether condition and action both returned true
if condition() then
if action() then
status = true
end
else
status = true
end
-- If the action did not succeed, lets check some common reasons
if status == false then
-- Out of Fuel?
if turtle.getFuelLevel() == 0 then
print( "Out of fuel" )
return false
else
-- Best report his even though it may correct itself in half a second
print(string.upper(sOperation) .. " returned error")
sleep(0.5)
end
else -- action DID succeed, so lets reduce distance
nDistance = nDistance - 1
end
end -- while distance > 0
else -- if there was no valid function handler found ...
print( "No such Handler: " .. string.upper(sOperation) )
return false
end
end -- Process Next Command
return true
end
-- Finds a seed in our inventory and plants it
-- Should be clear that there needs to be an empty block below in order to properly plant
function plantSeed()
local slotNumber = 0
local itemCount = 0
local attempt = 0
local seedItem = false
for slotNumber=1,16 do
-- There is a goto command in the new beta Lua .. cannot wait
local skipIt = false
while skipIt == false do
skipIt = true
if (slotNumber ~= fuelMatchSlot) and (slotNumber ~= seedMatchSlot) then
-- See if there is any items in the slot
itemCount = turtle.getItemCount(slotNumber)
if itemCount == 0 then
-- goto skipIt
break
end
-- Select the Slot
while turtle.select(slotNumber) == false do
attempt = attempt + 1
if attempt == 3 then
print("Unable to Select Slot#" .. slotNumber)
return false
end
-- Lets wait - maybe it will clear up
-- We will only make 3 attemps though
sleep(5)
end
-- Compare it to our seed slot
seedItem = turtle.compareTo(seedMatchSlot)
if not seedItem then
-- goto skipIt
break
end
-- We found a seed item - lets plant it
if not turtle.placeDown() then
print("Could not place seed")
return false
end
end -- slot <> seedslot condition
end -- while
-- ::skipit::
end -- next slot number
return true
end
-- Drops all items that are "extra"
-- at the time of writing, that means anything not fuel or seed
function dropExtras()
local slotNumber = 0
local keepItem = false
local itemCount = 0
local attempt = 0
-- iterate through our slots
for slotNumber=1,16 do
-- Can remove these two lines when LUA gets a GOTO statement
local skipIt = false
while skipIt == false do
if (slotNumber ~= fuelMatchSlot) and (slotNumber ~= seedMatchSlot) then
-- See if there is any items in the slot
itemCount = turtle.getItemCount(slotNumber)
if itemCount == 0 then
-- goto skipIt
break
end
-- Select the Slot, give up after 3 attempts
while turtle.select(slotNumber) == false do
attempt = attempt + 1
if attempt == 3 then
print("Unable to Select Slot#" .. slotNumber)
return false
end
sleep(5)
end
-- Is it an extra?
keepItem = (turtle.compareTo(fuelMatchSlot) or turtle.compareTo(seedMatchSlot))
if keepItem then
-- goto skipIt
break
end
-- We found an extra item - lets drop it
turtle.dropDown()
end -- valid slot check
end -- while loop
-- :: skipIt ::
end -- next slot number
return true
end
function reFuel()
local slotNumber = 0
local fuelItem = false
local itemCount = 0
local attempt = 0
for slotNumber=1,16 do
-- Remove these two lines when LUA gets a goto statement
local skipIt = false
while skipIt == false do
skipIt = true
if not (slotNumber == fuelMatchSlot) then
-- See if there is any items in the slot
itemCount = turtle.getItemCount(slotNumber)
if itemCount == 0 then
-- goto skipIt
break
end
-- Select the Slot
while turtle.select(slotNumber) == false do
attempt = attempt + 1
if attempt == 3 then
print("Unable to Select Slot#" .. slotNumber)
return false
end
sleep(5)
end
-- Compare it to our fuel slot
fuelItem = turtle.compareTo(fuelMatchSlot)
if not fuelItem then
break
end
-- We found a fuel item - lets refuel to the refuel limit
while turtle.getFuelLevel() < fuelRefill do
-- Attempt to Refuel with one unit
attempt = 0
while turtle.refuel(1) == false do
attempt = attempt + 1
if attempt == 1 then
print("Unable to refuel from slot #" .. slotNumber)
end
if attempt == 3 then
break -- give up on this slot
end
os.sleep(1)
end
-- If this slot does not appear to refilling then skip the slot
if attempt == 3 then
break
end
-- Keep refueling until we reach our refill level
end -- While Refueling
end -- slot <> fuelslot condition
-- if we have refueled sufficiently, lets stop checking slots
if turtle.getFuelLevel() >= fuelRefill then
break
end
end -- end while loop
end -- next slot number
-- Return Refuel success
if turtle.getFuelLevel() < fuelRefill then
return false
else
return true
end
end
local tArgs = { ... }
main(tArgs)
print("Finished")
Any assistance would be appreciated. Thank you in Advance.