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

Countdown

Started by svdragster, 17 April 2013 - 05:40 AM
svdragster #1
Posted 17 April 2013 - 07:40 AM
Hello,

I've already read every tutorial about the Parallel API, but I still don't really get it to work.

I simply want a countdown to print a number at the bottom left, and in the meantime I can do other stuff with os.pullEvent().
Like a quiz where you have to choose an answer before the time is up.

Can someone give me a good example or do I have to use something different than the Parallel API?
Sariaz #2
Posted 17 April 2013 - 07:49 AM
I can try and explain the parallel api. First you have to make your two or more functions that you want to run simultaneously. Then you have a line that looks like parallels.waitForAny(func1,func2). func one and two are the names not the actual function. So for a function like timer() you would do timer not in quotes. This is the name of the function so no quotes because those make string not function and not parenthesize because they make it run that function instead of letting parallels deal with running it. If you use the parenthesis only the first function will run. As for the difference between waitForAny and waitForAll the first will cancel all functions when one finishes. so if I have a function thats a timer and one that gets user input it will run the user input function but when the timer finishes that function will end ending the user input function and continue executing code that comes after the parallel.whatever line. Hope this helps if you need more help ill keep checking this post.
Bubba #3
Posted 17 April 2013 - 07:52 AM
Better not to use the parallel api for this one. Just use timers and timer events.


local time = 100
local function drawCountdown()
  term.setCursorPos(1,1)
  term.clearLine()
  term.write("Time left: "..time)
  time = time - 1
end

local timer = os.startTimer(1)
while true do
  local e = {os.pullEvent()}
  if e[1] == "timer" then
    drawCountdown()
    timer = os.startTimer(1)
  elseif e[1] == "key" then
    --Do other stuff
  end
end

For some reason everybody insists on using the parallels API: it is not necessary. I have yet to find a circumstance where I need the parallel API over just basic events.
svdragster #4
Posted 17 April 2013 - 07:59 AM
text

Thanks for the explanation! I tried it like this, but maybe I can fix something.
Sariaz #5
Posted 17 April 2013 - 08:00 AM
For some reason everybody insists on using the parallels API: it is not necessary. I have yet to find a circumstance where I need the parallel API over just basic events.

This is true but in some situations much easier to use parallels. Unless you can think of easy way to get rednet input and wait for a monitor_touch event and not go back to start of loop until you get monitor touch event but while still geting rednet signals constantly. You could do it with another loop inside when your waiting for monitor event that works like that as to not go back to main loop, but makes code look messier to me and more confusing so i used parallels for that.
Goof #6
Posted 17 April 2013 - 08:01 AM
well.. now before i saw the other guys, posting their information, i coded a nice little countdown program for you…

Edit: but as Bubba said, you dont always need the parallel.. my code, was just an example of what you wanted. :P/>

Spoiler


local timeLeft = 60 -- seconds
local inMinutes= false -- turn to true, to get timeLeft in minuts (default timeleft will then be 60 minutes or 1 hour)
local active = true -- when stopping counter, turn this variable to false

function countDown() -- quick countdown function
	if inMinutes then
		timeLeft = timeLeft * 60 -- calculates into Minutes.
	end
	while timeLeft >= 0 do
		if active then
			term.setCursorPos(1,19) -- set cursor position to bottom left
			term.clearLine() -- clears the line
			write(timeLeft .. " Seconds remaining!") -- write time left.

			timeLeft = timeLeft - 1 -- subtracts the time left by 1
			sleep(1) -- sleeps one second, per subtraction
		else
			timeLeft = 0 -- when doing this, the while loop quits
		end		
	end
end

parallel.waitForAny(countDown, yourQuiz) -- parallel. input your function name, for your


but.. im sorry for that late answer.

I hope i could help
svdragster #7
Posted 17 April 2013 - 08:05 AM
Better not to use the parallel api for this one. Just use timers and timer events.


local time = 100
local function drawCountdown()
  term.setCursorPos(1,1)
  term.clearLine()
  term.write("Time left: "..time)
  time = time - 1
end

local timer = os.startTimer(1)
while true do
  local e = {os.pullEvent()}
  if e[1] == "timer" then
	drawCountdown()
	timer = os.startTimer(1)
  elseif e[1] == "key" then
	--Do other stuff
  end
end

For some reason everybody insists on using the parallels API: it is not necessary. I have yet to find a circumstance where I need the parallel API over just basic events.

How can I get the x and y position of a mouse click then?
Goof #8
Posted 17 April 2013 - 08:06 AM

local event, button, x, y = os.pullEvent("mouse_click")
print(x .. " " .. y)

EDIT: or in bubba's case:

local timer = os.startTimer(1)
while true do
  local e = {os.pullEvent()}
  if e[1] == "timer" then
        drawCountdown()
        timer = os.startTimer(1)
  elseif e[1] == "key" then
        --Do other stuff
  end
print(e[3] .. " " .. e[4]) -- <- prints the x and y chordinates of the click
end
svdragster #9
Posted 17 April 2013 - 08:14 AM
Thanks for everyone ^^

Helped me a lot.
Bubba #10
Posted 17 April 2013 - 09:36 AM
For some reason everybody insists on using the parallels API: it is not necessary. I have yet to find a circumstance where I need the parallel API over just basic events.

This is true but in some situations much easier to use parallels. Unless you can think of easy way to get rednet input and wait for a monitor_touch event and not go back to start of loop until you get monitor touch event but while still geting rednet signals constantly. You could do it with another loop inside when your waiting for monitor event that works like that as to not go back to main loop, but makes code look messier to me and more confusing so i used parallels for that.

The main reason I dislike the parallels API is because it is not optimized as a regular pullEvent. You are essentially switching back and forth between functions whenever one function yields. Why do that when you can react only upon a single event? Inefficiency is very important to me.

As to your point about needing loops within loops to check for a rednet message or some such thing, I would argue that such is not the case.


local needMessage = false
while true do
  local e = {os.pullEvent()}
  if e[1] == "mouse_click" then
    needMessage = true
  elseif e[1] == "rednet_message" and needMessage then
    print("Hey you hit the monitor and I needed a message")
    needMessage = false
  end
end
Sariaz #11
Posted 17 April 2013 - 09:43 AM

local needMessage = false
while true do
  local e = {os.pullEvent()}
  if e[1] == "mouse_click" then
	needMessage = true
  elseif e[1] == "rednet_message" and needMessage then
	print("Hey you hit the monitor and I needed a message")
	needMessage = false
  end
end

This would not do what i need i have something run at start of loop that isnt os.pullEvent and then after that it waits until a monitor_touch but doesnt run that begining bit until got monitor_touch and during this whole time get rednet msges and do stuff with them
Bubba #12
Posted 17 April 2013 - 10:43 AM

local needMessage = false
while true do
  local e = {os.pullEvent()}
  if e[1] == "mouse_click" then
	needMessage = true
  elseif e[1] == "rednet_message" and needMessage then
	print("Hey you hit the monitor and I needed a message")
	needMessage = false
  end
end

This would not do what i need i have something run at start of loop that isnt os.pullEvent and then after that it waits until a monitor_touch but doesnt run that begining bit until got monitor_touch and during this whole time get rednet msges and do stuff with them

Well first off, I can't really understand what you are saying. But if you are saying what I think you are then:

1) You run something, perhaps a draw function at the start of a loop if and only if a monitor_touch event has been received
2) The loop waits until it receives a monitor_touch and then runs the draw function?
3) During that time it receives rednet messages.

Well here is how you could easily go about that.

local status = false
while true do
  if status then
    doFunc() --Do your function
  end
  local e = {os.pullEvent()}
  if e[1] == "monitor_touch" then
    status = true
  elseif e[2] == "rednet_message" then
    --handle that
  end
end

What part of this does not work for your situation? Does the function it runs have sleep or take time to complete? If so, then you could still modify the code to use timers instead.

My point is not that you should never use parallels. For some purposes it is well suited. I am just arguing that, no matter the situation, there is a way to use regular events instead of parallels.
Sariaz #13
Posted 17 April 2013 - 10:47 AM
Yes and that would work my main point was that parallels can be used to help brake up code to make easier to read and understand. We both have good points and think we got sidetracked with proving our points a little :P/>
Bubba #14
Posted 17 April 2013 - 10:51 AM
Yes and that would work my main point was that parallels can be used to help brake up code to make easier to read and understand. We both have good points and think we got sidetracked with proving our points a little :P/>

True enough. Sorry, I can get defensive when it comes to programming practices. I'm very set in my ways xD
Sariaz #15
Posted 17 April 2013 - 10:59 AM
Yes and that would work my main point was that parallels can be used to help brake up code to make easier to read and understand. We both have good points and think we got sidetracked with proving our points a little :P/>

True enough. Sorry, I can get defensive when it comes to programming practices. I'm very set in my ways xD

Same only as a perfectionist at heart its about pretty much everything XD :P/>
TheOddByte #16
Posted 18 April 2013 - 11:51 AM
Better not to use the parallel api for this one. Just use timers and timer events.


local time = 100
local function drawCountdown()
  term.setCursorPos(1,1)
  term.clearLine()
  term.write("Time left: "..time)
  time = time - 1
end

local timer = os.startTimer(1)
while true do
  local e = {os.pullEvent()}
  if e[1] == "timer" then
	drawCountdown()
	timer = os.startTimer(1)
  elseif e[1] == "key" then
	--Do other stuff
  end
end

For some reason everybody insists on using the parallels API: it is not necessary. I have yet to find a circumstance where I need the parallel API over just basic events.
Just one question.. Why didn't you use a do this for countdown instead?

local function drawCountdown()
 for i = 60 , 1, -1 do --This is much simpler instead of doing time = time - 1, And as you can see it counts down from 60
  term.setCursorPos(1,1)
  term.clearLine()
  term.write("Time left: "..i)
end

local timer = os.startTimer(1)
while true do
  local e = {os.pullEvent()}
  if e[1] == "timer" then
	drawCountdown()
	timer = os.startTimer(1)
  elseif e[1] == "key" then
	--Do other stuff
  end
end

I always prefeer those loops since you can do so much with 'em
Sariaz #17
Posted 18 April 2013 - 11:58 AM
@Hellkid98 He did it his way because while your for loop is running the code is stopped and so events aren't being pulled.
P.S. you need a sleep(1) in your for loop
TheOddByte #18
Posted 18 April 2013 - 12:02 PM
@Hellkid98 He did it his way because while your for loop is running the code is stopped and so events aren't being pulled.
P.S. you need a sleep(1) in your for loop
Well… I know this for a fact now… I shall never post when I'm tired :P/>
And ooops.. I did it again
Sariaz #19
Posted 18 April 2013 - 12:04 PM
@Hellkid98 He did it his way because while your for loop is running the code is stopped and so events aren't being pulled.
P.S. you need a sleep(1) in your for loop
Well… I know this for a fact now… I shall never post when I'm tired :P/>
And ooops.. I did it again

Np yesterday even though I wasn't tiered I typed in sleep("1") instead of sleep(1) :P/>
Skampi #20
Posted 19 April 2013 - 05:52 AM
Better not to use the parallel api for this one. Just use timers and timer events.


local time = 100
local function drawCountdown()
  term.setCursorPos(1,1)
  term.clearLine()
  term.write("Time left: "..time)
  time = time - 1
end

local timer = os.startTimer(1)
while true do
  local e = {os.pullEvent()}
  if e[1] == "timer" then
	drawCountdown()
	timer = os.startTimer(1)
  elseif e[1] == "key" then
	--Do other stuff
  end
end

For some reason everybody insists on using the parallels API: it is not necessary. I have yet to find a circumstance where I need the parallel API over just basic events.

Couldn't you just use


local time = 100 -- the time you want to count down from

for time = time, 1, -1 do

 term.setCursorPos(1,1)
  term.clearLine()
  term.write("Time left: "..time)
  sleep(1)
end

Sariaz #21
Posted 19 April 2013 - 06:29 AM
Better not to use the parallel api for this one. Just use timers and timer events.


local time = 100
local function drawCountdown()
  term.setCursorPos(1,1)
  term.clearLine()
  term.write("Time left: "..time)
  time = time - 1
end

local timer = os.startTimer(1)
while true do
  local e = {os.pullEvent()}
  if e[1] == "timer" then
	drawCountdown()
	timer = os.startTimer(1)
  elseif e[1] == "key" then
	--Do other stuff
  end
end

For some reason everybody insists on using the parallels API: it is not necessary. I have yet to find a circumstance where I need the parallel API over just basic events.

Couldn't you just use


local time = 100 -- the time you want to count down from

for time = time, 1, -1 do

term.setCursorPos(1,1)
  term.clearLine()
  term.write("Time left: "..time)
  sleep(1)
end


He also wants to pullEvents at the same time its counting down.
Alerith #22
Posted 19 April 2013 - 07:12 AM
I made this for your cause, is quite simply, I don't know if it works for a rednet connection but is a countdown in a few lines:


local tm = 100
repeat
term.setCursorPos(1,1)
term.clear()
write("Remaining time: "..tm)
tm = tm - 1
sleep(1)
until tm == 0
Sariaz #23
Posted 19 April 2013 - 07:25 AM
It does not need to be rednet specifically. It just needs to be able to pull events while counting down, like Bubba's does, if you can find a better way to do that then Bubba's code that would be best way to help. Good counter though just has no way to get events while running it.