I am currently working on a text-based game and I would like to add a delay in the appearance of a text. The text where I want the delay is the third descendant of an if-else command.
I've tried time.sleep() function but that doesn't seem to work.
if path.lower().strip() == "yes":
print("Then let your journey begin")
else:
print("\nWell,")
print("You don't have much of a choice do you.")
# the text I need to delay ^^^
So what I'm hoping to do is add a few seconds of delay to the entrance of the commented text.
import time
# ...
if path.lower().strip() == "yes":
print("Then let your journey begin")
else:
print("\nWell,")
time.sleep(3) # parameter used here is in seconds
print("You don't have much of a choice do you.")
# the text I need to delay ^^^
time.sleep(secs)
secs - The number of seconds the Python program should pause execution. This argument should be either an int or a float.
Suspend execution of the calling thread 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.
Changed in version 3.5: The function now sleeps at least secs even if the sleep is interrupted by a signal, except if the signal handler raises an exception (see PEP 475 for the rationale).
Related
Im trying to make a countdown timer with the feature to reset/stop/pause/resume. I tried implementing an if/elif/else statement to check for user input letter within the while loop while it continues looping. However, the loop stops running when the conditional statement executes. How do I implement my intended functionality into the code?
code:
import time
import datetime
def timeinput():
# Inputs for hours, minutes, seconds on timer
h = input("Enter the time in hours: ")
m = input("Enter the time in minutes: ")
s = input("Enter the time in seconds: ")
countdown(int(h), int(m), int(s))
# Create class that acts as a countdown
def countdown(h, m, s):
# Print options for user to do
print("Press w to reset \nPress s to stop \nPress a to pause \nPress d to resume")
# Calculate the total number of seconds
total_seconds = h * 3600 + m * 60 + s
# While loop that checks if total_seconds reaches zero
# If not zero, decrement total time by one second
while total_seconds > 0:
# Timer represents time left on countdown
timer = datetime.timedelta(seconds = total_seconds)
# Prints the time left on the timer
print(timer, end="\r")
# Delays the program one second
time.sleep(1)
# Reduces total time by one second
total_seconds -= 1
user=input()
if user=="w":
total_seconds=0
print("Timer will now reset")
timeinput()
print("Bzzzt! The countdown is at zero seconds!")
timeinput()
result:
outcome of code
As shown in the provided image, the loop stops at 20 secs. My intended action here was for the countdown to continue until the user presses the W key, which shall then reset the countdown back to its original set time at initialization.
Soo, I'm also kinda new to programming and python so I don't exactly how to make a timer with that functionality. What is happening is that when you use the input() function the code stops and waits for the user input.
I know you can use some libraries, like pygame, in order to check for user input inside the loop without stopping it, but without one I'm not sure how to do it.
You can also use the module keyboard, that comes inside python, and I think is great for the problem you shared. Check this post How to detect key presses?
The command input() is blocking. It waits until it get something from the console. Maybe take a look at this post and try to implement a non blocking version of input. Non-blocking console input?
The problem is that input is blocking - that is, it will stop the execution until the user presses < enter> .
Antique running environments, on 8 bit computers, using Basic, could check "what the user is pressing right now", without waiting for a confirmation with "enter" using the inkey command.
In Python programs running on terminal, terminedia, a 3rdy party library, implements inkey() as it was - but it needs the terminal input to be reconfigured for which it provides a "keyboard" context manager.
You can then run almost the same code you have -just install terminedia in your Python environment with "pip install terminedia"
import terminedia as TM
...
def countdown(h, m, s):
...
while total_seconds > 0:
# Timer represents time left on countdown
timer = datetime.timedelta(seconds = total_seconds)
# Prints the time left on the timer
print(timer, end="\r")
with TM.keyboard:
# Delays the program one second
time.sleep(1)
# Reduces total time by one second
total_seconds -= 1
user=TM.inkey()
if user=="w":
total_seconds=0
print("Timer will now reset")
timeinput()
print("Bzzzt! The countdown is at zero seconds!")
timeinput()
(disclaimer: I am terminedia author)
Taking inputs from the answers received here and subsequent follow-up questions on stack overflow and Reddit, this question has been solved using pygame. I'll provide the link below for future reference to this question.
problem solution
This is my attempt:
from inputimeout import inputimeout, TimeoutOccurred
import time
import sys
import os
def get_choice(maxtimeout=9):
try:
for remaining in range(maxtimeout, 0, -1):
sys.stdout.write("\r")
sys.stdout.write(
"Want to continue to next item(Y/N)? Defaults to Y in {:2d} seconds...".format(
remaining + 1
)
)
sys.stdout.flush()
time.sleep(1)
c = inputimeout(prompt="", timeout=1)
except TimeoutOccurred:
c = "Y"
return c
The issues with my approach are:
The inputed key is not visible until the timeout completes.
The user has to press enter after his choice.
The user has to wait till timeout completes irrespective of when he entered the value.
There are two problems to solve here to meet your preferred requirements.
First, here's a simple example of how you can use a signal timer to give the user some amount of time to input an answer:
import signal
def input_timeout(*ignore):
raise TimeoutError
signal.signal(signal.SIGALRM, input_timeout)
signal.setitimer(signal.ITIMER_REAL, 10)
try:
inp = input("enter something: ")
signal.setitimer(signal.ITIMER_REAL, 0)
except TimeoutError:
print("you took too long!")
What this does is set a timer to go off after 10 seconds (you can use fractional time if you want, say, 2.5 seconds). If the user hasn't input anything before the timer goes off, it raises the TimeoutError exception, breaking the input prompt. If the user does enter something, it disables the timer by setting it to zero. If the timer does fire and calls input_timeout(), it passes two arguments (the signal number and the interrupted stack frame) but you can usually ignore them, so I've set those arguments as *ignore.
Here's a question that covers this approach in more detail: Python timeout decorator. The reason I didn't just point you to that is so that you could see the bare essence of the process and decide for yourself how to use it. Plus, well, when I pasted the code and tried to use it, it didn't work. You can decide how to proceed as meets your needs.
The second issue is you mention the problem with your approach is the user having to press enter. Here's a question that covers that topic: raw_input in python without pressing enter. In short, there's not a simple built-in solution for that.
I am writing a long-term prime search program, that can be closed and reopened with a system of writing out found primes to file. I do not want help with the algs, but I need a method of killing the program only when it gets to the end of the main loop i.e. it has fully found a prime. The relevant parts of code are below.
check = 7
def isprime(n):
#do...
while True:
if isprime(check):
print(check, "is prime")
else:
print(check, "isn't prime")
check += 2
This code will not work, but it is a good template as my question is not specific to my program. I want to break out of the main while True loop, only when at the end of it. The only solution I could think of, which is not practical at all, is at the end of while True I read in a file and if it is "stop" I break. However, I don't want to have to type into a file when I want to stop, and reading a file is a time-waster.
I am sorry if this question appears opinion based, but I tried my best.
Threading is a good option as suggested by others. However, you can have a lighter option of using a try/except catching a keyboard interrupt and using an end flag. If the kill signal is sent during the isprime() calculation, the current calculation for isprime() will be killed, check will not be incremented by 2, the except block will execute to switch the end flag to True, and then you will re-start the isprime calculation for the previous check until you are done, increment, then break. The advantage of this method is that it is lighter than having the overhead of creating a new thread (which is small compared to creating a new process) and that it is easier to debug than a multithreaded script. However, the multithreaded option is fine to debug if the code will not get much bigger and you won't be needing other threads as a part of the same script.
end = False
while True:
try:
if isprime(check):
print(check, "is prime")
else:
print(check, "isn't prime")
check += 2
if end:
break
except KeyboardInterrupt:
print('end signal received')
end = True
You can define a function to create a prime and another function to listen to KeyboardInterrupt signals as Ralf commented. In your prime function at the end do a
if not Keyboard_thread.is_alive():
break
This will have your code check that it has not been stopped only at the end of the cycle, thereby avoiding terminating your program mid calculation. Threading documentation is at https://docs.python.org/2/library/threading.html for more depth! essentially though you want to do something like
t = threading.Thread(target=your_function, args=[your_list_of_parameters](arguments are optional))
t.start()
Sorry if you already know threads, but it wasn't part of your post so I will assume you do not.
You can call t.join() to end your thread that is waiting for keyboard interrupts (specifying a timeout), or have your function come to an end by breaking. Doing so will then flag your other thread (the one checking if keyboard_thread.is_alive() that it should also break out of its loop. Note: threads only run until the end of the function you assign them, so for instance if your function is:
def new_function():
print("hey")
If you assign a thread to this function, the thread will print "hey" once and then terminate itself upon reaching the end of the function. Feel free to leave a comment if something I said is unclear!
So I am creating just a basic game, where you purchase ballons and every balloon you buy raises the amount of money you have get per second. But I cant seem to work out how to add the money on every second, considering I already have a While loop and you can't have another one
This is my code
###Game###
import time
money=1
money_ps=0
score=0
while True:
time.sleep(1)
money=money+money_ps
while score==0:
inp=input().lower()
if inp=="buy" or inp=="purchase":
print("What would you like to buy")
print("•Red Balloon (£1)")
print("•Blue Balloon (£100)")
print("•Yellow Balloon (£10000)")
print("•Green Balloon (£1000000)")
print("•Pink Balloon (£100000000)")
inp=input().lower()
if inp=="red balloon":
if money >= 1:
money_ps=money_ps+0.1
money=money-1
print("You successfully bought a Red Balloon")
else:
print("You are unable to afford this")
elif inp=="blue balloon":
if money >= 100:
money_ps=money_ps+1
money=money-1
print("You successfully bought a Blue Balloon")
else:
print("You are unable to afford this")
elif inp=="bank":
print("You have £",money)
Any help is greatly appreciated
Your problem is that your main loop is blocking on those input calls. Fortunately, this is really just a special case of the fundamental problem behind GUI applications, 3D games, and network servers, so the solutions are pretty well known. Unfortunately, the solutions can be a bit complicated, or at least require a lot of learning.
One solution is asynchronous I/O. If you read from a non-blocking file (input just reads from sys.stdin, which acts like a file, even though it isn't on disk), you can use a loop from selectors, or something higher-level like asyncio, to wait, with a timeout, until it's ready, instead of waiting forever. Or you can go below the level of stdin and loop over waiting (with a timeout) for events from the console or the OS and then put those events together into input. Or you can use a higher-level library like curses to do that for you.
The other solution requires less rethinking of your code: Let your main thread spend all its time running a loop around input, and use a background thread that runs a different loop, one which updates your money and then sleeps for a second.
See the threading docs for details and some examples, but you're probably going to want to work through a more thorough tutorial. Anyway, here's the changes you need to make the money loop run in a thread:
money = 1
money_ps = 0
money_lock = threading.Lock()
def money_loop():
global money
global money_ps
global money_lock
while True:
time.sleep(1)
with money_lock:
money=money+money_ps
money_thread = threading.Thread(target=money_loop, args=())
money_thread.start()
Now, we also have to make sure to use the same Lock whenever we want to access money or money_ps in the main thread:
if inp=="red balloon":
with money_lock:
if money >= 1:
money_ps=money_ps+0.1
money=money-1
print("You successfully bought a Red Balloon")
else:
print("You are unable to afford this")
And that's it; now it will work.
Except for one problem: you need a way to tell the background thread to stop when it's time to quit. If your whole program is just going to quit at the same time, then there's a quick and dirty solution to this: using a daemon thread:
money_thread = threading.Thread(target=money_loop, args=(), daemon=True)
Daemon threads get hard-killed as soon as the main thread exits. If your background threads are, say, rewriting files, this can be dangerous, because you can end up with corrupted files only half-way written. But here, all your background thread does is sleep and modify some variables used by the main thread, which doesn't care about them anymore at quitting time, so it's safe.
There are multiple approaches to writing event loops in games. Threading and asyncio are some of the more advanced approaches you may want to consider.
But the simplest approach is to put all the updates inside your while loop. Import time, and add an if statement inside the main loop that checks if at least one second has passed since the last update. If it has, update your state variable.
Game engines will often have a task loop inside the main loop that has a list of any entity that needs to change over time. It then calls an update() method on each entity. Then each entity will check the clock and decide how much to change based on the current time.
while True:
for entity in entities:
entity.update()
But, your input calls will block the main loop from running. Consider using tkinter for input instead, since this won't block.
The other answers have done a good job of introducing you to multithreading and event loops, which will be the right answer if you need to report changes to the user while waiting for input. But in your case, since you're not reporting new money as it is added, you could just wait until you get input, then update the money status. That is, you can update the money status from your main input loop, like this:
import time
money = 1
money_ps = 0
score = 0
last_update_time = int(time.time())
def update_money():
global money, last_update_time
new_time = int(time.time())
money = money + (new_time - last_update_time)
last_update_time = new_time
while score==0:
inp=input().lower()
update_money()
if inp=="buy" or inp=="purchase":
print("What would you like to buy")
print("•Red Balloon (£1)")
print("•Blue Balloon (£100)")
print("•Yellow Balloon (£10000)")
print("•Green Balloon (£1000000)")
print("•Pink Balloon (£100000000)")
inp=input().lower()
update_money()
if inp=="red balloon":
if money >= 1:
money_ps=money_ps+0.1
money=money-1
print("You successfully bought a Red Balloon")
else:
print("You are unable to afford this")
elif inp=="blue balloon":
if money >= 100:
money_ps = money_ps+1
money = money - 1
print("You successfully bought a Blue Balloon")
else:
print("You are unable to afford this")
elif inp=="bank":
print("You have £", money)
I wrote a Python script that executes an optimization and runs days to get a solution (due to the costly objective function). In all days work it will be sufficient to just stop the calculation at some point because the solution is good enough for me (but not for the optimization algorithm).
The problem is, I can always abort hitting Ctrl+C. But then there is no chance to nicely output the current best parameters, plot the data, save it etc. It would be great to stop the script in a controlled way after the next calculation of the objective function. So my thought was so question some variable (if user_stop=True) and programatically stop the optimization. But how to set such a variable? The python console is blocked during execution.
I thought about setting the content of a text file and reading it in each iteration but it's more than poor and hard to explain for other users of the script. Theoretically, I could also ask the user for an input but than the script won't run automatically (which it should until someone decides to stop).
Any ideas for my problem?
Basically that's it - stop the loop at some point but execute the print:
a = 0
while True:
a = a + 1
print(a)
If you poll your "variable" infrequently (say at most once every 20 seconds) then the overhead of testing for a file is negligible. Something like
import os
QUITFILE = "/home/myscript/quit_now.txt"
# and for convenience, delete any old QUITFILE that may exist at init time
... # days later
if os.path.isfile( QUITFILE)
# tidy up, delete QUITFILE, and exit
Then just echo please > home/myscript/quit_now.txt to tell your program to exit.
maybe you can use a do-while loop. holding your target in a varible
outside the loop and start looping the calculatio while <= your target calculation.
For Windows, I would use msvcrt.getch()
For example, this script will loop until a key is pressed, then, if it is q, prompt for the user to quit: (Note that the if statement uses 'short circuiting' to only evaluate the getch() - which is blocking - when we know that a key has been pressed.)
import msvcrt, time
while True: #This is your optimization loop
if msvcrt.kbhit() and msvcrt.getch() == 'q':
retval = raw_input('Quit? (Y/N) >')
if retval.lower() == 'y':
print 'Quitting'
break #Or set a flag...
else:
time.sleep(1)
print('Processing...')
If you place this if block at a point in the optimization loop where it will be frequently run, it will allow you to sop at a convenient point, or at least set a flag which you can check for at the end of each optimization run.
If you cannot place it somewhere where it will be frequently checked, then you can look at handling the KeyboardInterrupt raised by Ctrl-C
If you are running on Linux, or need cross-platform capability, have a look at this answer for getting the keypress.