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

how to make that sleep() stop only a part of the program?

Started by bart74, 23 January 2014 - 03:13 PM
bart74 #1
Posted 23 January 2014 - 04:13 PM
hello,

I made a simple timer :

repeat
time=time-1
sleep(1)
until
time==0
but I can't put it into more advanced programs because the sleep don't stop only the timer,it stop the whole program
I'm making a simple quiz program :
Spoilerlocal function centerText(text)
local x,y = term.getSize()
local x2,y2 = term.getCursorPos()
term.setCursorPos(math.ceil((x / 2) - (text:len() / 2)), y2)
write(text)
end

time=10
calcmax=20
calc=0
result=0
while true do
shell.run("clear")

x=math.random(1,9)
y=math.random(1,9)

write("Il reste "..calcmax-calc.." calculs score : "..result.."/"..calcmax)
print("")
print("")

calc=calc+1
write(x.."+"..y.."=")
answer=tonumber(read())

z=x+y

if calc==calcmax then
shell.run("clear")
print("")
print("")
print("")
print("")
print("")
print("")
print("")
centerText(result.."/"..calcmax)
if result<calcmax/2 then
print("")
centerText("PERDU")
elseif result>=calcmax/2 then
print("")
centerText("GAGNE")
end
sleep(5)
shell.run("quiz")
end
if answer==quit then
shell.run("quiz")
end
if answer==z then
result=result+1
print("")
print("")
centerText("BRAVO!")
print("")
print("")
centerText("Appuyez sur une touche pour continuer")
os.pullEvent("key")
else
print("")
print("")
centerText("faux")
sleep(0.5)
print("")
print("")
print("la bonne réponse était "..z)
print("")
print("")
centerText("Appuyez sur une touche pour continuer")
os.pullEvent("key")
end
end
and I'd love to add a timer for it,the problem is if I add a timer,nothing will work until the timer reach 0
is there a way to make that sleep stop only a part of the program isntead of the whole one?
OReezy #2
Posted 23 January 2014 - 04:35 PM
You can create a timer and receive its end as an event. Here's a very basic code.
os.startTimer(5)  --Starts a 5 second timer
event = os.pullEvent()
if event == "timer" then
  print("Timer")
end

Here's an events tutorial as well.
CometWolf #3
Posted 23 January 2014 - 04:41 PM
You'll either have to split your program into looping functions and use the parallel api.
http://computercraft...allel_%28API%29
To simplify it's usage for you, when you call sleep in a function running in parallel, the funciton in question will sleep for the amount of time, while the other function executes, until it sleeps. This goes on and on, passing the control between the functions.

Or you can do it the way i prefer to do it, using coroutines. The parallel API is made from coroutines.
http://computercraft...utine_%28API%29
When using coroutines, you make a function and put coroutine.yield in the body of the function wherever you want it to stop. Then pass it to coroutine.create and it gives you a coroutine variable. Pass this variable to coroutine.resume and it will run the coroutine. When the running coroutine gets to coroutine.yield it will stop executing and pass control to the code block that called it.

local tRunning = {
  [1] = true,
  [2] = true
}
tTimer = {
  [1] = ""
  [2] = ""
}
local func1()
  while true do -- if the routine does not loop, it will be considered "dead" when it's done executing.
	print"derp1"
   tRunning[1] = false --coroutine complete, set the running variable to false to keep it yielding
	tTimer[1] = os.startTimer(20) --start rerun timer
	while not tRunning[1] do --check run variable
	  coroutine.yield()
	end
  end
end

local func2()
  while true do
	print"derp2"
   tRunning[2] = false
	tTimer[2] = os.startTimer(13)
	while not tRunning[2] do
	  coroutine.yield()
	end
  end
end

tCoroutine = { --create table containg coroutine variables
  [1] = coroutine.create(func1),
  [2] = coroutine.create(func2),
}

for i=1,#tCoroutine do
  coroutine.resume(tCoroutine[i]) -- start all coroutines in order at the start of the program
end

while true do
  local _e,tID = os.pullEvent"timer"
  for i=1,#tTimer do
	if tID == tTimer[i] then
	  coroutine.resume(tCoroutine[i])
	  break
	end
  end
end
Note that this is a pretty advanced way of doing things, you're probably better off finding a simpler way, cause i doubt this is required for your program to be honest.
bart74 #4
Posted 23 January 2014 - 04:59 PM
You can create a timer and receive its end as an event. Here's a very basic code.
os.startTimer(5)  --Starts a 5 second timer
event = os.pullEvent()
if event == "timer" then
  print("Timer")
end

Here's an events tutorial as well.
is there a way to make it write how much time left with this method or not?

You'll either have to split your program into looping functions and use the parallel api.
http://computercraft...allel_%28API%29
To simplify it's usage for you, when you call sleep in a function running in parallel, the funciton in question will sleep for the amount of time, while the other function executes, until it sleeps. This goes on and on, passing the control between the functions.

Or you can do it the way i prefer to do it, using coroutines. The parallel API is made from coroutines.
http://computercraft...utine_%28API%29
When using coroutines, you make a function and put coroutine.yield in the body of the function wherever you want it to stop. Then pass it to coroutine.create and it gives you a coroutine variable. Pass this variable to coroutine.resume and it will run the coroutine. When the running coroutine gets to coroutine.yield it will stop executing and pass control to the code block that called it.

local tRunning = {
  [1] = true,
  [2] = true
}
tTimer = {
  [1] = ""
  [2] = ""
}
local func1()
  while true do -- if the routine does not loop, it will be considered "dead" when it's done executing.
	print"derp1"
   tRunning[1] = false --coroutine complete, set the running variable to false to keep it yielding
	tTimer[1] = os.startTimer(20) --start rerun timer
	while not tRunning[1] do --check run variable
	  coroutine.yield()
	end
  end
end

local func2()
  while true do
	print"derp2"
   tRunning[2] = false
	tTimer[2] = os.startTimer(13)
	while not tRunning[2] do
	  coroutine.yield()
	end
  end
end

tCoroutine = { --create table containg coroutine variables
  [1] = coroutine.create(func1),
  [2] = coroutine.create(func2),
}

for i=1,#tCoroutine do
  coroutine.resume(tCoroutine[i]) -- start all coroutines in order at the start of the program
end

while true do
  local _e,tID = os.pullEvent"timer"
  for i=1,#tTimer do
	if tID == tTimer[i] then
	  coroutine.resume(tCoroutine[i])
	  break
	end
  end
end
Note that this is a pretty advanced way of doing things, you're probably better off finding a simpler way, cause i doubt this is required for your program to be honest.
OMG,it's possible to use that much lines of code for a simple timer?!
I were proud of my program,now it looks very simple… :(/>

edit : I found a way to print time with your method OReezy

time=10
repeat
time=time-1
os.startTimer(1)
event = os.pullEvent()
if event == "timer" then
  shell.run("clear")
  print(time)
end
until
time==0
thanks a lot :)/>

edit 2 : :(/> I tried to incorporate that code to my program but it has the same problem as the old one with sleep(1),the program won't do anything until the timer reach 0,should I use something else than "repeat until" that would make the same thing?
Edited on 23 January 2014 - 04:15 PM
CometWolf #5
Posted 23 January 2014 - 05:12 PM
Haha, what i posted above is an easily expandable multi tasker pretty much, based on timers instead of events. OReezy's suggestion is probably a lot more suited to your program.
bart74 #6
Posted 23 January 2014 - 05:28 PM
Haha, what i posted above is an easily expandable multi tasker pretty much, based on timers instead of events. OReezy's suggestion is probably a lot more suited to your program.
yeah,I'm trying to adapt his suggestion to my program,I just have to know how to use it… (and it's really hard,I can't find a way to make the timer don't block the whole program while it's running…)
CometWolf #7
Posted 23 January 2014 - 05:57 PM
don't do the repeat thing, just use another timer to time when to do other stuff.
OReezy #8
Posted 23 January 2014 - 07:38 PM
The solution I came up with is actually a combination of CometWolf's and my post. Try making two functions and running them together:
local function timer()
  os.startTimer(5)
  os.pullEvent("timer")
  print("Times Up!")
end

local function question()
  print("Whats the answer?")
  local ans = read()
  if ans == "answer" then
	print("Correct")
  else
	print("Incorrect")
  end
end

paralell.waitForAny(timer, question)

Whichever function receives an input first will execute. So if the user types something in then it will finish running question() and tell them if it is correct or not, but if the user waits too long the os.pullEvent("timer") will trigger from the timer created and that function will finish instead. There may be better ways to do it, but this is the simplest way I can think of.
bart74 #9
Posted 24 January 2014 - 06:36 AM
but my problem is that I want to write on the top right of the screen how much time left,as a countdown…
I just want to know if/how it's possible with your methods
but I think I understood how to use the paralell api,so I think I found an easy way to solve my problem,but I'm pretty sure that it won't work…
I'm trying it right now,I hope that it will works

edit : well,I added that to my program
local function timer()
time=10
repeat
time=time-1
os.startTimer(1)
event = os.pullEvent()
if event == "timer" then
  term.clearLine()
  term.setCursorPos(39,2)
  write("temps : 00:0"..time)
end
until
time==0
end
and I modified a little bit the rest of the program
local function question()
if calc==calcmax then
shell.run("clear")
print("")
print("")
print("")
print("")
print("")
print("")
print("")
centerText(result.."/"..calcmax)
if result<calcmax/2 then
print("")
centerText("PERDU")
elseif result>=calcmax/2 then
print("")
centerText("GAGNE")
end
sleep(5)
shell.run("quiz")
end
if answer==quit then
shell.run("quiz")
end
if answer==z then
result=result+1
print("")
print("")
centerText("BRAVO!")
print("")
print("")
centerText("Appuyez sur une touche pour continuer")
os.pullEvent("key")
else
print("")
print("")
centerText("faux")
sleep(0.5)
print("")
print("")
print("la bonne réponse était "..z)
print("")
print("")
centerText("Appuyez sur une touche pour continuer")
os.pullEvent("key")
end
end
end

paralell.waitForAny(timer, question)
and I don't know how,but it totally broken my program :(/>
have I done something wrong?
Spoiler

local function centerText(text)
local x,y = term.getSize()
local x2,y2 = term.getCursorPos()
term.setCursorPos(math.ceil((x / 2) - (text:len() / 2)), y2)
write(text)
end

calcmax=20
calc=0
result=0
while true do
shell.run("clear")

x=math.random(1,9)
y=math.random(1,9)

write("Il reste "..calcmax-calc.." calculs				   score : "..result.."/"..calcmax)
print("")

local function timer()
time=10
repeat
time=time-1
os.startTimer(1)
event = os.pullEvent()
if event == "timer" then
  term.clearLine()
  term.setCursorPos(39,2)
  write("temps : 00:0"..time)
end
until
time==0
end

print("")

calc=calc+1
write(x.."-"..y.."=")
answer=tonumber(read())

z=x-y

local function question()
if calc==calcmax then
shell.run("clear")
print("")
print("")
print("")
print("")
print("")
print("")
print("")
centerText(result.."/"..calcmax)
if result<calcmax/2 then
print("")
centerText("PERDU")
elseif result>=calcmax/2 then
print("")
centerText("GAGNE")
end
sleep(5)
shell.run("quiz")
end
if answer==quit then
shell.run("quiz")
end
if answer==z then
result=result+1
print("")
print("")
centerText("BRAVO!")
print("")
print("")
centerText("Appuyez sur une touche pour continuer")
os.pullEvent("key")
else
print("")
print("")
centerText("faux")
sleep(0.5)
print("")
print("")
print("la bonne réponse était "..z)
print("")
print("")
centerText("Appuyez sur une touche pour continuer")
os.pullEvent("key")
end
end
end

paralell.waitForAny(timer, question)
by broken,I mean that the timer is not rendered and that the program don't take care of you answer,and the 20 question limit no longer works too,I reached -9732/20 question
before,writting letters as an answer or putting no answer made you quit the quizz and get back to the menu but now,the only way to quit the program is ctrl+T
Edited on 24 January 2014 - 05:48 AM
OReezy #10
Posted 24 January 2014 - 03:25 PM
To add a function to print the time, change timer() to have a for loop that counts in reverse instead of os.pullEvent(). You would likely need to modify the question function to print in a specific place as well. It still functions the same as before though, which ever finishes first will execute the final bit of code.

local function timerNew()
  for i = 9,0,-1 do
	term.setCursorPos(1,1)
	print(i)
	term.setCursorPos(1,3)
	sleep(1)
  end
  print("Times up!")
end

PS: To make the timer start at 10, you would need to erase that line after the first count or print over it, otherwise it will look like this: 10, 90, 80, 70, 60.
bart74 #11
Posted 25 January 2014 - 08:09 AM
To add a function to print the time, change timer() to have a for loop that counts in reverse instead of os.pullEvent(). You would likely need to modify the question function to print in a specific place as well. It still functions the same as before though, which ever finishes first will execute the final bit of code.

local function timerNew()
  for i = 9,0,-1 do
	term.setCursorPos(1,1)
	print(i)
	term.setCursorPos(1,3)
	sleep(1)
  end
  print("Times up!")
end

PS: To make the timer start at 10, you would need to erase that line after the first count or print over it, otherwise it will look like this: 10, 90, 80, 70, 60.
thanks for your help but this timer has the same problem as others,it stop the whole program until it reach 0
or maybee it's just me that haveplaced it at a wrong place…

edit : yeah!!! I found a way using functions and parallel api,thanks a lot!!!

local function timerNew()
  for i = 9,0,-1 do
		term.setCursorPos(39,2)
		write("temps : 00:0"..i)
		term.setCursorPos(1,3)
		sleep(1)
  end

  centerText("TEMPS ECOULE!")
  print("")
  print("")
  print("la bonne réponse était "..z)
  print("")
  print("")
  centerText("Appuyez sur une touche pour continuer")
  os.pullEvent("key")
end

local function reponse()
calc=calc+1
write(x.."-"..y.."=")
answer=tonumber(read())
z=x-y
end

calcmax=20
calc=0
result=0
while true do
shell.run("clear")

x=math.random(1,9)
y=math.random(1,9)

write("Il reste "..calcmax-calc.." calculs				   score : "..result.."/"..calcmax)

parallel.waitForAny(reponse,timerNew)
Edited on 25 January 2014 - 07:25 AM
bart74 #12
Posted 25 January 2014 - 08:54 AM
Spoilerlocal function centerText(text)
local x,y = term.getSize()
local x2,y2 = term.getCursorPos()
term.setCursorPos(math.ceil((x / 2) - (text:len() / 2)), y2)
write(text)
end

local function timerNew()
for i = 9,0,-1 do
term.setCursorPos(39,2)
write("temps : 00:0"..i)
term.setCursorPos(1,3)
sleep(1)
end

centerText("TEMPS ECOULE!")
print("")
print("")
print("la bonne réponse était "..z)
print("")
print("")
centerText("Appuyez sur une touche pour continuer")
os.pullEvent("key")
end

local function reponse()
calc=calc+1
term.setCursorPos(1,3)
write(x.."-"..y.."=")
term.setCursorPos(5,3)
answer=tonumber(read())
z=x-y
end

calcmax=20
calc=0
result=0
while true do
shell.run("clear")

x=math.random(1,9)
y=math.random(1,9)

write("Il reste "..calcmax-calc.." calculs score : "..result.."/"..calcmax)

parallel.waitForAny(reponse,timerNew)

if calc==calcmax then
shell.run("clear")
print("")
print("")
print("")
print("")
print("")
print("")
print("")
centerText(result.."/"..calcmax)
if result<calcmax/2 then
print("")
centerText("PERDU")
elseif result>=calcmax/2 then
print("")
centerText("GAGNE")
end
sleep(5)
shell.run("quiz")
end
if answer==quit then
shell.run("quiz")
end
if answer==z then
result=result+1
print("")
print("")
centerText("BRAVO!")
print("")
print("")
centerText("Appuyez sur une touche pour continuer")
os.pullEvent("key")
else
print("")
print("")
centerText("faux")
sleep(0.5)
print("")
print("")
print("la bonne réponse était "..z)
print("")
print("")
centerText("Appuyez sur une touche pour continuer")
os.pullEvent("key")
end
end
not it got a timer,but I get a weird crash when the timer reach 0
parallel:22:quiz_-:19:attempt to concatenate string and nil
it's weird because it worked fine for 3 or 4 times,but now,I get this crash
I haven't modified anything
CometWolf #13
Posted 25 January 2014 - 09:35 AM
Not really that weird, it will happen if you let the timer run out.

print("la bonne réponse était "..z)
z is not defined, thus attempt to concatenate string and nil