I'm making an unoriginal game for a first project that just runs in my python terminal. The user is randomly given a set of 2-3 letters and the user has to come up with a real word (checked by the Webster dictionary) that contains the given set of letters within 5 seconds. For example, if the game generates "le" the user can input "elephant" within 5 seconds as a correct word and gives them a point.
The problem is that I can't seem to implement the 5 second timer function to run in the back for every time a prompt is given without messing up some other part or running into another problem. I've looked into threading and can't seem to make use of it.
Here is the code for the main game:
from letters import letter_sets_list
fhand = open("words_dictionary.json")
data = fhand.read()
global score
score = int(0)
game_over = False
while game_over is False:
import random
random_letters = random.choice(letter_sets_list)
print('Word that contains:', random_letters)
answer = input("Type a word:")
if answer in data and random_letters in answer:
score += 1
print("nice one")
else:
game_over = True
print("Game Over \n Score:", score)
fhand.close()
exit()
Here is the timer function I found off YouTube and tried to implement:
def countdown():
global my_timer
my_timer = int(5)
for x in range(5):
my_timer -= 1
sleep(1)
countdown_thread = threading.Thread(target=countdown)
countdown_thread.start()
Take a look at that. Especially check if that will work for you:
import time
from threading import Thread
answer = None
def check():
time.sleep(2)
if answer != None:
return
print("Too Slow")
Thread(target = check).start()
answer = input("Input something: ")
Edit: I tried to implement code from my previous answer to your code but with a little different approach:
import time, threading
#from letters import letter_sets_list
#import random
#fhand = open("words_dictionary.json")
#data = fhand.read()
data = ["answer"]
answer = [None]
random_letters = [None]
global score
score = int(0)
game_over = False
x = 0
def game(answer, random_letters):
#random_letters = random.choice(letter_sets_list)
print('Word that contains:', random_letters)
while True:
answer[0] = input("Type a word: ")
mythread = threading.Thread(target=game, args=(answer, random_letters))
mythread.daemon = True
mythread.start()
for increment in range(5):
time.sleep(1)
if answer[0] in data: # and random_letters in answer
score += 1
print("Good answer")
x = 1
break
if x != 1:
print("\nTime is up")
else:
x = 0
game_over = True
In this approach I didnt use time.sleep() inside threaded function but outside of it which helps with killing it. Also i assumed that if your answer is incorrect you would like to have another chance to answer untill time is up or answer is correct so I just used while loop in threaded function. The code is quite simple so I think if you spend a little time analysing your parts of the code you will figure it out.
Some parts of the code I didn't use as I dont have access to your json files ect., but if I understand correctly what you're trying to do, it shoud work. Also check how will behave your kernel. In my case sometimes it shows some problems but my PC is not the best and so it might be only problem with RAM or other part of my computer as it happens quite often with my projects.
I am a novice Python programmer, trying to write a Python script to run a barcode scanning station (Raspberry Pi 4, RPiOS, Python 3.7.3). I want to scan a certain number of items, and when complete I want to scan a different barcode to process the input. From there either it will send a GPIO signal if batch count is met, or terminate the program outright if the count is too high or low.
I have been successful with what I've written, with one exception: when a second barcode is scanned to process the input, it needs to be scanned TWICE to trigger the rest of the script. I'm stumped as to why this is, and am sure this is something simple I overlooked.
import RPi.GPIO as GPIO
GPIO.setwarnings(False)
import time
good = 38
GPIO.setmode(GPIO.BOARD)
GPIO.setup(good,GPIO.OUT)
GPIO.output(good,GPIO.HIGH)
try:
def batch_order():
batch = input("Enter the number of parts on the order: ")
barcode1 = input("Scan MASTER barcode: ")
print("Begin scanning barcodes: ")
count = 0
while True:
if input() == barcode1:
count+= 1
print("Part count: %s"%(str(count)))
elif input() != barcode1:
time.sleep(0.2)
if batch == str(count):
print("Order complete! Now printing shipping label...")
time.sleep(0.2)
GPIO.output(good,False)
time.sleep(15)
GPIO.output(good,True)
break
else:
print("Order incorrect, %s of %s parts scanned."%(str(count), batch))
time.sleep(2)
break
batch_order()
except KeyboardInterrupt:
GPIO.cleanup()
print("QUIT")
GPIO.cleanup()
All I want to do is eliminate the double scan required to terminate the program at elif input() != barcode1:. Any help would be greatly appreciated, thank you!
Just get the input() once and assign it
value = input()
if value == barcode1:
...
else: # there is also no other case
...
I am making a Cookie clicker like game in Python, and I am trying to have the while loop keep going so it checks if a second has gone (so it adds "cookies") while still looking if the user is making an input (clicking on "Cookie").
Whenever I try this it waits for the input instead of doing the rest of the loop.
This is what my current code looks like (There's more of course):
While True:
console.clear()
cookieText = "You have " + str(cookies) + " cookies"
print cookieText
clicker = raw_input("")
if clicker == "":
cookies += clickerPower
more...
This is what I want to add:
While True:
last = time()
if last == timer:
timer = last
more...
this worked for me (source)
import msvcrt
num = 0
done = False
while not done:
print num
num += 1
if msvcrt.kbhit():
print msvcrt.getch()
done = True
The answer is threading. But it's not simple.
I'm new to Python and have been googling for a couple of days and read all I can find on this forum. Might be that I don't understand it all but I haven't found a solution to my problem yet. Ask for forgiveness already if there's an answer already to my problem, then I haven't understood it.
I want to make a Pause function for my program Tennismatch. The program will when it's being run print the score of a tennis match like this: "15-0, 15-15 etc ongoing till the match ends. It will print the score line by line.
I want the user to be able to pause after x number of balls, games, etc. So I don't know when the user wants to pause and after the user has paused I want the user to be able to resume the tennismatch where it was.
Have seen the time.sleep() but as I have understood it you must know when you want to pause to use this and it also ain't an indefinetie pause like I want. With input() it's the same.
Am going to make a GUI later on when the code is finished. Happy for anything that leads me to solving my problem.
I use Windows and Python 3.42 and run the program in Shell.
A piece of the code (haven't written it all yet, it's more of a general situation when something is being printed line after line for some time and want to be able do pause in the CIL:
#self.__points = [0,0]
def playGame(self):
if self.server == True: #self.server is either True or False when someone calls playGame()
server = self.player_1.get_win_serve() #self.player_1 = an object of a class Player():
else:
server = self.player_2.get_win_serve() #get_win_serve() method returns the probability to win his serv (1-0)
while (0 < self.__points[0] - self.__points[1] >= 2 or 0 < self.__points[1] - self.__points[0] >= 2) and (self.__points[1] >= 4 or self.__points[0] >= 4):
x = random.uniform(0,1)
if x > 0 and x < server:
self.__points[0] += 1
else:
self.__points[1] += 1
# print('The score, by calling a score() function that I haven't written yet')
For dealing with events in main loop you need to make a separated thread which capture input or any other event.
import sys
from sys import stdin
from time import sleep
from threading import Thread
from Queue import Queue, Empty
def do_something():
sleep(1)
print 42
def enqueue_output(queue):
while True:
# reading line from stdin and pushing to shared queue
input = stdin.readline()
print "got input ", input
queue.put(input)
queue = Queue()
t = Thread(target=enqueue_output, args=(queue,))
t.daemon = True
t.start()
pause = False
try:
while True:
try:
command = queue.get_nowait().strip()
print 'got from queue ', command
except Empty:
print "queue is empty"
command = None
if command:
if command == 'p':
pause = True
if command == 'u':
pause = False
if not pause:
print pause
do_something()
except KeyboardInterrupt:
sys.exit(0)
I came up with the following.
while True:
try:
## Keep doing something here
## your regular code
print '.',
except KeyboardInterrupt:
## write or call pause function which could be time.sleep()
print '\nPausing... (Hit ENTER to continue, type quit to exit.)'
try:
response = raw_input()
if response.lower() == 'quit':
break
print 'Quitting...'
except KeyboardInterrupt:
print 'Resuming...'
continue
The Event loop might as well be the code I wrote with.
I don't see any user input so I assume that x emulates it. To pause the game if x < 0.1 and to unpause(/resume) it if x > 0.9, you could:
while your_condition(self.__points):
x = random.random()
if x < 0.1: # pause
self.pause()
elif x > 0.9: # resume
self.resume()
if self.is_paused:
continue # do nothing else only wait for input (`x`)
# assume your_condition() has no side-effects
# here's what the resumed version does:
print("...")
# change self.__points, etc
where pause(), resume(), is_paused() methods could be implemented as:
def __init__(self):
self.is_paused = False
def pause(self):
self.is_paused = True
def resume(self):
self.is_paused = False
as you can see the implementation is very simple.
in python, is there a way to, while waiting for a user input, count time so that after, say 30 seconds, the raw_input() function is automatically skipped?
The signal.alarm function, on which #jer's recommended solution is based, is unfortunately Unix-only. If you need a cross-platform or Windows-specific solution, you can base it on threading.Timer instead, using thread.interrupt_main to send a KeyboardInterrupt to the main thread from the timer thread. I.e.:
import thread
import threading
def raw_input_with_timeout(prompt, timeout=30.0):
print(prompt, end=' ')
timer = threading.Timer(timeout, thread.interrupt_main)
astring = None
try:
timer.start()
astring = input(prompt)
except KeyboardInterrupt:
pass
timer.cancel()
return astring
this will return None whether the 30 seconds time out or the user explicitly decides to hit control-C to give up on inputting anything, but it seems OK to treat the two cases in the same way (if you need to distinguish, you could use for the timer a function of your own that, before interrupting the main thread, records somewhere the fact that a timeout has happened, and in your handler for KeyboardInterrupt access that "somewhere" to discriminate which of the two cases occurred).
Edit: I could have sworn this was working but I must have been wrong -- the code above omits the obviously-needed timer.start(), and even with it I can't make it work any more. select.select would be the obvious other thing to try but it won't work on a "normal file" (including stdin) in Windows -- in Unix it works on all files, in Windows, only on sockets.
So I don't know how to do a cross-platform "raw input with timeout". A windows-specific one can be constructed with a tight loop polling msvcrt.kbhit, performing a msvcrt.getche (and checking if it's a return to indicate the output's done, in which case it breaks out of the loop, otherwise accumulates and keeps waiting) and checking the time to time out if needed. I cannot test because I have no Windows machine (they're all Macs and Linux ones), but here the untested code I would suggest:
import msvcrt
import time
def raw_input_with_timeout(prompt, timeout=30.0):
print(prompt, end=' ')
finishat = time.time() + timeout
result = []
while True:
if msvcrt.kbhit():
result.append(msvcrt.getche())
if result[-1] == '\r': # or \n, whatever Win returns;-)
return ''.join(result)
time.sleep(0.1) # just to yield to other processes/threads
else:
if time.time() > finishat:
return None
The OP in a comment says he does not want to return None upon timeout, but what's the alternative? Raising an exception? Returning a different default value? Whatever alternative he wants he can clearly put it in place of my return None;-).
If you don't want to time out just because the user is typing slowly (as opposed to, not typing at all!-), you could recompute finishat after every successful character input.
I found a solution to this problem in a blog post. Here's the code from that blog post:
import signal
class AlarmException(Exception):
pass
def alarmHandler(signum, frame):
raise AlarmException
def nonBlockingRawInput(prompt='', timeout=20):
signal.signal(signal.SIGALRM, alarmHandler)
signal.alarm(timeout)
try:
text = raw_input(prompt)
signal.alarm(0)
return text
except AlarmException:
print '\nPrompt timeout. Continuing...'
signal.signal(signal.SIGALRM, signal.SIG_IGN)
return ''
Please note: this code will only work on *nix OSs.
The input() function is designed to wait for the user to enter something (at least the [Enter] key).
If you are not dead set to use input(), below is a much lighter solution using tkinter. In tkinter, dialog boxes (and any widget) can be destroyed after a given time.
Here is an example :
import tkinter as tk
def W_Input (label='Input dialog box', timeout=5000):
w = tk.Tk()
w.title(label)
W_Input.data=''
wFrame = tk.Frame(w, background="light yellow", padx=20, pady=20)
wFrame.pack()
wEntryBox = tk.Entry(wFrame, background="white", width=100)
wEntryBox.focus_force()
wEntryBox.pack()
def fin():
W_Input.data = str(wEntryBox.get())
w.destroy()
wSubmitButton = tk.Button(w, text='OK', command=fin, default='active')
wSubmitButton.pack()
# --- optionnal extra code in order to have a stroke on "Return" equivalent to a mouse click on the OK button
def fin_R(event): fin()
w.bind("<Return>", fin_R)
# --- END extra code ---
w.after(timeout, w.destroy) # This is the KEY INSTRUCTION that destroys the dialog box after the given timeout in millisecondsd
w.mainloop()
W_Input() # can be called with 2 parameter, the window title (string), and the timeout duration in miliseconds
if W_Input.data : print('\nYou entered this : ', W_Input.data, end=2*'\n')
else : print('\nNothing was entered \n')
from threading import Timer
def input_with_timeout(x):
def time_up():
answer= None
print('time up...')
t = Timer(x,time_up) # x is amount of time in seconds
t.start()
try:
answer = input("enter answer : ")
except Exception:
print('pass\n')
answer = None
if answer != True: # it means if variable have somthing
t.cancel() # time_up will not execute(so, no skip)
input_with_timeout(5) # try this for five seconds
As it is self defined... run it in command line prompt , I hope you will get the answer
read this python doc you will be crystal clear what just happened in this code!!
A curses example which takes for a timed math test
#!/usr/bin/env python3
import curses
import curses.ascii
import time
#stdscr = curses.initscr() - Using curses.wrapper instead
def main(stdscr):
hd = 100 #Timeout in tenths of a second
answer = ''
stdscr.addstr('5+3=') #Your prompt text
s = time.time() #Timing function to show that solution is working properly
while True:
#curses.echo(False)
curses.halfdelay(hd)
start = time.time()
c = stdscr.getch()
if c == curses.ascii.NL: #Enter Press
break
elif c == -1: #Return on timer complete
break
elif c == curses.ascii.DEL: #Backspace key for corrections. Could add additional hooks for cursor movement
answer = answer[:-1]
y, x = curses.getsyx()
stdscr.delch(y, x-1)
elif curses.ascii.isdigit(c): #Filter because I only wanted digits accepted
answer += chr(c)
stdscr.addstr(chr(c))
hd -= int((time.time() - start) * 10) #Sets the new time on getch based on the time already used
stdscr.addstr('\n')
stdscr.addstr('Elapsed Time: %i\n'%(time.time() - s))
stdscr.addstr('This is the answer: %s\n'%answer)
#stdscr.refresh() ##implied with the call to getch
stdscr.addstr('Press any key to exit...')
curses.wrapper(main)
under linux one could use curses and getch function, its non blocking.
see getch()
https://docs.python.org/2/library/curses.html
function that waits for keyboard input for x seconds (you have to initialize a curses window (win1) first!
import time
def tastaturabfrage():
inittime = int(time.time()) # time now
waitingtime = 2.00 # time to wait in seconds
while inittime+waitingtime>int(time.time()):
key = win1.getch() #check if keyboard entry or screen resize
if key == curses.KEY_RESIZE:
empty()
resize()
key=0
if key == 118:
p(4,'KEY V Pressed')
yourfunction();
if key == 107:
p(4,'KEY K Pressed')
yourfunction();
if key == 99:
p(4,'KEY c Pressed')
yourfunction();
if key == 120:
p(4,'KEY x Pressed')
yourfunction();
else:
yourfunction
key=0
This is for newer python versions, but I believe it will still answer the question. What this does is it creates a message to the user that the time is up, then ends the code. I'm sure there's a way to make it skip the input rather than completely end the code, but either way, this should at least help...
import sys
import time
from threading import Thread
import pyautogui as pag
#imports the needed modules
xyz = 1 #for a reference call
choice1 = None #sets the starting status
def check():
time.sleep(15)#the time limit set on the message
global xyz
if choice1 != None: # if choice1 has input in it, than the time will not expire
return
if xyz == 1: # if no input has been made within the time limit, then this message
# will display
pag.confirm(text = 'Time is up!', title = 'Time is up!!!!!!!!!')
sys.exit()
Thread(target = check).start()#starts the timer
choice1 = input("Please Enter your choice: ")