Changing the output inside a while True loop - python

I am very new in Python and I decided to make a game.
I want a value to be output like this:
Heat: x #x would always be changing
For that I have the following block of code:
while True:
print("Heat: {}".format(Heat))
but all it does is spam "Heat: xHeat: xHeat: x"
When it should be only one Heat bar
What should I do?

In that code 'Heat' in the loop and it will be printed all the time:
Heat = 0
while True:
Heat +=1
print ('Heat: {heat}'.format(heat=Heat))
In that code 'Heat' out of the loop and it will be printed once:
Heat = 0
print ('Heat:')
while True:
Heat +=1
print ('{heat}'.format(heat=Heat))
if you want more newlines use '\n' char (strictly depends on OS).

You can use carriage return to send the cursor to the start of the line.
import sys
while True:
sys.stdout.write("\rHeat: {}".format(Heat))
sys.stdout.flush()
But this approach doesn't sound like you will be able to extend it into any sort of game.
You should look up the python curses library for complete control over the console output.
Also if the number of digits in your output changes then you might want to right-align the output so that you don't get any left-overs. This code demonstrates what happens if you go from a 2 digit number to a 1 digit number:
import sys
import time
for heat in reversed(range(5, 12)):
time.sleep(0.5)
sys.stdout.write("\rHeat: {:>5}".format(heat))
sys.stdout.flush()

Related

How do I make the print statement from this code stay in one line? [duplicate]

This question already has answers here:
How to output to the same line overwriting the previous line?
(4 answers)
Closed last year.
How do I make the print statement from this code stay in one line?
import time
bitcoin = 0
while 1 == 1:
time.sleep(1)
print(f"Bitcoin: {bitcoin}")
Try this:
import time
bitcoin = 0
while 1 == 1:
time.sleep(1)
print(f"\r\xb[{2}KBitcoin: {bitcoin}",end='')
bitcoin+=1
basically, \r is the escape code for carriage return, meaning it goes back to the start and writes over the previous line. \x1b[{2}K clears the line,(the previous bitcoin value). end='' means that print doesn't go down to a new line.
Another solution, if you know exactly what terminal coordinates you want the text is:
import time
bitcoin = 0
x=10
y=0
def posprint(string,x=0,y=0):
print('\u001b[s')
print(f'\x1b[{y};{x}H\x1b[{2}K')
print(f'\x1b[{y};{x}H',string)
print('\u001b[u',end='')
while 1 == 1:
time.sleep(1)
posprint(f"Bitcoin: {bitcoin}",x,y)
posprint takes the coordinates you enter into it, and prints the text at those coordinates. I use ansi escape codes here to navigate to the position and clear the line before printing the string at that location.
Again, here \x1b[{2}K clears the line, but this time \x1b[{y};{x}H first travels to the x and y coordinates. Then, after clearing the line, the function goes back to the coordinates, and then finally prints the string.
The function also goes back to where the cursor was last. \u001b[s saves the cursor position and \u001b[u restores the position of the cursor.

How to Print Something Every Other Time Something Happens

I'm trying to learn python and while learning I've come across a bit of a problem.
import time
import pyautogui
def SendScript():
time.sleep(2)
with open('script.txt') as f:
lines = f.readlines()
for line in lines:
time.sleep(2)
pyautogui.typewrite(line.strip())
pyautogui.press('enter')
SendScript()
I'm trying to print something to the screen every second time the 'enter' key has been pressed, but I'm an extreme beginner so I really don't know how to do that. Could someone help me accomplish this task?
You could create a new boolean variable to track if the enter key has been pressed before. That way, every time the for loop iterates, the value of pressed switches and only when the value of pressed is True will it print something.
import time
import pyautogui
def SendScript():
pressed = False
time.sleep(2)
with open('script.txt') as f:
lines = f.readlines()
for line in lines:
time.sleep(2)
if pressed:
print("Something")
pressed = not pressed
pyautogui.typewrite(line.strip())
pyautogui.press('enter')
SendScript()
From a more step-back approach, you could do:
events=['event1', 'event2', 'event3', 'event4', 'event5', 'event6', 'event7', 'event8']
counter = 0
for event in events:
counter += 1
if counter % 2 == 0: # ie do stuff when divisible by 2, ie when its even
print('print what you want to be printed every second time')
else:
pass
Of course you are not looping through events like I do in this example. The point is counting the events and only doing stuff when this count is even.
As indicated in another answer already, a simple toggle can be implemented with a bool and then code which toggles it every time something happens:
thing = False
:
if happens(something):
thing = not thing
This is fine for toggling between two states. A more general approach which allows for more states is to use a numeric variable and a modulo operator:
times = 0
maxtimes = 12
:
if happens(something):
times += 1
if times % maxtimes == 1:
print("ding dong")
The modulo could be compared to 0 instead if you want to print on the 12th, 24th etc iterations instead of the first, the 13th, etc, or of course any other offset within the period if that's what you want.
Another useful trick is to flip-flop between zero and some other value.
value = 0
othervalue = 1234
:
if happens(something):
value = othervalue - value
Of course, you can flip-flop between any two values actually; subtract the current value from their sum to get the other one.
Needless to say, just toggling or flip-flopping isn't very useful on its own; you'd probably add some (directly or indirectly) user-visible actions inside the if happens(something): block too.
You could use a generator for this:
def everySecondTime():
while True:
yield "hi"
yield "not hi"
mygen = everySecondTime()
print(next(mygen))
print(next(mygen))
print(next(mygen))
print(next(mygen))
This prints
hi
not hi
hi
not hi
I'm sure it's clear to you how you could adapt this to do some other actions instead.
Whether this approach is better than just using a boolean is highly debatable, but I thought I'd leave it here so you could learn about generators (the yield keyword) if you want to.

How To Print Grid In Python Without "Flashing" Screen

In the program I've been working on in Python, I need to be able to print a list of elements one by one, going to a new line after n elements to form a grid. However, every time the program reprints the grid, you can see it progressing element by element, which looks rather ugly and distracting to the user. I was wondering if there was a way to "pause" the console output for a brief amount of time to allow the grid to be printed, then show the grid afterwards, erasing the previous printout, as to not show it printing element by element. The reason I need to do this is because the program uses Colorama for colored outputs, but different elements in the list will need to have different colors, meaning each element has to be printed one by one.
EDIT (Current code):
import time as t
from os import system as c
h = 50
w = 50
loop1 = 0
ostype = "Windows"
def cl():
if(ostype == "Linux"):
c('clear')
if(ostype == "Windows"):
c('cls')
def do():
grid = []
for x in range(0,h):
temp = []
for z in range(0,w):
temp.append("#")
grid.append(temp)
for a in range(0,h):
for b in range(0,w):
print(grid[a][b], flush=False, end="")
print()
while(loop1 == 0):
do()
t.sleep(1)
cl()
You can probably tell print to not to flush the standard out buffer, and have the last print to flush everything. Depends on what version of python you're using, for python 3 print function takes a flush argument, set that to true/false accordingly.

Python random.randint stops randomizing after a few loops

I'm running a python script that will display messages on a board. One of the subroutines that I've created is supposed to grab a random line from a small text file, and display that line. It mostly works, except after looping a few times, it gets stuck on the same number, and just displays the same thing over and over.
I am running this in Python 2.7, on a Raspberry Pi in Raspbian. I am using this github as the base for the project, and added lines of my own to it:
https://github.com/CalebKussmaul/Stranger-Things-Integrated
This is part of a halloween display that will be Stranger Things-themed, so the preloaded messages have a reference to the show. I noticed this issue the other day, and have been pouring over the internet to try and figure out what the problem could be. I've tried doing different methods of selecting a randomized number, including some in some similar (but different) threads on this site. All of them produce exactly the same issue.
Below is the subroutine I created:
def preloaded_messages():
print "Preloaded Messages thread is loaded."
global displaying
while True:
if not displaying:
with open('preloaded_messages.txt') as f:
lines = len(f.readlines())
rgn = random.randint(1,lines)
msg = linecache.getline('preloaded_messages.txt', rgn)
print "rng: ", rgn
print "total lines: ", lines
print "line: ", msg
print "displaying from preloaded_messages.txt: ", msg
display(msg)
time.sleep(10)
And here's my preloaded_messages.txt file:
help me
im trapped in the upside down
leggo my eggo
friends dont lie
run /!
hopper is alive
rip barb
demogorgon is coming /!
mouthbreather
When I run it, my output is like this:
rng: 6
total lines: 9
line: hopper is alive
rng: 2
total lines: 9
line: im trapped in the upside down
rng: 9
total lines: 9
line: mouthbreather
...
rng: 9
total lines: 9
line: mouthbreather
the first few times are always random (and the number of times it successfully randomizes varies), but when it gets on 9, it just stays there for as long as I let it run. I am at a loss as to why it works the first few times, but not once it gets to 9.
EDIT: Interestingly, as I've been writing this, I also tried adding a blank line at the end, and while it looked like it'd be stuck again, as it did that one three times in a row, then it finally moved to others. I'm not sure how that changes things. And ideally, I'd rather not have the blank line in there, as it eats up time displaying nothing. So it'd be nice to fix the issue. Anyone have any ideas?
It is reseeding the random generator. See line 49 of stranger.py in the https://github.com/CalebKussmaul/Stranger-Things-Integrated: random.seed(i).
The color_of function should be written as:
def color_of(i):
"""
This function generates a color based on the index of an LED. This will always return the same color for a given
index. This allows the lights to function more like normal christmas lights where the color of one bulb wont change.
:param i: index of LED to get color of
:return: a pseudorandom color based on the index of the light
"""
_random = random.Random(i)
rgb = colorsys.hsv_to_rgb(_random.random(), 1, 1)
return int(rgb[0] * 255), int(rgb[1] * 255), int(rgb[2] * 255)
To create its own Random instance with the given seed rather than reseeding the Random instance that is a singleton in the random module.
This appears to work for me. Note that I'm seeding the RNG.
import time
import random
from datetime import datetime
def preloaded_messages():
print("Preloaded Messages thread is loaded.")
displaying = False
while True:
if not displaying:
with open('preloaded_messages.txt') as f:
random.seed(datetime.utcnow())
text = f.read().splitlines()
msg = random.choice(text)
print("line: ", msg)
# print("displaying from preloaded_messages.txt: ", msg)
time.sleep(10)
if __name__ == "__main__":
preloaded_messages()

Count # of times a certain outcome appears when randomly selecting from a list of possible outcomes

My code generates random outcomes of the list "outcomes". I am running batches of 10,000+, and I need a way to count the batches and total them at the bottom. How would I do this?
Here is my code:
import random
import time
from time import sleep
outcomes = ['TT','Tt','Tt','tt']
for x in range (0, 5):
b = "LOADING OUTCOMES" + "." * x
print (b, end="\r")
time.sleep(0.5)
print("4 Possible Genetic Outcomes Will Be Shown. . . ") ; sleep(1)
for x in range (0, 10000):
print(random.choice(outcomes))
time.sleep(0.001)
x=input("Done determining outcomes!! Press enter to close")
from collections import Counter
from random import choice
outcomes = ["TT", "Tt", "Tt", "tt"]
totals = Counter(choice(outcomes) for _ in range(10000))
which gives something like
Counter({'TT': 2528, 'Tt': 4914, 'tt': 2558})
This is using the code you provided in the screen shot. Here is how I would go about it. Check if this solution works for you. Next time please put the code inside the question itself and not as an image. It will attract more people to help you since they can just copy paste your code and help you out quicker instead of typing out your code themselves.
How I solved it:
have a dictionary already predefined with the possible choices from the list. Each time a choice appears, just increment the counter by 1. At the end print all the possibilities. You can use a loop to do this, but since there are only 3 elements I decided to just print them out.
import random
import time
from time import sleep
outcomes = ["TT", "Tt", "Tt", "tt"]
outcomesCount = {"TT":0, "Tt":0, "tt":0}
for x in range(0,5):
b = "LOADING OUTCOMES" + "." * x
print(b, end="\r")
time.sleep(0.5)
print("4 Possible Genetic Outcomes Will Be Shown. . . ")
sleep(1)
for x in range(0,10000):
choice = (random.choice(outcomes))
time.sleep(0.001)
outcomesCount[choice] += 1
print(choice) #This is something you were doing in original code. I would not do this because there are too many print statements, and will cause the program to run for a while.
print("The number of times each outcome appeared was: ")
print("TT : %s" %(outcomesCount["TT"]))
print("Tt : %s" %(outcomesCount["Tt"]))
print("tt : %s" %(outcomesCount["tt"]))
x = input("Done determining outcomes!! Press enter to close")
The output of running the above program was note this is only the last print statements:
The number of times each outcome appeared was:
TT : 2484
Tt : 4946
tt : 2570
Done determining outcomes!! Press enter to close
improvements:
1. get rid of the sleep because you are just delaying the program execution. You don't need it there. If you want the user to see the loading message for a second of two, you can just add 1 pause at the end.
The sleep in the second for loop is not needed at all. This is a computer and is capable of doing amazing things. This is nothing compared to what it can handle.
dont print all the outcomes, as it is going to be printing 10000 different rows.
Good luck and hope this helped.

Categories

Resources