This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
GamerNebulae's profile picture

Pausing A Program Using Coroutine Api

Started by GamerNebulae, 18 November 2013 - 11:13 AM
GamerNebulae #1
Posted 18 November 2013 - 12:13 PM
Hello everyone!

I was in my mine today and I am using a simple branching program (link here: http://pastebin.com/TjELb1rj) and the program is working like a charm. Now is a negative side effect that you can really fall far behind if the branch contains alot of ores.

Now is my question: Is there any way to stop the turtle (for example pressing spacebar) to pause the program and if I press spacebar again to let it continue? Could you give me a script example? It would be really appreciated :)/>
Edited on 19 November 2013 - 02:30 AM
ardera #2
Posted 18 November 2013 - 12:45 PM
My implementation of a pause functionality would be like that:

local pause = false
local runprogram = true
local pausekey = 123 -- I don't know the post key id
function programloop()
while runprogram do
  while not pause do -- do stuff when the program is not paused, you can replace this with anything, only the sleep(0) is important
   sleep(0)
  
   -- do turtle stuff
  
  end
  while pause do
   sleep(0)
  end
end
end
function waitforspace()
while runprogram do
  while not pause do
   local ev = {os.pullEvent("key")}
   if ev[2] == pausekey then
    pause = true
    break
   end
  end
  while pause do
   local ev = {os.pullEvent("key")}
   if ev[2] == pausekey then
    pause = false
    break
   end
  end
end
end
parallel.waitForAny(waitforspace, programloop)
GamerNebulae #3
Posted 18 November 2013 - 02:47 PM
My implementation of a pause functionality would be like that:

local pause = false
local runprogram = true
local pausekey = 123 -- I don't know the post key id
function programloop()
while runprogram do
  while not pause do -- do stuff when the program is not paused, you can replace this with anything, only the sleep(0) is important
   sleep(0)
  
   -- do turtle stuff
  
  end
  while pause do
   sleep(0)
  end
end
end
function waitforspace()
while runprogram do
  while not pause do
   local ev = {os.pullEvent("key")}
   if ev[2] == pausekey then
	pause = true
	break
   end
  end
  while pause do
   local ev = {os.pullEvent("key")}
   if ev[2] == pausekey then
	pause = false
	break
   end
  end
end
end
parallel.waitForAny(waitforspace, programloop)

Can you maybe go through the waitForSpace part step by step so I can maybe personalize it to my likings and understand it?
jay5476 #4
Posted 18 November 2013 - 03:40 PM

function waitforspace() --# make another function to run along side to wait for a pause key
while runprogram do --# this is here so even while paused this will still run
  while not pause do --# if it is not paused continue
   local ev = {os.pullEvent("key")} --# capture a key press
   if ev[2] == pausekey then --# see if key was pause key
		pause = true --# pause program
		break
   end
  end
  while pause do --# if its paused run this loop because of the runprogram loop still running
   local ev = {os.pullEvent("key")} --# capture a key press
   if ev[2] == pausekey then --# see if key is pause key
		pause = false --#unpause it
		break
   end
  end
end
end
Edited on 18 November 2013 - 02:40 PM
Bomb Bloke #5
Posted 18 November 2013 - 05:08 PM
You might consider using os.queueEvent() here. The idea is that your "programloop" function periodically checks to see if "pause" is true, then if it IS, rather then sleep(0)'ing over and over again flat out, it waits for a custom event type that you'll create when the program unpauses.

Eg:

local pause,runprogram = false,true

function programloop()
  while runprogram do
    if pause then os.pullEvent("unpause") end

    -- Perform turtle tasks.
  end
end

function waitforspace()
  local ev
  while runprogram do
    ev = {os.pullEvent("key")}
    if ev[2] == keys.space then pause = not pause end
    if not pause then os.queueEvent("unpause") end
  end 
end

parallel.waitForAny(waitforspace, programloop)

Depending on the structure of your current program, you may need to insert multiple checks to see if it should "pause".
Lyqyd #6
Posted 18 November 2013 - 06:04 PM
Instead of the above suggestions, you should create a program that manages the actual program in a coroutine. It would watch the events coming through, and when it saw the space key event come through, it would stop resuming the program, and keep track of any other events it received in a table, until it got the space key again. Then it would play back the stored events (so as not to miss any turtle movement events, but maybe you only want to store those and no others, up to you) and then resume cycling events into the controlled coroutine as usual. Trying to use parallel for this is like trying to put a square peg in a round hole.
GamerNebulae #7
Posted 19 November 2013 - 03:30 AM
Instead of the above suggestions, you should create a program that manages the actual program in a coroutine. It would watch the events coming through, and when it saw the space key event come through, it would stop resuming the program, and keep track of any other events it received in a table, until it got the space key again. Then it would play back the stored events (so as not to miss any turtle movement events, but maybe you only want to store those and no others, up to you) and then resume cycling events into the controlled coroutine as usual. Trying to use parallel for this is like trying to put a square peg in a round hole.

Could you maybe give an example, Lyqyd?
Lyqyd #8
Posted 19 November 2013 - 11:06 AM
You might give this a shot. Save it as something like "pauseable", then run `pauseable myProgram` if your program's name is "myProgram".


local eventsCache = {}
local args = {...}
if #args < 1 then
  print("Usage:"
  print(fs.getName(shell.getRunningProgram()).." <program> [arguments]")
  return
end

local co = coroutine.create(function() shell.run(unpack(args)) end)
local paused = false
local event = {}
local filter

local function resume(ev)
  if coroutine.status(co) == "dead" then return false end
  if not filter or (filter and filter == ev[1]) or ev[1] == "terminate" then
    ret, filter = coroutine.resume(unpack(ev))
    return ret
  end
  return "skipped"
end

while true do
  if not paused then 
    if not resume(event) then return end
  else
    table.insert(eventCache, event)
  end
  event = {os.pullEventRaw()}
  if event[1] == "char" and event[2] == " " then
    paused = not paused
    if not paused then
    for i = 1, #eventCache do
      resume(table.remove(eventCache, 1))
    end
  end
end