简体   繁体   中英

How do I implement a timer on each question asked in a quiz?

I was attempting to create a quiz and one of the criteria is to limit the time available to solve for each question in the quiz. I looked up certain tutorials but some require an input of x seconds for the timer to go off while others looked more like a stopwatch...

I was wondering how do I do like a background timer that ticks down as soon as the question is printed out and skips to the next question if, for example the 30-second period has ended? I'm clueless in the timer function and was having problems to even try to implement them onto my codes. Could someone give out a few pointers so I can sorta progress further in implementing a working timer?

Thank you!

EDITED section below: The timer that I want to implement onto my coding:

import time
import threading

def atimer():
    print("Time's up.")

a_timer = threading.Timer(10.0, atimer)
a_timer.start()
print("")

This is the whole coding that I tried to implement the timer into. I noticed that when I tried to define qtimer to just print 1 or 2 lines of statements the timer works but I want the timer to stop and go to second question or stop and give the user another attempt to retry the question, so I tried to attach a bunch of codes after the definition and it didn't work. I know I'm most probably doing something wrong here since I'm not quite familiar with time or threading functions. Is there a workaround?

def qtimer():
    print("I'm sorry but your time is up for this question.")
    print("You may have another attempt if you wish to, with reduced marks allocated.")
    response1 = input("Type 'Yes' for another attempt, anything else to skip: ")
    if response1 == "Yes":
        Answ = input("Which option would you go for this time?: ")
        Answ = int(Answ)
        if possible[Answ - 1] == qaItem.corrAnsw:
            print("Your answer was correct.")
            corr += 1
            marks += 0.5 * qaItem.diff
        else:
            print("Your answer was wrong.")
            print("Correct answer was: " + qaItem.corrAnsw)
            print("Explanation: " + qaItem.expl)
            print("")
    else:
        print("Correct answer was: " + qaItem.corrAnsw)
        print("Explanation: " + qaItem.expl)
        print("")

class A:
  def __init__(self, question, correctAnswer, otherAnswers, difficulty, explanation):
    self.question = question
    self.corrAnsw = correctAnswer
    self.otherAnsw = otherAnswers
    self.diff = difficulty
    self.expl = explanation

qaList = [A("What is COVID-19?", "Coronavirus Disease 2019", ["Wuhan virus", "I don't understand...", "Coronavirus Disease v19"], 1, "Explanation 1"),
A("What describes COVID-19?", "A disease", ["A virus", "A parasite", "A bacteriophage"], 1, "Explanation 2"),
A("What causes COVID-19?", "SARS-CoV-2", ["Coronavirus", "Mimivirus", "Rubeola Virus"], 1, "Explanation 3"),
A("Which of the following is used in COVID-19 treatment?", "Lopinavir / Ritonavir ", ["Midazolam / Triazolam", "Amiodarone", "Phenytoin"], 2, "Explanation 4"),
A("Which of the following receptors is used by COVID-19 to infect human cells?", "ACE-2 Receptors", ["ApoE4 Receptors", "TCR Receptors", "CD28 Receptors"], 3, "Explanation 5")]

corr = 0
marks = 0
random.shuffle(qaList)
for qaItem in qaList:
    q_timer = threading.Timer(5.0, qtimer)
    q_timer.start()
    print(qaItem.question)
    print("Possible answers are:")
    possible = qaItem.otherAnsw + [qaItem.corrAnsw]
    random.shuffle(possible)
    count = 0
    while count < len(possible):
        print(str(count+1) + ": " + possible[count])
        count += 1
    print("Please enter the number of your answer:")
    Answ = input()
    Answ = str(Answ)
    while not Answ.isdigit():
        print("That was not a number. Please enter the number of your answer:")
        Answ = input()
        Answ = int(Answ)
    Answ = int(Answ)
    while Answ > 4 or Answ < 1:
        print("That number doesn't correspond to any answer. Please enter the number of your answer:")
        Answ = input()
        Answ = int(Answ)
    if possible[Answ-1] == qaItem.corrAnsw:
        print("Your answer was correct.")
        corr += 1
        marks += 1 * qaItem.diff
    else:
        print("Your answer was wrong.")
        response = input("Would you want to try again? If so, input 'Yes' to attempt it again, if not just input whatever!")
        if response == "Yes":
            Answ = input("Which option would you go for this time?: ")
            Answ = int(Answ)
            if possible[Answ - 1] == qaItem.corrAnsw:
                print("Your answer was correct.")
                corr += 1
                marks += 0.5 * qaItem.diff
            else:
                print("Your answer was wrong.")
                print("Correct answer was: " + qaItem.corrAnsw)
                print("Explanation: " + qaItem.expl)
                print("")
        else:
            print("Correct answer was: " + qaItem.corrAnsw)
            print("Explanation: " + qaItem.expl)
            print("")

print("You answered " + str(corr) + " of " + str(len(qaList)) + " questions correctly.")
print("You have achieved a total score of " + str(marks) + ".")

Even with a timer, the main thread can't proceed past waiting for the user to input a number; so if the user doesn't nothing, the timer function runs, and once it has finished the main thread is still waiting for input at

print("Please enter the number of your answer:")
Answ = input() 

You could have a global flag that the timer thread sets to tell the main thread to treat the input received as response1 in the timer code, and also have a flag to tell the timer that an answer was received, and so on, and it quickly becomes rather complicated.

So rather than trying to work around the blocking call to input by communicating between the timer and main thread, take the non-blocking input example from https://stackoverflow.com/a/22085679/1527 and stop the loop early if the time is up.

def timed_input(msg, timeout=10):
    kb = KBHit()

    print(msg)

    end_time = time.time() + timeout
    warn_time = 5

    result = None

    while True:

        if kb.kbhit():
            c = kb.getch()
            if '0' <= c <= '9':
                result = int(c)
                break                
            print(c)

        if time.time() > end_time:
            print('time is up')
            break

        if time.time() > end_time - warn_time:
            print(f'{warn_time}s left')
            warn_time = warn_time - 1

    kb.set_normal_term()

    return result


# Test    
if __name__ == "__main__":
    result = timed_input('Enter a number between 1 and 4')
    if result is None:
        print('be quicker next time')
    elif 1 <= result <= 4:
        print('ok')
    else: 
        print(f'{result} is not between 1 and 4')

Note also that breaking up into smaller functions helps make the code easier to follow, the logic of the test doesn't need to know about the logic of the timeout.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM