Break a Input when the Time is up - python

I am making a project where users are asked to enter multiple input within a stipulated time.
This is what I Tried:
import time
import threading
def timer():
global sec
sec =21
while sec != 0:
sec -= 1
time.sleep(1)
print("Seconds left:",sec)
print("\nTime Over")
def ask_words():
while sec >0:
#Ask Question#
timer = threading.Thread(target = timer)
timer.start()
ask_words()
Output:
This is the output
Problem: After the time is up I can add the last input after which the code is getting completed because the code(input) is executed after which the sec variable is becoming Zero so the program is waiting for the user to enter something. I don't know how to fix it.

Related

Using two different functions at the same time in python

import time
import random
def timer():
correct = 1
x = 0
while correct != 2:
time.sleep(0.1)
x = x + 0.1
def round1():
numb = random.randint(1, 100)
print(numb)
timer()
ans = input(">")
if ans == numb:
correct = 2
x = round(x)
print("you did that in", x ,"seconds!")
round1()
I was trying to get both functions to run together (have the game playing and the timer going in the background) but as soon as the timer started it would let me continue the game.
In the given program, I have created two different functions that will work at the same time. I have used threading to create thread of functions and sleep to limit the printing speed. In similar manner you can use game and timer function together.
from threading import Thread
from time import sleep
#sleep is used in functions to delay the print
#the below functions has infinite loop that will run together
#defining functions
def func1():
for x in range(20):
sleep(1)
print("This is function 1.")
def func2():
for x in range(10):
sleep(2)
print("This is function 2.")
#creating thread
thread1=Thread(target=func1)
thread2=Thread(target=func2)
#running thread
thread1.start()
thread2.start()

How to stop 'enter spamming' in a python reaction timer

I have been trying to make a reaction timer for a project to test reaction times. It uses 'perf_counter' to record the times before and after an input to test how long it takes to press the enter key. The issue is that the enter key can be spammed which makes it seem if they have a reaction time of 0.000001 seconds. I have made a class which disables the keyboard and enables it when I want. Even in that case, people are able to sneak in extra enter presses between the disables and enables. I have attached the code below. Any ideas how to prevent enter spamming?
import time, random, msvcrt
from math import log10, floor
def round_sig(x, sig=5):
return round(x, sig-int(floor(log10(abs(x))))-1)
class keyboardDisable():
def start(self):
self.on = True
def stop(self):
self.on = False
def __call__(self):
while self.on:
msvcrt.getwch()
def __init__(self):
self.on = False
import msvcrt
disable = keyboardDisable()
disable.start()
print('When I say __GO__ you hit ENTER! This will happen 3 times. Got it?')
time.sleep(2)
print('Ready')
time.sleep(1)
print('Steady')
time.sleep(random.randint(2,5))
print('#####__GO__######')
disable.stop()
tic = time.perf_counter()
a = input()
toc = time.perf_counter()
if msvcrt.kbhit():
disable.start()
timeSpent = toc-tic
print('Your first time was '+str(timeSpent) + ' seconds')
time.sleep(1)
print('The next one is coming up.')
time.sleep(1)
print('Ready')
time.sleep(1)
print('Steady')
time.sleep(random.randint(2,5))
print('#####__GO__######')
disable.stop()
tic2 = time.perf_counter()
b = input()
toc2 = time.perf_counter()
if msvcrt.kbhit():
disable.start()
timeSpent2 = toc2-tic2
print('Your second time was '+str(timeSpent2) + ' seconds')
time.sleep(1)
print('The last one is coming up.')
time.sleep(1)
print('Ready')
time.sleep(1)
print('Steady')
time.sleep(random.randint(2,5))
print('#####__GO__######')
disable.stop()
tic3 = time.perf_counter()
c = input()
toc3 = time.perf_counter()
timeSpent3 = toc3-tic3
print('Your last time was '+str(timeSpent3) + ' seconds')
average = (timeSpent + timeSpent2 + timeSpent3)/3
numAverage = round_sig(average)
print('Your average time is '+str(numAverage) + ' seconds')
The keyboard-disabling code never really runs.
Here's a simplification of your program that uses a function to capture one reaction time and calls it thrice.
The clear_keyboard_buffer() function (that should consume all outstanding keystrokes) was borrowed from https://stackoverflow.com/a/2521054/51685 .
import time, random, msvcrt, math
def round_sig(x, sig=5):
return round(x, sig - int(math.floor(math.log10(abs(x)))) - 1)
def clear_keyboard_buffer():
while msvcrt.kbhit():
msvcrt.getwch()
def get_reaction_time():
print("Ready")
time.sleep(1)
print("Steady")
time.sleep(random.randint(2, 5))
print("#####__GO__######")
clear_keyboard_buffer()
tic = time.perf_counter()
a = input()
toc = time.perf_counter()
return toc - tic
print("When I say __GO__ you hit ENTER! This will happen 3 times. Got it?")
time1 = get_reaction_time()
print(f"Your first time was {time1} seconds")
time.sleep(1)
print("The next one is coming up.")
time2 = get_reaction_time()
print(f"Your first time was {time2} seconds")
time.sleep(1)
print("The last one is coming up.")
time3 = get_reaction_time()
print(f"Your first time was {time3} seconds")
average = (time1 + time2 + time3) / 3
print(f"Your average time is {round_sig(average)} seconds")
This solution uses a Thread to start the timer, while the main thread waits for input all the time. That way, it is possible to catch early key presses:
from threading import Thread
import random
import time
def start():
global started
started = None
time.sleep(random.randint(2,5))
print("#### GO ####")
started = time.time()
t = Thread(target=start)
print("ready...")
# start the thread and directly wait for input:
t.start()
input()
end = time.time()
if not started:
print("Fail")
else:
print(end-started)
t.join()

Logging rainfall with Python

First post and I am at a dead end with this problem.
(some background)
I have a raspberry PiZero which I am developing a weather station with, so far it logs temp, humidity and pressure as well as sending the data to the windy.com API. Recently I added a tipping bucket rain gauge.
This has 2 wires which connect to the GPIO, when the bucket tips it momentarily competes the circuit, essentially a button press!
The goal here is to count the tips every hour, then reset. before resetting, send this data to log file + Windy API. This is the part I am struggling with.
I am pretty good with python but I am at a true writers block moment, here is a small program I cobbled together from snippets which counts the tips for testing
/usr/bin/python3
import requests
from gpiozero import Button
import time
rain_sensor = Button(27)
bucket_size = 0.2794
count = 0
def bucket_tipped():
global count
count = count + 1
print(count * bucket_size)
def reset_rainfall():
global count
count = 0
#display and log results
def timed_loop():
reset_rainfall
timeout = time.monotonic() + 3600 # 1 hour from now
while True:
if time.monotonic() > timeout: # break if timeout time is reached
rain_sensor.when_pressed = bucket_tipped
time.sleep(1) # Short sleep so loop can be interupted
continue
print count
# close the log file and exit nicely
GPIO.cleanup()
It looks like you are continuously setting your rain to 0 in your while True: loop.
Edit:
Try something like this for your loop.
def timed_loop():
rain = 0
timeout = time.monotonic() + 3600 # 1 hour from now
while True:
if time.monotonic() > timeout: # break if timeout time is reached
# You place your code here that you want to run every hour.
# After that the loop restarts
rain = 1
time.sleep(1) # Short sleep so loop can be interupted
continue
Edit 3:
With the following code you can record button presses over a specified amount of time.
import time
def bucket_tip_counter():
recording_time_timeout = 3600 # Amount of seconds you want to have the timer run
recording_time = time.monotonic() + recording_time_timeout
button_timeout = 1 # This timeout is here so the button doesnt trigger the count more then once for each trigger
# You have to modify this to your needs. If the button stays activated for a few seconds you need to set the timer accordingly.
count = 0 # Sets the counter to 0 at the start
button = 0 # Here you need to replace the 0 with the GPIO pin that returns True if the button is pressed
while True: # starts the loop
if button: # if button gets pressed/bucket tipped
count += 1 # up count by one
time.sleep(button_timeout) # wait specified timeout to make sure button isnt pressed anymore
if time.monotonic() > recording_time: # If the recording_time is reached the loop triggers this if condition
print(count) # print count
# Here you can also place code that you want to run when the hour is over
# Note that the counter wont start back up until that code is finished.
count = 0 # set count back to 0
recording_time = time.monotonic() + recording_time_timeout # Set a new timer so the hour can start anew
continue # restart the loop
time.sleep(1) # small sleep to stop CPU hogging.

How do I make a count down timer to run alongside my game in python?

I'm fairly new to Python and have created a trivia quiz, linking to txt files for the questions / answers and to store the high scores.
EDIT I AM NOT USING PYGAME
I would like to set a time limit for the questions to be answered, for example 1 minute. I've managed to get the timer to countdown but it counts down and then proceeds to my game.
Is there a way to make it run alongside? I thought about a while loop but it just messed it up so I'm guessing I did it wrong...
Here's my code (well the top bit):
import linecache
import sys
import pickle
import time
def countdown():
t = 60
while t:
mins, secs = divmod(t, 60)
timeformat = '{:02d}:{:02d}'.format(mins, secs)
print(timeformat, end='\r')
time.sleep(1)
t -= 1
print('You're out of time!\n')
def travel():
i = 0
countdown()
name = input("What is your name: ")
q1 = linecache.getline("travel.txt", 1)
a1 = linecache.getline("travel.txt", 2)
b1 = linecache.getline("travel.txt", 3)
c1 = linecache.getline("travel.txt", 4)
print("\n", q1, a1, b1, c1)
q = input("Answer: ")
if q == "b":
print("Correct! You've scored 1 point.")
i += 1
else:
print("Wrong answer buddy, 0 points.")
If you wanted to, you could use threading.Thread to have this functionality.
Note the following code:
import threading
import time
def countdown():
t = 60
while t:
mins, secs = divmod(t, 60)
timeformat = '{:02d}:{:02d}'.format(mins, secs)
print(timeformat, end='\r')
time.sleep(1)
t -= 1
print("You're out of time!\n")
# add some function which stops the game, for example by changing a variable to false (which the main thread always checks)
# or some other method like by checking count_thread.is_alive()
def main_game():
count_thread = threading.Thread(None, countdown)
# do game things
In this example, the print("You're out of time") will happen 60 seconds after main_game() is started, but at the same time the code at # do game things will be run. All you need to implement is a way for either the count_thread itself to kill the game, or make the game check whether the thread is still alive, and if not, to exit.

sleep without interrupting program

I am creating a program that counts down after a time, and asks for input of seconds to add to the countdown. (Not really, just an example).
Kind of like this:
mytime = 10
while True:
print(time)
mytime -= 1
time.sleep(1)
mytime += int(input('add > '))
There is 2 problems.
I want the time to still tick down after a second, but don't want to have to wait the second before inputting. Similar to this. I think I need to use threading.
I don't want to wait for input either! I just want it to tick down without waiting for input, and when I want I can input things.
Thanks for your help.
There is an easier way than making your own thread from 0. Timer thread prepared for you:
import threading
timer = None
def wuf ():
global timer
print "Wuf-wuf!"
timer = threading.Timer(5, wuf)
timer.start()
timer = threading.Timer(5, wuf)
timer.start()
input() # Don't exit the program
This code will wait 5 seconds and then start printing "Wuf-wuf!" every 5 seconds.
If you want to stop it from main thread do:
timer.cancel()
But if you are writing a GUI application using event driven GUI system like wxPython or PyQT, then you should use theirs event managed timers. Especially if you are changing some GUI status from the timer callback.
Edit:
Oh, all right, here is your full answer:
import threading
seconds = 1 # Initial time must be the time+1 (now 0+1)
timer = None
def tick ():
global seconds, timer
seconds -= 1
if seconds==0:
print("%i seconds left" % seconds)
print("Timer expired!")
return
# printing here will mess up your stdout in conjunction with input()
print("%i second(s) left" % seconds)
timer = threading.Timer(1, tick)
timer.start()
seconds += int(input("Initial countdown interval: "))
tick()
while 1:
seconds += int(input("Add: "))
if not timer.is_alive():
print("Restarting the timer!")
seconds += 1
tick()
Or easy version with thread (but a little clumsyer then using threading.Thread):
from thread import start_new_thread as thread
from time import sleep
seconds = 1 # Initial time+1
alive = 0
def _tick ():
global seconds, alive
try:
alive = 1
while 1:
seconds -= 1
if seconds==0:
print("%i seconds left" % seconds)
print("Timer expired!")
alive = 0
return
# printing here will mess up your stdout in conjunction with input()
print("%i second(s) left" % seconds)
sleep(1)
except: alive = 0
def tick ():
thread(_tick,())
# Then same as above:
seconds += int(input("Initial countdown interval: "))
tick()
while 1:
seconds += int(input("Add: "))
if not alive:
print("Restarting the timer!")
seconds += 1
tick()
You must realize that using the stdout within a thread will insert the printed text after the prompt message outputed by input().
This will be confusing. If you want to avoid this then you will have to write another thread that will get messages from a queue and output them.
If a last message was prompt message, then you will have to remove it from screen, write the new message, then return the prompt message, and position the cursor accordingly.
You could do it by implementing the file-like interface within the subclass of threading.Thread, then substituting sys.stdout with it. Perhaps overriding input() as well to indicate when a prompt message is out and stdin being read.
You'll need to use threading to do so. All you have to do is create a subclass of threading.Thread override the run() method and add some external control methods over the thread.
Here is a simple example you can try and tweak according to your own taste.
import threading
import time
class SleepingThread(threading.Thread):
def __init__(self, sleep_for):
super(SleepingThread, self).__init__()
self.sleep_for = sleep_for
def run(self):
while self.sleep_for != 0:
time.sleep(1)
self.sleep_for -= 1
print("Done sleeping")
def add_seconds(self, seconds):
self.sleep_for += seconds
def get_sleep_for(self):
return self.sleep_for
sleeping_thread = SleepingThread(10)
sleeping_thread.start()
while True:
print(sleeping_thread.get_sleep_for())
sleeping_thread.add_seconds(int(input('add > ')))
Don't forget to join() if you want to go serious about it.

Categories

Resources