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

Help with coroutines

Started by Micheal Pearce, 13 January 2016 - 07:57 PM
Micheal Pearce #1
Posted 13 January 2016 - 08:57 PM
I'm stumped with this one, I have no idea why but when I run this it keeps setting the var 'word' to 'time' and writing it abunch of times


gobal = _G
gobal.runningTerminal = true
function TermWrite(word,tm)
  while true do
	local x,y = term.getCursorPos()
	local g = 0
	local ostimer = os.startTimer(tm)
	local typing = true
	local count = 1
	while true do
	  e = { os.pullEvent(true) }
	  if e[1] == "timer" and e[2] == ostimer then
		term.setCursorPos(3,4)
		write(word)
		term.setCursorPos(x+g,y)
		write( string.sub(word,count,count) )
		ostimer = os.startTimer(tm)
		g = g + 1
		count = count + 1
		if count == #word then
		  break
		end
	  end
	end
	word = os.pullEvent(false)
  end
end
TerminalWrite = coroutine.create(TermWrite)
TW = coroutine.create(TermWrite)
e = {}
term.clear()
term.setCursorPos(1,1)
coroutine.resume(TerminalWrite,"Hello There!",1)
term.setCursorPos(1,2)
coroutine.resume(TW,"This is pretty Cool!",.01)
while true do
  g,b = coroutine.resume(TerminalWrite,unpack(e))
  f,j = coroutine.resume(TW,unpack(e))
  if not b then
	break
  end
  e = { os.pullEvent() }
end
Lupus590 #2
Posted 13 January 2016 - 09:27 PM
an event loop inside of an event loop, that just sounds like a disaster
worse: event loop in event loop in coroutine in eventloop
change those to coroutine.yield for readability

also os.pullEvent takes a sting parameter for the event to pull (discarding other event types), I have no idea what you think it is doing by passing it a boolean

http://www.computerc...ics-coroutines/

BB's first law of coroutines is "you probably don't need to be using coroutines"
Edited on 13 January 2016 - 09:15 PM
Micheal Pearce #3
Posted 13 January 2016 - 09:33 PM
os.pullEvent is basically just coroutine.yeild so when a pass the boolean though it, it comes out as var b in the main loop at the bottom and if its false it means it's stopped typing and if b is false then it breaks the loop ending the program
valithor #4
Posted 13 January 2016 - 10:11 PM

gobal = _G
gobal.runningTerminal = true
function TermWrite(word,tm)
  while true do
	local x,y = term.getCursorPos()
	local g = 0
	local ostimer = os.startTimer(tm)
	local typing = true
	local count = 1
	while true do
	  e = { os.pullEvent(true) }
	  if e[1] == "timer" and e[2] == ostimer then
		term.setCursorPos(3,4)
		write(word)
		term.setCursorPos(x+g,y)
		write( string.sub(word,count,count) )
		ostimer = os.startTimer(tm) --# Timer started here
		g = g + 1
		count = count + 1
		if count == #word then
		  break --# the loop breaks, but the timer is still running
		end
	  end
	end
	word = os.pullEvent(false) --# timer is what the event that gets pulled is, hence word getting set to "timer" (not time)
  end
end
TerminalWrite = coroutine.create(TermWrite)
TW = coroutine.create(TermWrite)
e = {}
term.clear()
term.setCursorPos(1,1)
coroutine.resume(TerminalWrite,"Hello There!",1)
term.setCursorPos(1,2)
coroutine.resume(TW,"This is pretty Cool!",.01)
while true do
  g,b = coroutine.resume(TerminalWrite,unpack(e))
  f,j = coroutine.resume(TW,unpack(e))
  if not b then
	break
  end
  e = { os.pullEvent() }
end

edit:

Notice the comments I did not actually change any of the actual code.
Edited on 13 January 2016 - 09:12 PM
Lupus590 #5
Posted 13 January 2016 - 10:16 PM
I think you may have replied while I was editing my post (sorry about that)

Wouldn't a slow write function in a coroutine be better?
Edited on 13 January 2016 - 09:19 PM
valithor #6
Posted 13 January 2016 - 10:22 PM
I think you may have replied while I was editing my post (sorry about that)

Wouldn't a slow write function in a coroutine be better?

Most likely yes. Textutils.slowWrite just uses timers anyway, so it should work perfectly fine, however he would still have the same problem. He is grabbing his timer event and treating it as if it were the thing he passed it. All he needs to get this to work is to just do a few checks when he pulls the event.
Micheal Pearce #7
Posted 13 January 2016 - 10:27 PM
Thank you for your help! I've added a check in the main loop so if b or j is false they stop running

and could I use textutils.slowWrite instead of this? remember I'm trying to write two lines at the same time
Lupus590 #8
Posted 13 January 2016 - 10:30 PM
you should use coroutine.status to see if your coroutine has ended - http://lua-users.org...outinesTutorial scroll down to simple usage

testutils.slowWrite would break if you run two at the same time, look at the print loop


--#textutils file
function slowWrite( sText, nRate )
	nRate = nRate or 20
	if nRate < 0 then
		error( "Rate must be positive", 2 )
	end
	local nSleep = 1 / nRate
		
	sText = tostring( sText )
	local x,y = term.getCursorPos(x,y)
	local len = string.len( sText )
	
	for n=1,len do
		term.setCursorPos( x, y ) --#move this line
		sleep( nSleep ) --#below this one to fix
		local nLines = write( string.sub( sText, 1, n ) )
		local newX, newY = term.getCursorPos()
		y = newY - nLines
	end
end
Edited on 13 January 2016 - 09:30 PM
Micheal Pearce #9
Posted 13 January 2016 - 10:48 PM
I couldn't use coroutine.status because of how I set it up so I could use it more than once, it would just return suspended and I wouldn't be able to tell where it suspended from
Bomb Bloke #10
Posted 14 January 2016 - 12:55 AM
Which is a good reason to change how you set it up, really.

As in most cases where you could use coroutines, it's easier to have the parallel API implement them for you:

local function TermWrite(word,tm)
	local x, y = term.getCursorPos()
	
	for i = 1, #word do
		term.setCursorPos(x + i - 1, y)
		term.write(word:sub(i, i))
		sleep(tm)
	end
end

parallel.waitForAll(
	function()
		term.setCursorPos(1,1)
		TermWrite("Hello There!",1)
	end,
	
	function()
		term.setCursorPos(1,2)
		TermWrite("This is pretty Cool!",.01)
	end)
Micheal Pearce #11
Posted 14 January 2016 - 01:11 AM
But I feel like it'd be better in the long run to use coroutines in my program because I'm gonna need to get input from other running programs while this is running
Bomb Bloke #12
Posted 14 January 2016 - 01:18 AM
The example provided IS using coroutines. It's simply handling the resuming via the parallel API.

If you really, really want to handle them directly within your own code, read through the example here. You can't simply resume your coroutines any time an event occurs - your coroutines are tolerant of that, but "regular scripts" you try to run within your manager will fail hard if you don't respect their filters.

I've also decided to finish writing my coroutine tutorial, as I've got a bit of spare time today. With any luck I'll have it done within a few hours.