Python while loop continues even when false (even if variable declared global) - python

I have a while loop in python that won't stop when false, but unlike other questions, I encountered on stack overflow, I declared my global variable.
import random
score = 0
health = 75
maxhealth = 100
keys = 0
health_potions = 0
skip_stage = 1
cmd = ""
inc = 0
def hiahelp():
#code
def stats():
#code
def oCmds():
global cmd
global inc
global health
if cmd == "stats":
stats()
inc = 0
elif cmd == "help":
hiahelp()
inc = 0
elif cmd == "use health potion":
#healing code
elif cmd == "use":
print("incomplete command")
else:
inc = 1
#intro code
while health > 0:
#more intro code
print("What is HungryIronApple's favorite music artist (besides himself, include proper capitalization)?")
def stage1():
r = True
while r:
global inc
global cmd
global health
if inc == 1:
print("incorrect, try again")
health = health - 10
cmd = input("answer: ")
if cmd == "Alan Walker":
inc = 0
r = False
elif cmd == "left" or cmd == "right":
print("originally I would take health away for such a dumb mistake but because we are just getting started, I'll ignore it")
else:
oCmds()
stage1()
print("the door opens")
quit()
print(f"you died {username}")
I expected it to stop when I die but it continues asking for answers.
Can someone please explain this?
please note I hardly use tag comments and that they are just substitutions.
Below is an example of the running code:

Your while loop is constrained by values of health. The only time health changes within your loop is if inc == 1.
Given your code snippet, it's impossible to say if inc ever changes within your loop (I do see #more code so I'm guessing there's something in there?). Since it starts at 0 and never changes, then health will never change also.
To debug this, take a look at values of inc and health and track their change over time. It may also help you to temporarily change the iteration of while health > 0 to for x in range(100) so that you constrain the repetition and can debug patterns in the change in values for health and inc.

It's pretty obvious that inc is set to 0, and then health doesn't get modified at all.
Thus, the while loop condition never breaks.
The global statement is redundant, in python a scope is limited to 3 possibilities (global, local, nonlocal).
Unlike C, where each block has its own scope.

Related

How do I make my stash function work? Every time I write "stash" it responds with "You have 0 Diamonds". Although I have ran mine several times

This is my code:
import random
Mine_time = 0
Mining = 0
Diamond = 0
def Mine(Mining):
if Doing == "mine" or Doing == "Mine":
Mining = random.randint(0, 10)
print("you mined", Mining,"diamonds ")
def Stash(Mining, Diamond):
if Doing == "Stash" or Doing == "stash":
Diamond = Diamond + Mining
print("You have", Diamond, "diamonds")
def Time(Mine_Time):
if Doing == 'Time' or Doing == 'time':
print('Your Time is:', Mine_time)
def MT(Mine_Time):
if Mine_time > 0:
print("this action is on cooldwon please wait", Mine_time, "seconds")
while True:
Doing = input("\n")
Mine(Mining)
Stash(Mining, Diamond)
Time(Mine_time)
MT(Mine_time)
The possible commands are Stash, Mine, and Time, but time doesn't do anything yet. It would be very helpfull if every time I run Stash it didn't show "You have 0 Diamonds"
Your code has multiple issues, starting with concept and style and ending with the actual fulfillment of the task. I reworked your code so Mine and Stash work logically (leastwise for me).
Disclaimer: the code below is still wrong on multiple points, but I want to post it in this form in order to be understandable for OP.
import random
Mine_time = 0
Mining = 0
Diamond = 0
def Mine():
global Mining
if Doing == "mine" or Doing == "Mine":
Mined = random.randint(0, 10)
print("you mined", Mined, "diamonds ")
Mining += Mined
def Stash():
global Diamond, Mining
if Doing == "Stash" or Doing == "stash":
Diamond = Diamond + Mining
Mining = 0
print("You have", Diamond, "diamonds")
def Time():
if Doing == 'Time' or Doing == 'time':
print('Your Time is:', Mine_time)
def MT():
if Mine_time > 0:
print("this action is on cooldown please wait", Mine_time, "seconds")
while True:
Doing = input("\n")
Mine()
Stash()
Time()
MT()
What I've changed:
Your global variables are now global inside your functions. So they keep their values between cycle's loops.
Mine now firstly obtain random Mined value, this value shown to the user, and then it's added to Mining. So if you mined several times, you lose nothing.
Stash now resets Mining to 0, so mined once wouldn't be added to stash several times.
Not sure how Time and MT should work, so I left them untouched.
What you should change (and also learn):
General structure. If you have some data united with some logic, most probably it's a class. You have to learn what it is and how you should use it for tasks like this, and you wouldn't have such strange situations with variable scopes.
Function concept. Maybe you feel some things, but you definitely don't understand them.
Python code style. Here is quite easy to read intro.

Why doesn’t redefining a function inside another function work? (Python Turtle)

I'm programming a game where enemy turtles (called badturt in the program) chase the user's turtle. The user can make its turtle attack the enemy turtles by sending an attack (another turtle).
In lvl 2, there are two enemy turtles chasing the user's turtle. To make one enemy turtle stop moving (after it is attacked/hit), I tried to redefine the function that makes the enemy turtle move, which was done inside another function.
(I redefined it to None)
attack = turtle.Turtle()
#...attributes
def turtleattack():
global lvl
global q
global w
global e
#... positioning attack
for i in range(75):
attack.forward(10)
if lvl == 1:
Chase(badturt)
if lvl == 2:
Chase(badturt)
Chase(badturt2)
if lvl == 3:
Chase(badturt)
Chase(badturt2)
Chase(badturt3)
IfAttackHit()
bg.onkeypress(turtleattack, 'z')
bg.listen()
def Chase(bt): #makes bad turt (bt) chase turt
bt.setheading(bt.towards(turt))
bt.forward(11)
def StopChase(bt):
global lvl
global win
#global Chase <---------------- program stops running if I write it in
if lvl == 1:
#...
if lvl == 2:
def Chase(bt):
None
if q == 2 and w == 2:
lvl = 3
writeinfo()
if lvl == 3:
def Chase(bt):
None
if q == 3 and w == 3 and e == 3:
#... (winning the game)
def ChaseAgain(bt): #makes badturt chase again when it moves onto next lvl
def Chase(bt):
bt.setheading(badturt.towards(turt))
bt.forward(11)
Chase(bt)
def IfAttackHit():
global win
global lvl
global q
global w
global e
if lvl == 1:
if badturt.distance(attack) < 20:
badturt.hideturtle()
attack.hideturtle()
badturt.goto(300,350)
q = 1
StopChase(badturt) #<---- doesn't work
if lvl == 2:
if badturt.distance(attack) < 20:
badturt.hideturtle()
attack.hideturtle()
badturt.goto(300,350)
q = 2
StopChase(badturt)
if badturt2.distance(attack) < 20:
badturt2.hideturtle()
badturt2.goto(-300,350)
attack.hideturtle()
w = 2
StopChase(badturt2)
if lvl == 3:
#same format as lvl 2 but with addition of badturt3
while True:
if lvl == 1:
while True:
CheckDamage()
if turthealth == 0:
LOSE()
break
IfAttackHit()
Chase(badturt)
if q == 1:
break
break
if lvl == 2:
ChaseAgain(badturt) #make it move again
ChaseAgain(badturt2)
badturt.goto(300,350)
badturt.showturtle()
badturt2.showturtle()
while True:
CheckDamage()
if turthealth == 0:
LOSE()
break
IfAttackHit()
Chase(badturt)
Chase(badturt2)
break
if lvl == 3:
#same format as lvl 2 but with addition of badturt3
break
This didn't work. Was it because it was nested inside another function? Was StopChase() never called? Did the function get redefined again so that the enemy turtle started moving again?
Also, my teacher told me that I had to write 'global Chase' to redefine it within another function, but when I do, the program stops running at that point - when I move my cursor over the turtle screen, it just shows the loading cursor, and nothing happens on the screen/it freezes. (Was it wrong to do that, or is it an issue with the python program on my laptop?)
I also tried redefining Chase() so that badturt would only move forward 0 (essentially making it do nothing), but that didn't work either.
Please let me know what I'm doing wrong, or if there's another way to make badturt stop moving.
When you redefine a non-class method the redefinition is permanent meaning it applies to everything. You probably don't want that.
What speaks against writing a condition inside of your Chase method?
There are various bad coding practices in your code:
You should generally refrain from using global. You should create classes and instances of classes which have attributes and pass those instances around.
Methods aren't capitalized. Classes are capitalized.
You have some unreachable code due to break
Use pass instead of None when nothing is supposed to happen
Tin Nguyen is absolutely right and you should definitely follow his advices. I'd just like to elaborate on your first question. Even if it could be bad, redefining your function using global should work. Here is what I tried as a minimal example:
def f():
print("f")
def g():
global f
def f():
print("f_prime")
f()
g()
f()
When called I get:
f
f_prime
The explanation why your program stops must be elsewhere but you do not provide the error you faced, if any.

Changing a local variable in multiple functions in Python?

background: I'm currently writing a text-based adventure and each enemy has a certain amount of turns you can attack it before it attacks back.
So to handle this the code sets an argument in the function for the fight dictating how many times you can attack.
def fight_sequence(rounds):
while rounds > 0:
attack = input()
if attack == magic:
magic("you teleport away to safety. Congratulations you have stayed alive through your journey and found a few souvenoirs. nice job!", 1, "you muster up all of your energy, chant the spell.... and nothing happens.Cthulu... seems unimpressed", 1, "")
elif attack == sword:
sword(1)
def magic(teleportmessage, teleportsuccess, firemessage, firefail, winmessage):
x = 0
while x == 0:
fightorflight = input("""you open the book to cast a spell
Do you want to try teleporting or use a fireball?""").lower()
if "teleport" in fightorflight:
if teleportsuccess = 1:
print(teleportmessage)
x = 1
else:
choice = input("You can't teleport out of this battle. Would you like to try a fireball?")
if choice == yes:
fightorflight = "fireball"
else:
x = 1
elif "fire" in fightorflight:
print(firemessage)
if firefail == 1:
choice = input("do you want to try to teleport instead?").lower()
if "yes" in choice:
fightorflight = "teleport"
else:
x = 1
else:
print(winmessage)
else:
print("Sorry not sure what you mean")
def sword(attacksuccess):
if attacksuccess == 1:
print("You pull out the sword and swing at the monster damaging it severely.")
else:
print("You pull out the sword and swing at the monster, but its immune to blunt objects.")
fight_sequence(3)
both magic() and sword() need to be able to decrease rounds by 1, originally i just did that before entering the magic or sword function. however some items to attack with allow you to attack more than once if you want so that won't work for them. Such as magic if they also choose to teleport. Is there a way to allow me to change the variable rounds while inside of another function?
I think using a return value might help but I'm not sure how to go about it
You can simply add a new argument to the magic function, and pass the 'rounds' variable through when you call it.
e.g.
def fight_sequence(rounds):
...
magic("some message", false, "fired", false, "you won", rounds)
def magic(teleportmessage, teleportsuccess, firemessage, firefail, winmessage, rounds):
Your passing through the variable (not just the value) so it will change in every context where rounds can be seen.
HTH.
I would recommend using classes to create this game rather than lots of functions, an example of a class in a hero game below.
class Hero:
def __init__(self):
self.health = 10
def eatApple(self):
self.health += 1
def takeDamage(self):
self.health -= 1
init function runs as class is initialized.
player = Hero()
print(player.health) # will print 10
player.takeDamage()
print(player.health) # will print 9
This way you can have global variables for you functions which can be changed in each function and is much more organised.

How can I create a while loop that runs all the time but doesn't interfere with the order that the code runs in?

I'm making a text adventure game in Python to get myself started, as I am not that good at Python yet. I have tried to implement a set of health rules:
while True:
if health == maxHealth:
playerAtMaxHealth = True;
elif health > maxHealth:
health = maxHealth;
elif health < 0:
health = 0
elif health == 0:
playerDead = True;
Here is it with the rest of my code:
def startUp():
StartPRINT("""╔═══╗
║╔══╝
║╚══╦══╦══╦══╦══╦══╗
║╔══╣══╣╔═╣╔╗║╔╗║║═╣
║╚══╬══║╚═╣╔╗║╚╝║║═╣
╚═══╩══╩══╩╝╚╣╔═╩══╝
─────────────║║
─────────────╚╝ \n""")
global gold
global health
global inventory
global berryCollected;
global maxHealth;
global playerAtMaxHealth;
global playerDead
berryCollected = False;
playerAtMaxHealth = True;
playerDead = False
gold = 0
health = 30
maxHealth = 30
inventory = []
time.sleep(2)
while True:
if health == maxHealth:
playerAtMaxHealth = True;
elif health > maxHealth:
health = maxHealth;
elif health < 0:
health = 0
elif health == 0:
playerDead = True;
forest()
Basically what happens is that it prints out the start text, but then it just gets stuck in the while loop and doesn't move onto forest().
I don't know if you have considered this yet, but it might be better for you to do this in an object orientated way. So, have the hero or the player as the class and his attributes being gold, health.etc. Then you can easily have a function that you can run after a fight or interaction, to check to see if the player is alive or not
Dont use while true to cover the health rules.
So if you want checking the health of the player is like this..
While true
Forest() // maybe some fight with monster
//health checking goes here...
It will do health check after some action in the forest....
If you wrote like yours it only get stuck in the health checking
You can simply wrap your while loop inside a thread. Then start the thread and it will not change the other structure of your code.
Creating threads in Python are extremely easy. You need to import threading
Then you can create a thread using threading.Thread() function
You can create as many threads as you want and you can simply start them using start() function. And they all will execute without interfering your code.
For more details on python thread refer to this threading example of python.

Error when trying to create list with a specific range. Why? [duplicate]

Well i've seen this error occur to others aswell but i can't figure out were my mistake is.
I get this:
Traceback (most recent call last):
File "C:\Users\Bill\Desktop\Finalizing_2.1(DEVELOPING).py", line 100, in <module>
combined = list(zip(symbols,deck))
TypeError: 'str' object is not callable
Here is my code: (Python 3.x)
import random #shuffle
import os#file deleting
def shuffledDeck(deck):#shuffles ceck
random.shuffle(deck)
def dealCard(deck,participant):#deal cards , chooses between player and house with string z
participant.append(deck.pop())
if z==1:
print('\nYou got %s ' %("{} {}".format(player[len(player)-1],symbols.pop())))
else:
print('\nHouse got %s ' %("{} {}".format(house[len(house)-1],symbols.pop())))
def total(hand):#chooses between player and house with string z and displays total
y =sum(hand)
if z==1:
print('Your total now is :',y)
else:
print('House total now is :',y)
def compareHands(house, player): #compares players and house's hand totals
global wallet
global bet
global bank
if sum(house)>sum(player):
print('You Lose :(')
wallet += bet
bank -= bet
prw = False
elif sum(house)<sum(player):
print('You Win!')
wallet += bet
bank -= bet
prw = True
elif sum(house)==sum(player):
print('DRAW!')
def printHistory(history): # prints history.txt
if history=='h':
f = open('history.txt')
for l in f:
print(l,end='')
# r=0 # last game
row = 1 # times a game was played
bank = 10 # starting value
exit = False # making sure the game won't exit if the user doesn't want to
newGame = True
# defy if it is a new game or the previous had been canceled
try:
f=open('history.txt')
print('\n________________________ \nHistory File Available')
newGame=False#it is not a new game
except FileNotFoundError:
print('Creating History File..')
f=open('history.txt','w')
newGame=True#it is a new game
if newGame==False:#if it is not a new game
answer=input('Start new game (n) or continue previous game (c)?')#ask
if answer=='n':
f.close()
os.remove('history.txt')
f=open('history.txt','w')
elif answer=='c':
f=open('history.txt')
l=f.readlines()
list=l.pop()
splitlist=list.split()
row=int(splitlist[0])
bank=int(splitlist[5])
print('========================')#begining game
Done=iter([True, False])
while bank>0 and exit==False and (bank <30 or next(Done)):#if bank<0 bank looses so the loop brakes
deck=[2,2,2,2,3,3,3,3,4,4,4,4,7,7,7,7,8,8,8,8,9,9,9,9,10,10,10,10,11,11,11,11]
symbols=['\u2660', '\u2661', '\u2662', '\u2663','\u2660', '\u2661', '\u2662', '\u2663','\u2660', '\u2661', '\u2662', '\u2663','\u2660', '\u2661', '\u2662', '\u2663','\u2660', '\u2661', '\u2662', '\u2663','\u2660', '\u2661', '\u2662', '\u2663','\u2660', '\u2661', '\u2662', '\u2663','\u2660', '\u2661', '\u2662', '\u2663']
wallet = 0 #Money player won
prw = False #Player Won
player = []
house = []
bet = 0
z = 1 #to choose player or house in totalHand()
loop = True #Enter Houses loop
#out2=1#loopbrake2
Round = 2 #Rounds played(used in 5 cards combination)
# shuffle both deck and symbols the same way
combined = list(zip(symbols,deck))
shuffledDeck(combined)
symbols[:], deck[:] = zip(*combined)
#player
dealCard(deck,player)
bet = int(input('Place your bet: '))
while bet > bank:
print('Your bet should not be higher than bank\nplease try again >>>')
bet = int(input('Place your bet: '))
dealCard(deck,player)
total(player)
#checking
if sum(player) == 22: #double ace
print('You win (Α-Α)!!')
wallet += bet
bank -= bet
loop = False
prw = True
elif sum(player)==21:
print('You win!!')
wallet += bet
bank -= bet
loop = False
prw = True
else:
action = input('Hit (h) or stand (s)?: ')
while action == 'h' and sum(player) <= 21 and prw == False:
dealCard(deck, player)
total(player)
Round += 1 # 5 cards combination
if player[0] == 7 and player[1] == 7 and player[2] == 7:
print('You win (Σκουπα)!!')
wallet += bank
bank -= bank
loop = False
prw = True
exit = True
elif Round == 5 and sum(player) <= 21:
print('You win! (Πενταφυλλια)')
wallet += bet
bank -= bet
loop = False
prw = True
elif sum(player) == 21:
print('You win (21)!!')
wallet += bet
bank -= bet
loop = False
prw = True
elif sum(player) < 21:
action = input('Hit (h) or stand (s)?: ')
elif sum(player) > 21:
print('You Lose :( ')
wallet -= bet
bank += bet
loop = False
pwd = False
#houses turn
if loop is True:
z=0
dealCard(deck,house)
total(house)
while sum(house)<17:
dealCard(deck,house)
total(house)
#comparison
if sum(house)<=21:
if house[0] == 7 and house[1] == 7 and house[2] == 7:
print('You Lose :( (7-7-7)')
wallet = 0
bank += bet
pwd = False
exit = True
elif sum(house) == 21:
print('You Lose :( ')
wallet -= bet
bank += bet
pwd = False
else:
compareHands(house,player)
elif sum(house)>21:
print('You Win!')
wallet += bet
bank -= bet
prw = True
print("Bank's balance now is", bank)
if sum(house) == sum(player):
winner = 'DRAW'
elif prw is False:
winner = 'House'
elif prw is True:
winner = 'Player'
#updating history.txt file
if row==1:
f=open('history.txt','r+')
f.write('%-*s%-*s%-*s%-*s%-*s %-*s'% (10,'Round',15,'Bet($)',10,'Player',10,'House',15,'Winner',10,'Bank($)'))
f.close()
f=open('history.txt','a')
f.write('\n%-*s%-*s%-*s%-*s%-*s %-*s'%(10,row,15,bet,10,sum(player),10,sum(house),15,winner,10,bank))
row+=1
f.close()
else:
f=open('history.txt','a')
f.write('\n%-*s%-*s%-*s%-*s%-*s %-*s'% (10,row,15,bet,10,sum(player),10,sum(house),15,winner,10,bank))
row+=1
f.close()
#display history and other actions
history=input('\nContinue(c), print history (h) or exit game (x)?')
while history=='h':
printHistory(history)
history=input('\nContinue(c), print history (h) or exit game (x)?')
if history=='c':
exit=False
else:
exit=True
#game overview
print('Game Over')
if bank==0:
print('Player has won $10')
elif bank>10:
print('Player has lost %d$'%(bank-10))`
It is a simple blackjack game that most beginners make in python i hope that the comments on the code will help you understand it.
My mistake should be something silly as long as i am new to the language but i hope you will help me.
It runs as it should the only problem is...
When the programm asks :
Start new game (n) or continue previous game (c)?
and you give 'c' as input it gives the error.
I found this method on this site so i may not use it right:
combined = list(zip(symbols,deck))
shuffledDeck(combined)
symbols[:], deck[:] = zip(*combined)
any improvements to the code are acceptable.
Thanks in Advance!
UPDATE!
is there any way to display the letter 'A' (stands for ace) instead of 11?
eg.
You got A ♡
instead of
You got 11 ♡
You've overwritten the built-in list function with a string:
list=l.pop()
To fix this, use a different variable name, other than list. In general, you'll want to avoid shadowing built-ins when naming your variables. That is, don't name things list, map, dict, etc.
It's also good practice to name your variables after what's in them. So if you have list = ["apples", "oranges", "pears"], you might consider renaming it fruits = ["apples", "oranges", "pears"]. It really helps with code readability.
You've defined list to be a string:
list=l.pop()
So
list(zip(symbols,deck))
causes Python to complain that list is not callable.
The solution, of course, is to use descriptive variable names that do not shadow Python builtins.
This happened to me recently where I tried to call a function I had defined from within another function, but didn't notice that I also had a local variable in the calling fucntion with the same name as the function I was trying to call.
Due to the scope rules the call to the function was being interpreted as calling the local variable...hence the error message since a scalar variable of type 'str' (for example) is not callable.
So the essence of the problem is variables sharing the names of functions you need to call within their scope, whether they be functions you've defined, those included in imported modules or Python built-ins.

Categories