Threading Timer for a Quiz game - python

I have to do some exercises in my university with Python.So I need to build a quiz game. And the requirements are:
Right answer get +1 point.
Wrong answer get -1 point
The player has to answer each question in 20 seconds. If the player answers with more than 20 seconds, he gets -1 point even his answer is correct.
I just tried with threading and Timer. My code is like this:
from time import *
import threading as th
score = 0
correct_answer = 1
def sctn():
global score
score -=1
print(score)
S = th.Timer(20.0, sctn)
S.start()
answer = int(input("enter : "))
if answer == correct_answer :
score += 1
else:
score -= 1
print(score)
S.cancel()
I set an example for the correct answer. But when I run the code, if I type the correct answer more than 20 seconds, after that the score = -1 + 1 = 0, or if I type the wrong answer more than 20 seconds, the score = -1 -1 = -2.

You have too much code. There are two cases: if the user has entered the correct answer in 20 seconds or less, he gets a point; otherwise he loses one.
The timer function doesn't need to do anything. When you test for the correct answer, you can also test to see if the timer has expired. Timer is a subclass of Thread, therefore it has an function is_alive that returns True if it's still running.
The problem with your original program is that once the timer expires, the answer doesn't matter any more. But you check it anyway, so the -1 point from the timer function gets added to the plus or minus 1 from the answer-checking logic.
from time import *
import threading as th
score = 0
correct_answer = 1
def sctn():
pass
S = th.Timer(20.0, sctn)
S.start()
answer = int(input("enter : "))
if answer == correct_answer and S.is_alive():
score += 1
else:
score -= 1
S.cancel()
print(score)

You can use the after method of tkinter to start a timer when a question is shown, and deduct a score if the user hasn't responded in time. If the user responds in time you can call after_cancel with the return value of after to cancel the job.
For example, when you want to start the timer you would do something like this:
def start_timer():
global after_id
root.after(20000, times_up)
This assumes you have a global variable named root which refers to the root window. Though, you can use any widget for this. What it does is instruct tkinter to call the function times_up in 20 seconds (20,000 milliseconds)
In that function you can reduce the score by one, for example:
def times_up():
global score
score += 1
Then, in the code that processes the user picking an answer, you can stop the timer and prevent the score from doing down:
def user_picked_an_answer():
global after_id
root.after_cancel(after_id)
If this function is called when the user picks an answer, it will compute the new score as well as prevent the timer from ever triggering.

Related

Confused over a python concept as a beginner who has only started learning cs. Any help would be really appreciated

I've been stuck with something which has really halted my learning process as someone who has just started learning cs
Suppose I get an output score every turn in an iteration and the score for every turn is a random number ranging from 1 to 15
Now for every turn I want to print whether the score jump in that respective term is the biggest score jump in ALL of the turns played yet. It won't print anything if it isn't the biggest jump in score yet
I just can't seem to wrap my head around executing something like this and it has put everything I have to learn after it to a halt
#This is the function where I try to define the highest point for the score in this function-
def highest_gain(previous_value, highest_point) :
def say(score0) :
if previous_value == 0:
print ('Biggest gain by player0 yet with',score0,'points!')
return highest_gain(score0, score0)
gain = score0 - previous_value
if gain > highest_point:
print('Biggest gain by player0 yet with',score0,'points!')
return highest_gain(score0, gain)
return say
#This is the function for updating the score every turn and then call it with below-
while n > 0:
score += random.randint(1, 15)
f = say(score)
n -= 1
return score
score0(6,0,highest_gain(0,0))
Any help on this would be really appreciated🙏 . This has been bugging me for a few days now. I just can't seem to understand why the values inside of highest_gain can't remain updated after every turn they are executed.
This does what you ask, but I suspect what you need is not what you asked for.
import random
highest = 0
def score0(n):
global highest
score = 0
for i in range(n):
bump = random.randint(1, 15)
if bump > highest:
highest = bump
print('Biggest gain by player0 yet with',bump,'points!')
score += bump
return score
score0(6)

Is there a way to not give a point if they get it wrong the first time, quiz, python

I am new to python and am doing a basic quiz. I'm running into a problem for scoring.
trials = 3
for i in range(trials):
ans_2 = ansTwo()
results.append(ans_2)
if ans_2 in ('c','C'):
print("Good Job",name)
score+=1
break
else:
remaining = trials-i-1
s = '' if remaining == 1 else 's'
print("Oops Try Again? [{0} Chance{1} Remaining]".format(remaining, s))
This is my code and I'm trying to make it that if they do not get the answer the first time they do not get any points, but if they get the answer the first time they get a point.
Just add an if statement before score += 1 that checks if the loop is running for the first time. In your case:
if i == 0:
score += 1

Coin Acceptor With Python Timer

I'm having trouble figuring out this code. I am currently making a script in python where a it's kind of how an arcade machine works when you have 30 seconds to continue and you can insert more coins to go again. The trouble I'm having is I cant get the coins to count up while the timer counts down. Here is my code so far:
while True:
start = GPIO.input(startBtn)
input_state = GPIO.input(counterPin)
if input_state == False:
coins += 1
print(str(coins) + "¢ inserted")
time.sleep(0.09)
if coins == 100:
coins -= 100
creditss += 1
print("You currently have: " +str(creditss) + " credits")
timer = creditss * 5
if start == False:
if creditss > 0:
print("You have: " +str(timer) + " minutes to play!")
print("Have Fun!")
x = timer
for i in range(x + 1):
time.sleep(1)
print(formatTime(x))
x -= 1
timer -= creditss * 5
creditss = 0
if timer == 0:
pause()
timer += 30
print("Continue? : Insert more money to keep playing!")
x = timer
if input_state == False:
coins += 1
print(str(coins) + "¢ inserted")
time.sleep(0.09)
else:
for i in range(x + 1):
time.sleep(1)
print(formatTime(x))
x -= 1
if coins == 100:
coins -= 100
creditss += 1
print(creditss)
if creditss > 0 & timer != 0:
print("Good")
pause()
else:
print("exit")
os.system('/home/pi/exit.sh')
Thanks for any help!
Okay...the best help I can give you is this:
At this point you need to refactor your code. When you get a program with more than two - three levels of nesting (you have four if statements nested) then you should be defining functions and splitting out different parts of your program into logical chunks. This makes debugging easier, as you can drop I/O print statements to see where your script is failing.
To help you know what to split out first - look for sections where you're repeating yourself. If you type it more than once, it deserves its own function (DRY Principle - Don't repeat yourself).
for example you have:
if coins == 100:
coins -= 100
creditss += 1
print("You currently have: " +str(creditss) + " credits")
timer = creditss * 5
and
if coins == 100:
coins -= 100
creditss += 1
print(creditss)
This functionality is extremely similar and can likely be split off into a function. The other thing you want to think about: You only want /one/ part of the program to be able to change the number of coins so that you know when you're calling it what's happening (explicit is better than implicit). That should be a function and anything that needs to operate it can call it. The easier your program is to read, the easier it will be to debug. At least until you get issues that silently fail.
The sleep function stops execution, so during countdown every time you sleep you stop checking the GPIO state for a whole second and then just check it once more until sleeping again for another second. For this strategy to work you need to be checking your input very fast as to not miss a fast event. My guess is that checking once every one second is probably not enough for what you are doing.
A sightly better solution would be to not sleep and to use time.clock() to check when the play time has ended. So when the game starts you store the current value of time.clock() and after that you continue checking it until enough time has elapsed. There could still be an input which unsets and sets your input pin faster your loop can detect it so it's not bulletproof.
I don't have experience with python on raspberry-pi but a quick google search shows me there are GPIO.add_event_detect() and GPIO.add_event_callback() functions which can be set up so a callback function is called on a GPIO pin state change, which I would guess relies on interrupts so that you wouldn't miss an event. It could be a good idea to look into that.

making basic python counter with keyboard input

This probably sounds stupid but I can't seem to make a basic counter. Basically I need it to have two real time inputs, keyboard 'f' for positive points, keyboard 'j' for negative points, then I need one more input 'q' to stop the iteration and then print how many times f and j keys were pressed respectively.
edit: Okay this is frustrating. I searched around more to find out that for real time input I need msvcrt module, I used Windows so no problem. But, it still doesn't do anything, the code just runs and exit, nothing happens.
Here is what I want to do:
1. Run the code.
2. Open up a freestyle video in background.
3. Press the j and f key on the keyboard respectively in real time to count the freestyle score, it's based on clicks, positive points (j) and negative points (f).
4. Video ends, I press q to print how many times I pressed j and f key.
import msvcrt
def counter():
negative = 0
positive = 0
while True:
score = input("input starts:")
if msvcrt.getch() == "f":
negative += 1
print(negative)
if msvcrt.getch() == "j":
positive +=1
print(positive)
if msvcrt.getch() == "q":
print ("positive", positive)
print ("negative", negative)
break
There are plenty of issue, but here are a few pointers.
Instead of num = num + 1 - use num +=1
Define your counters before incrementing them.
Move your input inside the loop, or else it's going to use the first input over and over and just run through the entire loop with one input.
def counter():
end=1
negative = 0
positive = 0
while end <= 1000:
end += 1
score = input("input here:")
if score == "f":
negative += 1
print(negative)
if score == "j":
positive +=1
print(positive)
if score == "q":
print ("positive", positive)
print ("negative", negative)
break
counter()
You have to define positive and negative outside the while loop to keep the changes made to these variables during each iteration. E.g. like so:
def counter():
score = input("input here:")
end=1
positive = 0
...
There's a small typo in positive==positive+1. I think you meant positive=positive+1 (comparison vs. assignment)
The general syntax of your counter is correct though if you want something to be running in the background and are operating outside of the console then you need something like pyHook. getch() wont work in this situation.
from pyHook import HookManager
from win32gui import PumpMessages, PostQuitMessage
class Keystroke_Watcher(object):
def __init__(self):
self.hm = HookManager()
self.hm.KeyDown = self.on_keyboard_event
self.hm.HookKeyboard()
def on_keyboard_event(self, event):
try:
if event.KeyID == keycode_youre_looking_for:
self.your_method()
finally:
return True
def your_method(self):
pass
def shutdown(self):
PostQuitMessage(0)
self.hm.UnhookKeyboard()
watcher = Keystroke_Watcher()
PumpMessages()
that will detect the keypress and then you can increment the values. Of course you'll need to extrapolate the code but the framework is all there for you to be successful.

Setting timer in Python

Hey guys I'm doing a program in python. It's a calculation program which gives you two random number from 2 to 10, and then asks you for example how much is 2 * 4.
And if your answer is correct it gives you a point. Now, I want that the program let's the user calculate for 20secs and when 20secs are over, it will show you how much points you have.
My code so far ->
__author__ = 'Majky'
import random
import time
a = random.randint(2, 10)
b = random.randint(2, 10)
print("How much is", a, "times", b)
t = 0
odg = int(input("Answer ?"))
sec = 0
while sec < 20:
if odg == a * b:
print("Correct")
t = +1
print("Incorrect")
print("Your points are", t)
You are going to want to use threading, and open a parallel thread that will calculate that time (maybe by using time.sleep()) and return once done, once it returns, the main thread will stop execution and return the results.
Using sleep() in the main program will just pause execution for that time, which is not what you want from what I understand. You want the user to be able to interact with the program while the timer is running. That is what using threads from the threading module will allow you to do.
Here is a quick example of the use of threading (adjust it if you need anything specific):
import random
import time
def main():
thread_stop = threading.Event()
thread = threading.Thread(target=user_thread, args=(2, thread_stop))
time.sleep(20)
thread_stop.set()
def user_thread(arg1, stop_event):
t = 0
while(not stop_event.is_set()):
a = random.randint(2, 10)
b = random.randint(2, 10)
print("How much is", a, "times", b)
odg = int(input("Answer ?"))
if odg == a * b:
print("Correct")
t += 1
else:
print("Incorrect")
print("Your points are", t)
main()
Here is also an example using signals that stops the user in the middle of an answer if the 20 seconds are up and counts the results. This example uses signals, which is in itself an interesting module to control execution flow, you should check its documentation when you get a chance. I also realized there was another error in your code which I overlooked and has been corrected now in both examples, when you want to increase "t", use "t+=1", since "t=+1" is incorrect, the last expression is just assigning "positive" one to t every time, so is not increased. Cheers!
import signal
t = 0
#Here we register a handler for timeout
def handler(signum, frame):
#print "Time is up!"
raise Exception("Time is up.")
#function to execute your logic where questions are asked
def looped_questions():
import random
global t
while 1:
#Here is the logic for the questions
a = random.randint(2, 10)
b = random.randint(2, 10)
print("How much is", a, "times", b)
odg = int(input("Answer ?"))
if odg == a * b:
t += 1
print("Correct")
else:
print("Incorrect")
#Register the signal handler
signal.signal(signal.SIGALRM, handler)
#Set the timeout
signal.alarm(20)
try:
looped_questions()
except Exception, exc:
print exc
#Here goes the results logic
print("Your points are", t)
Also, don't forget to add to that sanity checks so that invalid user input doesn't break your code. I will leave that to you ;)
You could use the time.sleep(20) function to wait 20 seconds.
This function suspend execution for the given number of seconds. The argument may be a floating point number to indicate a more precise sleep time.
The actual suspension time may be less than that requested because any caught signal will terminate the sleep() following execution of that signal’s catching routine. Also, the suspension time may be longer than requested by an arbitrary amount because of the scheduling of other activity in the system.
you could do something like this, using time.time().
import time
...
start = time.time()
answer = raw_input('enter solution')
finish = time.time()
if finish - start > 20:
#failure condition
else:
#success condition

Categories

Resources