Slow text printing in a function? - python

Is there a way in Python3 to slow the text that is inside a function?
I have created a text-based game that uses almost exclusively functions for each section of the game, but want the text within to be typed out.
For example:
def room_1():
Print("You are in a foyer.")
Print("You can see a painting on the wall.")
etc.
I have already imported, sys,time and is.
I have tried putting this inside the function but it doesn't seem to work:
for char in room_1():
Sys.stdout.write(char)
Sys.stdout.flush()
Time.sleep(0.1)

You were close, but you should look up some tutorials on how iterators work with Python. print doesn't return a value and your room_1 definition also doesn't return anything so your code was not entering the for loop.
I would recommend making a function that will print slowly.
import sys
import time
def slow_print(input_str):
for c in input_str:
sys.stdout.write(c)
sys.stdout.flush()
time.sleep(0.1)
sys.stdout.write('\n')
def room_1():
slow_print("You are in a foyer.")
slow_print("You can see a painting on the wall.")
room_1()

Related

Passing print function within another function

I decided I would create a simple text-based game as a learning project for Python as this is my first time using it. I have this function slow_print that simulates human typing which works in it's current form for strings, however is it possible to pass through a function instead. As I would like to break up the game text into sections for tidiness.
def slow_print(t):
for letter in t:
sys.stdout.write(letter)
sys.stdout.flush()
time.sleep(random.random()*10.0/55)
print ('')
def intro():
print("Welcome, this is a text-based adventure game.")
print("This isn't designed for the light hearted so proceed at your own peril.")
...
...
Is this possible in Python? After playing around with the params and passing it through I got the error of "Python object is not iterableable". From my understanding strings would be iterateable. Would there be another easier way to accomplish this?
slow_print(intro())
ERROR:
Traceback (most recent call last):
File "C:\Users\CDN Admin\Python\game.py", line 20, in <module>
slow_print(intro())
File "C:\Users\CDN Admin\Python\game.py", line 9, in slow_print
for letter in t:
TypeError: 'NoneType' object is not iterable
It seems like you should rename the variable str inside the function slow_print.
str is a reserved keyword in python and it should be the cause of your error.
I have tried this solution without issues:
import sys
import time
import random
def slow_print(t):
for letter in t:
sys.stdout.write(letter)
sys.stdout.flush()
time.sleep(random.random() * 10.0 / 55)
print('')
if __name__ == '__main__':
slow_print("Welcome, this is a text-based adventure game.")
slow_print takes text and slowly prints it. For it to work, you have to give it text.
intro does not return text. It prints text directly, then automatically returns None, the default return value for functions that don't explicitly return something else. slow_print then receives None and tries to slowly print it, but None is not text.
You need to restructure your code so the text that needs to be slowly printed is passed to slow_print instead of print. That might involve giving intro a parameter to select how to print things:
def intro(printer=print):
printer("Welcome, this is a text-based adventure game.")
printer("This isn't designed for the light hearted so proceed at your own peril.")
...
...
intro(slow_print)
In this modified code, intro has a printer parameter that it will use to print things. This parameter defaults to the built-in print function, but if you pass slow_print instead, intro will use slow_print to print its messages.
slow_print(intro()) prints what intro() returns, and this function does not return anything. You can rewrite this function.
def intro():
rerurn '''Welcome, this is a text-based adventure game.
This isn't designed for the light hearted so proceed at your own peril.'''
Then your slow_print will print intro message.
P. S. If you use intro() elsewhere, you should replace intro()to print(intro()).

printing every thing slowly (Simulate typing)

[printing slowly (Simulate typing)
I got my answer from the link above but it only works when you put the string as a parameter when calling function.
I want the code to print slowly every time when I use print().
is it possible?
Yes, you can do it like this, however, I think it's not a good idea:
import time
def dprint(string):
for letter in string:
__builtins__.print(letter,end = '', flush=True)
time.sleep(.1)
__builtins__.print("")
print = dprint
print("something")
Yes, you can do it using the stdout version as below.
import sys, time
def print(s):
for letter in s:
sys.stdout.write(letter)
time.sleep(.1)
print("Foo")
Changing the default behaviour of print() is not recommended and was only introduced for purpose of porting Python 2 programs easily. Moreover overloading the print function without a special parameter will make the default functionality of print() moot.
Create another function with adds a delay to the prints. Also remember that you cannot use print() because it appends a new line. You’ll have to you sys.stdout.write()
So a basic function would look like:
def typrint(x):
for i in len(x):
sys.stdout.write(x[i])
sleep(0.05)
sys.stdout.write(“\n”)
Check this article to see why Python updated print() to a function
I am using this as the solution for the problem,
import sys,time
def delay(str):
for i in str:
sys.stdout.write(i)
sys.stdout.flush()
time.sleep(0.04)
Note: You need to add in every print statement or here "delay" statement "\n".

Whole program typing effect

I'm making a text adventure game in Python 3. Is there any way to add a typing effect to any text that gets printed without repeating a command after every line?
Assuming that with "typing effect" you mean that the messages should slowly appear one character at a time, you can define a function that iterates the given message and prints it one character at a time, using time.sleep in between to wait a bit. Make sure to flush the buffer after each character.
import time
def slow_print(msg):
for c in msg:
print(c, end="", flush=True)
time.sleep(0.1)
print()
slow_print("Hello World!")
If you really want to apply this for each and every output in your game (which I'd really not recommend) you can overwrite the print function, keeping a reference to the original print function to use within your new slow print function.
original_print = print
def slow_print(msg):
# same as above, but using original_print instead of print
print = slow_print
print("Hello World!")
You could also just def print(...) directly, but I'd recommend defining it as a separate function and then assigning it to print. This way, you can still make this optional, as this will most likely annoy the player after the first few minutes.
I assume you want the characters to appear as if someone were typing them so I'll just assume that
Import modules
import os
import sys
import time
from colr import color
Define your function
def function_name(phrase,speed,r_value,g_value,b_value):
for char in phrase:
sys.stdout.write(color(char, fore=(r_value,g_value,b_value)))
sys.stdout.flush()
time.sleep(speed)
Test the function
function_name("Hello",0.05,0,255,0)
#prints the phrase "Hello" in green text
Alternatively you could write the function using the threading library, which would allow users to skip the typing effect if they so wish.
import time, threading, os, sys, tty, termios
from colr import color
def slow_type_interrupt(phrase,speed,r_value,g_value,b_value):
done = False # this acts as the kill switch, using if statements, you can make certain button presses stop the message printing and outright display it
def type_out():
for char in phrase:
if done:
break
sys.stdout.write(color(char,fore=(r_value,g_value,b_value)))
sys.stdout.flush()
time.sleep(speed)
os.system('clear')
print(color(phrase,fore=(r_value,g_value,b_value)))
t = threading.Thread(target=type_out)
t.start()
def getkey():
ky = sys.stdin.fileno()
Ab = termios.tcgetattr(ky)
try:
tty.setraw(sys.stdin.fileno())
key = sys.stdin.read(1)
finally:
termios.tcsetattr(ky, termios.TCSADRAIN, Ab)
return key
while not done:
key_press = getkey()
if key_press == 'a': #You can replace a with whatever key you want to act as the "kill key"
done = True
os.system('clear')
print(color(phrase,fore=(r_value,g_value,b_value)))
slow_type_interrupt("Hello this is a test. Pressing 'a' will end this and immediatley display the message",.05,0,255,0)
As I mentioned in the comments of the code, a can be replaced by whatever you want. The reason I use this particular method for retrieving keypresses is because it works on almost anything that runs Python. I would suggest reading up on some other ways to retrieve keyboard inputs.
Hope I could help :)

Get user input while printing to the screen

I would like to get user input while printing to the screen. I researched this a lot. but didn't find anything. I'm not very advanced with class programming in Python, so I didn't understand the other examples on stackoverflow.
Example:
import time
def user_input():
while True:
raw_input("say smth: ")
def output():
while True:
time.sleep(3)
print "hi"
input()
output()
I want the prompt to stay, even if the output is printing "hi". I already tried an example, but the input prompt disappears even if it is in a while loop.
First, let's go over your code
import time
def user_input():
while True:
raw_input("say smth: ")
def output():
while True:
time.sleep(3)
print "hi"
input()
output()
You are calling input() which is not actually your function name. It's user_input(). Also, once user_input() is called, output() will never be called because the while True condition in user_input() is always True, meaning it never exits outside the function.
Also, if you want to do something with multithreading, but you don't understand classes in Python, you should probably do a tutorial related to classes.
Take a look at this other StackOverflow Post on a multithreaded program.

More efficient text-based loading bar

I am making a program that has a "loading bar" but I can't figure out how to make the code shorter. This might be a simple fix for all I know, but for the life of me, I just can't figure it out. Here is what I have tried to do so far:
def ldbar():
print "Load: 1%"
time.sleep(0.5)
os.system('clear')
print "Load: 2%"
time.sleep(0.5)
os.system('clear')
print "Load: 3%"
time.sleep(0.5)
os.system('clear')
print "Load: 4%"
time.sleep(0.5)
os.system('clear')
print "Load: 5%"
#So on and so forth up to 100%
ldbar()
So, like I said, is there anyway I can make this shorter?
This should work:
def ldbar():
for i in range(1, 100):
print "Load: {}%\r".format(i),
sys.stdout.flush()
time.sleep(0.5)
ldbar()
It uses a for loop to avoid having the same code over and over again. In the print statement I use \r which moves the cursor to the front of the line, allowing it to be overwriten which is why sys.stdout.flush is used to make sure the output is printed without a newline (notice the comma at the end of the print statement which says that a newline should not be printed).
For Python 3 you would use this (but I think you're using python 2):
def ldbar():
for i in range(1, 100):
print("Load: {}%\r".format(i), end="")
sys.stdout.flush()
time.sleep(0.5)
ldbar()
Here's a nice version using a context manager:
from contextlib import contextmanager
import sys
#contextmanager
def scoped_progress_bar(num_steps, message):
class Stepper(object):
'''
Helper class that does the work of actually advancing the progress bar message
'''
def __init__(self, num_steps, message):
self.current_step = 0.0
self.num_steps = num_steps
self.message = message
def step(self, steps = 1.0):
self.current_step += steps
sys.stdout.write('\r{}:{}%'.format(message, (self.current_step/self.num_steps)*100))
sys.stdout.flush()
stepper = Stepper(num_steps, message) # This is where we actually create the progress bar
yield stepper.step # This is where we do the yield secret sauce to let the user step the bar.
# Finally when the context block exits we wind up back here, and advance the bar to 100% if we need to
if stepper.current_step < stepper.num_steps:
stepper.step(stepper.num_steps - stepper.current_step)
The advantage of this method is that
You can specify an arbitrary number of steps
You can step an arbitrary number of steps
Even if you don't hit the end of the number of steps, the context manager will always print 100% at the end
You can specify an arbitrary message
Usage:
with scoped_progress_bar(10, 'loading') as step:
for i in xrange(7):
step()
time.sleep(0.5)
Which prints:
loading: 10%
loading: 20%
...
loading: 70%
loading: 100%
It's likely a bit overkill for your situation, but thought I'd provide it just in case.
An important thing to note with all of these answers is that they assume you won't be printing out stuff during the process in which you're advancing the progress bar. Doing so will still work just fine, it just might not look like what you expect.
First off, use the Progressbar module (https://pypi.python.org/pypi/progressbar), it already does everything you'll ever want from a text-mode progress bar, and then some.
Now for a fix for your specific implementation, what you want to do is write a bar to stdout (or stderr) with no line return, then erase it, then draw it again. You do it like so:
import sys
import time
sys.stdout.write("0%")
# stdout is line-buffered and you didn't print a newline,
# so nothing will show up unless you explicitly call flush.
sys.stdout.flush()
time.sleep(2)
# Move the cursor back to the beginning of the line
# and overwrite the characters.
sys.stdout.write("\r1%")
sys.stdout.flush()
time.sleep(2)
sys.stdout.write("\r2%")
sys.stdout.flush()
# etc.
But really, use progressbar.

Categories

Resources