User input to stop while loop - python

I'm currently making a stopwatch function, where the user has to input 1 to start and 2 to stop the stopwatch. I'm wondering how to implement the stop function when the while loop is going on as whatever I tried didn't work.
This is the stopwatch code I'm working on:
second = 0
minute = 0
hour = 0
millisecond = 0
start = input("Press 1 to start and 2 to stop: ")
while True:
if start == "2":
break
else:
print("%02d : %02d : %02d "%(hour, minute, second,))
time.sleep(1)
second += 1
if second == 60:
minute += 1
second -= 60
if minute == 60:
hour += 1
minute -= 60

input is blocking until the user types something (and hit enters).
So if you put it in your while loop, the user will get asked repeatedly if he wants to stop, each time pausing the clock, it is not what is expected.
But if you put the input outside the loop (it is strange that you do that), then the user is never asked to type something until the loop ends (which is never).
It means that in your case, input is not a solution.
There is a very similar question which has an accepted answer (slightly adapted to your case) :
try:
while True:
print("%02d : %02d : %02d "%(hour, minute, second,))
...
except KeyboardInterrupt:
# here the loop has definitely stopped
...
which works with Ctrl+C, being a standard way to signal the program to stop something.
If you want to use something other than Ctrl+C, there are other questions here on StackOverflow that could fit your needs :
detecting any keypress in a terminal : How to break this loop in Python by detecting key press
How to kill a while loop with a keystroke?
Your question is thus a duplicate of one of these.

Here's a threading example that does what you describe.
import time
import threading
thread_live = False
def countdown():
seconds = 0;
while thread_live:
hour = seconds // 3600
minute = (seconds // 60) % 60
second = seconds % 60
print("%02d:%02d:%02d "%(hour, minute, second))
seconds += 1
time.sleep(1)
print("exiting")
while True:
start = input("Press 1 to start and 2 to stop, 3 to exit: ")
if start == "1" and not thread_live:
cd = threading.Thread(target=countdown)
thread_live = True
cd.start()
elif start == "2" and thread_live:
thread_live = False
cd.join()
elif start == "3":
break
Here's a version that uses a timedelta to store and format the time:
import time
import datetime
import threading
thread_live = False
def countdown():
t = datetime.timedelta(0)
one = datetime.timedelta(seconds=1)
while thread_live:
print(str(t))
t += one
time.sleep(1)
print("exiting")
while True:
start = input("Press 1 to start and 2 to stop, 3 to exit: ")
if start == "1" and not thread_live:
cd = threading.Thread(target=countdown)
thread_live = True
cd.start()
elif start == "2" and thread_live:
thread_live = False
cd.join()
elif start == "3":
break

Related

Why my thread doesn't stop after function finished?

So I wrote this script, which counts income packets on certain port, and in case if there are to many packets script has to do something. On the first received packet is has to start timer, and if timer reaches 60 sec, packet count should start from 0 again. It works, but only for first timer call, in any case, if script has to start timer again I get the error:
raise RuntimeError("threads can only be started once")
RuntimeError: threads can only be started once"`
It's clear, that this thread still running, but i don't understand why. I mean, in case if timer reaches 60 secs, timer loop is finished, and function should be finished too, so i can use timer again? Clearly i don't understand something here, can you guys explain it? Thanks for answers
My code:
from scapy.all import *
from threading import Thread
import time
global count
count = 0
def timer():
global count
i = 0
while i < 60:
if count > 0:
time.sleep(1)
i = i + 1
print(str(count))
else:
print("count is 0, timer turning off...")
break
else:
count = 0
print("60 seconds, timer is off")
background_thread = Thread(target=timer)
def pkt_callback(pkt):
global count
packet_limit = 10
if pkt.haslayer(UDP) and pkt.getlayer(UDP).dport == 5160 and pkt.haslayer(Raw):
raw = pkt.getlayer(Raw).load
s = str(raw)
if 'REGISTER' in s:
count += 1
print(count)
if count == 1:
if background_thread.is_alive() is False:
background_thread.start()
print("Register packet detected, timer is on")
if count >= packet_limit:
print("PACKETLIMIT reached, do smth")
count = 0
sniff(iface='ens160', filter="", prn=pkt_callback)
I think you have to use the return function not break, and either way you have only used it once, also you can change your code a bit, try this:
def timer():
global count
i = 0
while i < 60:
if count != 0:
time.sleep(1)
i += 1
print(str(count))
else:
return "count is 0, timer turning off..."
else:
count = 0
return "60 seconds, timer is off"

Creating a counter which resets itself every 30 seconds

I want to create a function that counts till 30, but when it reaches 30 I want to reset it to starting point.
def countdown():
global countDown
countDown = int(time.time() - start_time)
return countDown % 30
And then I want to print it like that.
print("You have " + str(30 - countdown()) + " time")
It works but when it reaches 0, it keeps counting below 0 like -1,-2 and it is not doing modula operation. So it doesn't reset itself. What can I do in this case ?
Desired case: 30 29.... 3 2 1 0 30 29 28
Recent case: 30 29 ... 2 1 0 -1 -2
The counter is not being reset using the modulo operator (countDown % 30). Try,
import time
def countdown(i):
counter = i
while True:
if (counter == i):
counter = 0
print(counter)
counter = counter + 1
time.sleep(1)
countdown(30)
What I got from your code
import time
start_time = time.time()
def countdown():
global countDown
countDown = int(time.time() - start_time)
return countDown % 30
print("You have " + str(30 - countdown()) + " time")
is working perfectly on https://www.python.org/shell/
Can't reproduce your problem. Or it's not with the code in your question!
Try to avoid using global variables. Also, use 4 space indentations.
I would use length of time as an input.
from time import time
def do_something():
pass
def get_time(start_time):
# returns how much time did it pass from event that started at start_time
return time() - start_time
def countdown(countDown):
start_time = time()
# this is counter that attains consecutive values [0, 1, ..., countDown]
current_count = 0
while current_count < countDown:
print(countDown - current_count, end=' ')
while get_time(start_time) - current_count < 1:
do_something()
#warning: if do_something takes significant anount of
#time forthcoming print won't be correct
current_count += 1
print(countDown - current_count, end=' ')
return current_count
countdown(7)
countdown(5)
Also the purpose of
print("You have " + str(30 - countdown()) + " time")
is not clear to me. Use it wherever you want in your script.
Due to the question being quite unclear, it is hard to create exactly what you're looking for. However, this code should work for you no matter how you intend it to be used.
This code allows you to:
Make a timer
Get the time left
Run code while the timer is counting down
Run code once the timer has ended.
You can also reset the timer
Code:
import time
class countdown():
def start(self):
self.t = time.time()
def remaining(self):
return 30 - int(time.time()-self.t)
timer = countdown()
timer.start()
while True:
print(30 - countdown(), "seconds remaining") #Still time left code
if timer.remaining() <= 0:
pass #30 seconds over code
timer.reset() #Starts timer again
As others pointed out, your function is not resetting your counter.
Try the following little modification:
def countdown():
global countDown
countDown = int(time.time() - start_time) % 30
return countDown
Firstly, I want to apologize from everyone for not explaining my question clearly because this is my first question. Secondly, as shown in example , I saw that I did not made any mistake about my code. First part is correct but when it prints ("You have " + str(5 - countdown()) + " time") showing me the negative ones because of I take the modula of 30 but showing it in print func " 5 - countdown()" . So when it becomes 15 it will return 15 but 5 - 15 = -10. Thanks for everyone who tried to help.

math quiz with a time limit (simultaneous functions) - advanced python

So I would like to run two programs, a timer and a math question. But always the input seems to be stopping the timer funtion or not even run at all. Is there any ways for it to get around that?
I'll keep the example simple.
import time
start_time = time.time()
timer=0
correct = answer
answer = input("9 + 9 = ")
#technically a math question here
#so here until i enter the input prevents computer reading the code
while True:
timer = time.time() - start_time
if timer > 3:
#3 seconds is the limit
print('Wrong!')
quit()
So recap i would like the player to answer the question in less than 3 seconds.
after the 3 seconds the game will print wrong and exit
if the player answer within three seconds the timer would be 'terminated' or stopped before it triggers 'wrong' and quit
hope you understand, and really appreciate your help
On Windows you can use the msvcrt module's kbhit and getch functions (I modernized this code example a little bit):
import sys
import time
import msvcrt
def read_input(caption, timeout=5):
start_time = time.time()
print(caption)
inpt = ''
while True:
if msvcrt.kbhit(): # Check if a key press is waiting.
# Check which key was pressed and turn it into a unicode string.
char = msvcrt.getche().decode(encoding='utf-8')
# If enter was pressed, return the inpt.
if char in ('\n', '\r'): # enter key
return inpt
# If another key was pressed, concatenate with previous chars.
elif char >= ' ': # Keys greater or equal to space key.
inpt += char
# If time is up, return the inpt.
if time.time()-start_time > timeout:
print('\nTime is up.')
return inpt
# and some examples of usage
ans = read_input('Please type a name', timeout=4)
print('The name is {}'.format(ans))
ans = read_input('Please enter a number', timeout=3)
print('The number is {}'.format(ans))
I'm not sure what exactly you have to do on other operating systems (research termios, tty, select).
Another possibility would be the curses module which has a getch function as well and you can set it to nodelay(1) (non-blocking), but for Windows you first have to download curses from Christopher Gohlke's website.
import time
import curses
def main(stdscr):
curses.noecho() # Now curses doesn't display the pressed key anymore.
stdscr.nodelay(1) # Makes the `getch` method non-blocking.
stdscr.scrollok(True) # When bottom of screen is reached scroll the window.
# We use `addstr` instead of `print`.
stdscr.addstr('Press "q" to exit...\n')
# Tuples of question and answer.
question_list = [('4 + 5 = ', '9'), ('7 - 4 = ', '3')]
question_index = 0
# Unpack the first question-answer tuple.
question, correct_answer = question_list[question_index]
stdscr.addstr(question) # Display the question.
answer = '' # Here we store the current answer of the user.
# A set of numbers to check if the user has entered a number.
# We have to convert the number strings to ordinals, because
# that's what `getch` returns.
numbers = {ord(str(n)) for n in range(10)}
start_time = time.time() # Start the timer.
while True:
timer = time.time() - start_time
inpt = stdscr.getch() # Here we get the pressed key.
if inpt == ord('q'): # 'q' quits the game.
break
if inpt in numbers:
answer += chr(inpt)
stdscr.addstr(chr(inpt), curses.A_BOLD)
if inpt in (ord('\n'), ord('\r')): # Enter pressed.
if answer == correct_answer:
stdscr.addstr('\nCorrect\n', curses.A_BOLD)
else:
stdscr.addstr('\nWrong\n', curses.A_BOLD)
if timer > 3:
stdscr.addstr('\nToo late. Next question.\n')
if timer > 3 or inpt in (ord('\n'), ord('\r')):
# Time is up or enter was pressed; reset and show next question.
answer = ''
start_time = time.time() # Reset the timer.
question_index += 1
# Keep question index in the correct range.
question_index %= len(question_list)
question, correct_answer = question_list[question_index]
stdscr.addstr(question)
# We use wrapper to start the program.
# It handles exceptions and resets the terminal after the game.
curses.wrapper(main)
Use time.time(), it returns the epoch time (that is, the number of seconds since January 1, 1970 UNIX Time). You can compare it to a start time to get the number of seconds:
start = time.time()
while time.time() - start < 60:
# stuff
You can have a timer pull you out of your code at any point (even if the user is inputting info) with signals but it is a little more complicated. One way is to use the signal library:
import signal
def timeout_handler(signal, frame):
raise Exception('Time is up!')
signal.signal(signal.SIGALRM, timeout_handler)
This defines a function that raises an exception and is called when the timeout occurs. Now you can put your while loop in a try catch block and set the timer:
signal.alarm.timeout(60)
try:
while lives > 0
# stuff
except:
# print score

datetime module not matching int comparison to int

I'm currently making an Alarm Clock as a tool to further learn python3 and I have come across a problem.
def clockCheck():
#get the hour and time from setAlarm
splitTime = re.compile(r'(\d+?)(:)(\d+)')
timeRe = splitTime.search(setAlarm())
alarmHour = timeRe.group(1)
alarmMinute = timeRe.group(3)
#get the live time
now = datetime.datetime.now()
currentHour = now.hour
currentMinute = now.minute
currentSecond = now.second
print(currentHour)
print(alarmHour)
while True:
if currentHour != alarmHour:
print("check1")
time.sleep(60-currentSecond) #if this isn't done, the alarm could be off by a couple seconds. Line's up things
time.sleep((60*60) - (60*currentMinute)) #this sleeps the program until the next hour is hit and reruns a check
elif currentMinute != alarmMinute:
print("check2")
time.sleep(60-currentSecond) #sleep until the next minute and rerun the check
#play sound
#break out of program, it's done
In this code snippet, when currentHour is compared to alarmHour (the first if statement), even when those two variables are the same, the code executes the if statement in which they do not equal each other.
In other words, if currentHour = 1 and alarmHour = 1, the code will execute as if currentHour != alarmHour and will run that if statements code.
Obviously that doesn't make sense and I don't know why that is happening when clearly 1==1. I have posted the full code, feel free to play with it. All these modules are built into python3.6
Here is my full code
'''
alarmclock.
ask user for what time to blare off
compare current time to set alarm time
if they do not equal the same then sleep the program for x time and ` rerun the check where it checks if current time is equal alarm time yet. loop until currenttime equals alarm time. then play soun`d
'''
import time
import datetime
import re
def setAlarm():
print("Hello, what time would you like the alarm to sound? Please input in this format\ne.g. 7:45pm\n")
time = input("Time: ")
splitTime = re.compile(r'(\d+?)(:)(\d+?)(pm|am)') #split up time inputted for manipulation
timeRe = splitTime.search(time)
hour = int(timeRe.group(1))
minutes = int(timeRe.group(3))
dayOfTime = timeRe.group(4).lower() #set pm or am to lowercase for ease
#errorChecking for proper time format
if hour > 12 or hour < 1:
print("Please input your time properly, in 12 hour time")
setAlarm()
if minutes > 59 or minutes < 0:
print("Please input your time properly")
setAlarm()
#if time of day is pm, then reassign all values from 1pm - 11:59pm as 13, 14, 15, etc 24 hour bullshit.
if dayOfTime == "pm" and hour != 12:
convertedHour = hour + 12
else:
convertedHour = hour
if dayOfTime == "am" and hour == 12:
convertedHour = 24
finalTime = str(convertedHour) + ":" + str(minutes)
print(finalTime)
return finalTime
def clockCheck():
#get the hour and time from setAlarm
splitTime = re.compile(r'(\d+?)(:)(\d+)')
timeRe = splitTime.search(setAlarm())
alarmHour = timeRe.group(1)
alarmMinute = timeRe.group(3)
#get the live time
now = datetime.datetime.now()
currentHour = now.hour
currentMinute = now.minute
currentSecond = now.second
print(currentHour)
print(alarmHour)
while True:
if currentHour != alarmHour:
print("check1")
time.sleep(60-currentSecond) #if this isn't done, the alarm could be off by a couple seconds. Line's up things
time.sleep((60*60) - (60*currentMinute)) #this sleeps the program until the next hour is hit and reruns a check
elif currentMinute != alarmMinute:
print("check2")
time.sleep(60-currentSecond) #sleep until the next minute and rerun the check
#play sound
#break out of program, it's done
def main():
clockCheck()
main()

Python time limit

I have a homework assignment to do and I really need a solution. I have been trying to do this since yesterday but I do not know how.
Program has to generate and print a letter or a number and then a user has to type it as quickly as possible and press ENTER. The game is over after 30 secs.
Well I do not know how to put time limit to a game. I was searching through stackoverflow and I did not find anything useful. Please help me.
**Here it is what I have done so far. I tried code from the answer by SYSS.STDER, but it does not quite work because when the 30 secs are over, the game should also be over, but here in this code the game is over when I type last character.
LOOP WILL NOT STOP UNTIL IT FINISHES AND WE DISCOVER THAT WE ARE PAST OUR DEADLINE. THE TASK NEEDS TO BE INTERRUPTED IN PROGRESS AS SOON AS THE TIME ELAPSES.
max_time =30
start_time = time.time() # remember when we started
while (time.time() - start_time) < max_time:
response = "a" # the variable that will hold the user's response
c = "b" #the variable that will hold the character the user should type
score = 0
number = 0
c = random.choice(string.ascii_lowercase + string.digits)
print(c)
number = number + 1
response = input("Type a letter or a number: ") #get the user's response
if response == c and (time.time() - start_time) < max_time:
# if the response from the previous loop matches the character
# from the previous loop, increase the score.
score = score + 1
Here's my way to do it:
import string
import random
import time
response = "a" # the variable that will hold the user's response
c = "b" #the variable that will hold the character the user should type
score = 0 #the variable that will hold the user's score
start = time.time() #the variable that holds the starting time
elapsed = 0 #the variable that holds the number of seconds elapsed.
while elapsed < 30: #while less than 30 seconds have elapsed
if response == c: #if the response from the previous loop matches the character
score += 1 #from the previous loop, increase the score.
#c is a random character
c = random.choice(string.ascii_lowercase + string.digits)
print(c)
response = input("Type a letter or a number: ") #get the user's response
elapsed = time.time() - start #update the time elapsed
Since you're using Windows you can use the msvcrt.kbhit function to check for keypresses inside timing loops:
import msvcrt #### windows only ####
import os
import random
import string
import time
max_time = 15
def readch(echo=True):
"Get a single character on Windows"
ch = msvcrt.getch()
while ch in b'\x00\xe0': # special function key?
msvcrt.getch() # get keycode & ignore
ch = msvcrt.getch()
if echo:
msvcrt.putch(ch)
return ch.decode()
def elapsed_time():
global start_time
return time.time() - start_time
number = 0
score = 0
start_time = time.time() # initialize timer
while elapsed_time() < max_time:
c = random.choice(string.ascii_lowercase + string.digits)
print(c, end='')
number += 1
print("Type a letter or a number: ", end='')
while elapsed_time() < max_time:
if not msvcrt.kbhit():
time.sleep(0.1) # don't hog processor
else:
response = readch(echo=False) # get the user's response
if response == c:
print(response) # only print if correct
score += 1
break
else:
print()
print()
print("Time's up")
print("You go {} out of {}:".format(score, number))
A sample program to exit prime number function when Time limit has exceeded.
import math
from time import time
start_time = time()
max_time = 2
def prime(n):
for i in range(2, int(math.sqrt(n))):
if(time() - start_time) > max_time:
return "TLE"
if n % i == 0:
return False
return True
print(prime(3900000076541747077))
use "timeit" module available in python for better result.

Categories

Resources