Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Function running as a timer goes down?

I'm really new to programming and I'm trying to create a maths quiz for young children. They have to answer as many questions as they can in 60 seconds. I have a timer and a question generator

The problem is however, I cant get them to run at the same time, for example, the program waits for 1 second, asks a question, waits until the user has answered it, then carries on with the timer etc. I want the timer to keep going and not stop whilst the questions are being answered!

This is my timer:

timer = 5
time.sleep(1)
timer -= 1

And my questions are generated by by defining a variable (I've shortened it down to addition):

def questions():
    first_number = random.randint(1, 50)
    second_number = random.randint(1, 50)
    print("What is", first_number, "+", second_number,"?")
    answer = int(input("Answer: "))
    if answer == first_number + second_number:
        print("Correct!")
        addition_score += 1
    else:
        print("Wrong!")
like image 266
Tom Avatar asked Feb 28 '26 18:02

Tom


1 Answers

It's harder than it should be to interrupt an input(). Let's first focus on a simpler task: you want to call questions() repeatedly, until the total elapsed time is 60 seconds or more. You can do that by measuring the time with time.time(), which returns a number of seconds since... some random "time zero" --- it doesn't matter. Code:

start_time = time.time()                 # "now" at the start
while time.time() < start_time + 60:     # "not 60 seconds later"
    questions()

The trick is not to use time.sleep(): in technical terms, the input() call is already "blocking", and you can only have one blocking function running at the same time (unless you introduce threads or multiple processes, which is completely overkill here).

The last question, if answered correctly, will count as +1, even though it was answered after more than 60 seconds. It's possible to change this logic by having questions() return either True or False, and doing the score += 1 part only if it returned True and if there is still time left.

If you want to get really interrupted after exactly 60 seconds, it's slightly harder. Try for example signal.alarm(60) (not on Windows). It will deliver the signal "Alarm clock" after the given number of seconds. By default it kills the process; if you want to catch it and do something else, try to do in addition: signal.signal(signal.SIGALRM, signal.default_int_handler). It will simulate a Ctrl-C after 60 seconds, which you can catch using:

try:
    while True:   # infinite loop, until interrupted
        questions()
except KeyboardInterrupt:
    pass          # interrupted, now we're out of the loop

(No need for time.time() any more in this version.)

like image 196
Armin Rigo Avatar answered Mar 03 '26 07:03

Armin Rigo