Can't break out of a while loop - python

I'm writing a terrible text-based adventure, and I can't figure out how to break this loop. I'll try to post the relevant stuff here. Please tell me if my comments don't adequately explain what I'm trying to do.
chained = 1
finished = 0
# home() and club() act as rooms in the game
def home():
while chained == 1:
# there's a way to unchain yourself that works
chained = 0
while chained == 0:
print 'your are in the room'
input = raw_input('> ')
if 'exit' in input or 'leave' in input or 'club' in input:
current_room = 'club'
break
def club():
print "this works"
# These sort of move you around the rooms.
# current_room keeps track of what room you're in
current_room = 'home'
while finished == 0:
if current_room == 'home':
home()
if current_room == 'club':
club()
The expected behavior is that I would enter "exit" or "leave" or "club" into the input, the home() function would end, and the club() function would start. What actually happens is that the terminal just keeps printing "you are in the room" and keeps giving me the input.
I'll post my completely unabridged code if I must, but I'd rather not, as the actual adventure isn't exactly...professional.

What break is doing is breaking out of the loop in the home() function. So when that breaks, it will go back to the beginning of
while finished == 0:
And will keep on repeating that input.
You have to also supply a break after home() (and club()):
while finished == 0:
if current_room == 'home':
home()
break
if current_room == 'club':
club()
break
Your code is extremely messy, by the way. While loops shouldn't be used for things like this (except when you're trying to get an input of exit or leave)
You may as well get rid of the final while loop.

Though I never really understood what the code was meant for here's solution that works. You haven't stated if the variable's were global or local and why would you use loops when simple if-else statements could be used
chained = 0
finished = 0
# home() and club() act as rooms in the game
def home():
global chained,current_room
if chained == 1:
# there's a way to unchain yourself that works
chained = 0
if chained == 0:
print 'your are in the room'
input = raw_input('> ')
if 'exit' in input or 'leave' in input or 'club' in input:
current_room = 'club'
club()
# Not sure if finished is a local or global variable
def club():
global finished,current_room
print "this is messy code!!"
# These sort of move you around the rooms.
# current_room keeps track of what room you're in
current_room = 'home'
if finished == 0:
if current_room == 'home':
home()
if current_room == 'club':
club()
home()

I think you need to do make the current_room a global variable. Because the variable current_room in home() and the one in while finished has different scopes.
Something like the following is what you are trying to achieve I guess. Look up on python variable scopes
chained = 1
finished = 0
current_room = 'home'
# home() and club() act as rooms in the game
def home():
global chained
# without the following line current_room has local scope and updating its value will not be
# reflected in the while at the end
global current_room
while chained == 1:
# there's a way to unchain yourself that works
chained = 0
while chained == 0:
print 'your are in the room'
input = raw_input('> ')
if 'exit' in input or 'leave' in input or 'club' in input:
current_room = 'club'
break
def club():
print "this works"
# These sort of move you around the rooms.
# current_room keeps track of what room you're in
while finished == 0:
if current_room == 'home':
home()
if current_room == 'club':
club()

Related

unexpected indent error inside a definition for a function

I have this code for the movement of a monster to move randomly between rooms but I get an unexpected intention error for the global value.
def monster(): """moves the monster randomly"""
global monster_current_room
if monster_current_room["name"] != current_room:
print('The monster is currently in', monster_current_room["name"])
exits = list(monster_current_room["exits"].values())
if random.randint(1, 4) == 4:
monster_current_room = rooms[random.choice(exits)]
elif monster_current_room["name"] == current_room:
game_over = True
if I unindent the global value it acts as the end of the definition and wants two lines between the definition and global value. when I try to run with the indent the program fails with the error.
You have misplaced the function comment:
def monster():
"""
moves the monster randomly
"""
global monster_current_room
if monster_current_room["name"] != current_room:
print('The monster is currently in', monster_current_room["name"])
exits = list(monster_current_room["exits"].values())
if random.randint(1, 4) == 4:
monster_current_room = rooms[random.choice(exits)]
elif monster_current_room["name"] == current_room:
game_over = True
or if you prefer an inline comment you can do like that
def monster(): # moves the monster randomly
global monster_current_room
if monster_current_room["name"] != current_room:
print('The monster is currently in', monster_current_room["name"])
exits = list(monster_current_room["exits"].values())
if random.randint(1, 4) == 4:
monster_current_room = rooms[random.choice(exits)]
elif monster_current_room["name"] == current_room:
game_over = True
when you write a multiline string like
"""
moves the monster randomly
"""
it has to respect the rules of the classic sentences of the python code. So you can't place them whenever you want like comments.

Python return is triggering else within previous function

I am attempting to make a simple text based adventure game in python and have come across a small error where an else command is being called when I do not want it to. The following is a small sample from my code.
## inventory var ##
inv=["torch"]
## inventory function ##
def ichk():
print(f" You are carrying{inv}")
return
##First room, links to a3##
def a2():
move=input("placeholder text.. You notice an exit to your 'east': ")
if move==("e"):
print("You exit to the east")
a3()
if move==("i"):
ichk()
if move==("q"):
print("You find nothing of value")
a2()
else:
print("You can't move in that direction")
a2()
When the function ichk() is triggered (by user input "i"), inventory is printed, howver the else print statement is also printed before returning to the beginning of function a2(). I am new to python so I understand that the constructed argument might not be efficient/effective coding, but I am not sure why this is being triggered.
Thanks to anyone taking the time to read.
You need to use elif statements when you chain them like that, otherwise with the input 'i', the 3rd if statement you have there will be false and run the associated else statement:
## inventory var ##
inv=["torch"]
## inventory function ##
def ichk():
print(f" You are carrying{inv}")
return
##First room, links to a3##
def a2():
move=input("placeholder text.. You notice an exit to your 'east': ")
if move==("e"):
print("You exit to the east")
a3()
elif move==("i"):
ichk()
elif move==("q"):
print("You find nothing of value")
a2()
else:
print("You can't move in that direction")
a2()
In Python, if you have multiple conditional statements, you need to write them as: if,elif,elif,elif,....,else
## inventory var ##
inv=["torch"]
## inventory function ##
def ichk():
print(f" You are carrying{inv}")
return
##First room, links to a3##
def a2():
move=input("placeholder text.. You notice an exit to your 'east': ")
if move==("e"):
print("You exit to the east")
a3()
elif move==("i"):
ichk()
elif move==("q"):
print("You find nothing of value")
a2()
else:
print("You can't move in that direction")
a2()

Why cant cant i kill this loop and why does 0 does not equal 0?

Hello I am just starting to try to teach my self python and with one of the resources I read, I saw this dice game to make. So I did the basic but then I wanted to make it more full. My idea was to add a loop and have after each round it would prompt the user to enter at first q but now 0 to try to determine if it is an error in my input.
def gamestate():
print('enter 0 if you would like to quit anything else to continue')
game = input()
print(game == 0) # diagnostic to check if value is correct
print(type(game)) #diagnostic to make sure type is correct
print(game != str(0))
def play():
print('do you want to play a game enter yes to start')
game = '1' #filler value
game=input()
str(game)
if game == "yes": #confirms start of the game
Dice()
else:
print('Ok Goodbye') #plays game anyways will fix after loop issue
gamestate()
______________________________________________________________
while game !=str(0): #cannot escape loop for some reason
if game == str(0) :
break #to break
Dice()
gamestate()
print('ok good bye')
___________________________________________________________
play()
First, sorry if code long for this, but what I expect is 0 as an input to break the loop, what I get is having to kill my console process in spyder in order to stop this from looping
You have the variable name game at 2 different variable scopes and so they have different state. Try returning a game from gamestate() and comparing the value
Short description of the scoping rules?
def gamestate():
print('enter 0 if you would like to quit anything else to continue')
game = input()
print(game == 0) # diagnostic to check if value is correct
print(type(game)) #diagnostic to make sure type is correct
print(game != str(0))
return game
while game !=str(0): #cannot escape loop for some reason
if gamestate() == str(0) :
break #to break
Dice()
print('ok good bye')
You have to return game value from gamestate function and assign it in while loop. Check below code:
def gamestate():
print('enter 0 if you would like to quit anything else to continue')
game = input()
print(game == 0) # diagnostic to check if value is correct
print(type(game)) #diagnostic to make sure type is correct
print(game != str(0))
return game
def play():
print('do you want to play a game enter yes to start')
game = '1' #filler value
game=input()
str(game)
if game == "yes": #confirms start of the game
Dice()
else:
print('Ok Goodbye') #plays game anyways will fix after loop issue
gamestate()
while game !=str(0): #cannot escape loop for some reason
if game == str(0) :
break #to break
Dice()
game = gamestate()
print('ok good bye')
play()
In order to compare with zero as a string you need merely do something like if game == "0":. The issue you may be running into is that of extra whitespace chars like "\n". If you use input().trimspace() you'll remove extraneous chars and do comparisons with the values you want to.
Also another problem in the code is that it will enter the while loop if game does not equal "0" and so the if condition that follows will automatically not be met. So break is never hit.
You need to modify your program to convert input to int and not converting 0 to string at multiple places.changes needs to be done in while loop and gamestate function

Variable is not updating in function

I'm new in Python but bear with me.
In my code, I am trying to make variable room to 2, via west() function.
Code:
EDIT: I have isolated most of the non-essential code.
room = 1
cmds = 'west'.lower()
def isValidCMD(cmd):
if cmd in cmds:
return True
else:
print("Unknown command. For help type /help, for available options type /options")
cmd = input(">> ")
if isValidCMD(cmd):
runCMD(cmd)
return False
def runCMD(cmd):
if cmd == '/help':
help()
elif cmd == '/exit':
exit()
elif cmd == '/about':
about()
elif cmd == '/stats':
stats()
elif cmd == '/options':
options()
elif cmd == 'north':
north()
elif cmd == 'south':
south()
elif cmd == 'east':
east()
elif cmd == 'west':
west()
elif cmd == '/lookaround':
look_around()
def west():
if room == 1:
print("You head on over to the lab, to get some advice from Professor Andrew.")
return 2 #LINE 40 < -------
elif room == 7:
print("You head back to Auderban Square feeling primed for battle.")
else:
print("You cannot go west.")
cmd = input(">> ")
if isValidCMD(cmd):
runCMD(cmd)
def main():
while True:
# Town
if room == 1:
print("\nYou are at the centre of town, Auderban Square.".upper())
print("\nYou look at the signpost and see 4 signs.")
print("\t- North - Twinleaf Forest")
print("\t- South - Store of Celestia")
print("\t- East - Deskemon Training Ground")
print("\t- West - Auderban's Deskemon centre")
# Lab
elif room == 2:
print("You are at Auderban's Deskemon Centre")
AndrewConv()
print("\nYou see the exit at the door.")
print("\t- East - Auderban Square")
cmd = input(">> ")
if isValidCMD(cmd):
runCMD(cmd)
main()
Output:
But room keeps its value, 1.
Please give some advice for the future so I won't make the same mistake twice.
Replace west() function with this:
def west():
global room
...
Global variables are widely considered bad programming practice because it is extremely difficult to determine where and when they might be modified in a large program. They also make thread-safe and reentrant code almost impossible to write.
A simple approach would be to have each function accept the room as a parameter and return the “new room.” You can then always update the room in your main function every time you invoke a command.
You will probably end up keeping track of more than the room, though. Consider using a mutable data structure like a dictionary or a class to store the game state, and then passing it into your command functions. That way, it is just as simple to keep up with many state variables as one, and you still do not need global variables.
def main():
state = {'room': 1}
while True:
[...]
if isValidCMD(cmd, state):
runCMD(cmd, state)
def west(state):
thisroom = state['room']
if thisroom == 1:
print("You head on over to the lab, to get some advice from Professor Andrew.")
state.update(room=2)
elif thisroom == 7:
print("You head back to Auderban Square feeling primed for battle.")
else:
print("You cannot go west.")
cmd = input(">> ")
if isValidCMD(cmd):
runCMD(cmd)
There are some additional issues with this code. For example, you duplicate the command prompt code in each command prompt, which is brittle and error prone, and unnecessary since you will be returning to main() anyway.
Edited: Here is a minimal, runnable example:
def main():
state = {'room': 1}
for i in range(20):
oldroom = state['room']
nextroom(state)
print("Went from room {} to room {}.".format(oldroom, state['room']))
def nextroom(state):
state['room'] += 2

Create a text menu in Python3x that is always available

I am new to python and learning quickly. Thank you all for the help.
I am attempting to create a text menu that will always run in the background of a storytelling text rpg. I have searched and cannot find an explanation of how to create an "always on" menu or how one would work.
I would like the player to be able to hit "m" at any time in the game and have the menu prompt show up.
So far, I have created a "userinput" function as well as a "menu" function that will be deployed each time the game prompts the user/player for input.
def menu():
print('Press "1" for map >>> "2" for stats >>> "3" for exit')
choice = input()
if choice == '1':
print('map needs to be made and shown')
elif choice == '2':
print('stats need to be made and assinged to choice 2 in def menu')
elif choice == '3':
print('You are exiting the menu. Press "M" at any time to return to the menu')
return
else:
print('I did not recognize your command')
menu()
def userinput():
print('Press 1 to attack an enemy >>> 2 to search a room >>> 3 to exit game')
print('Press "M" for menu at any time')
inputvalue = input()
if inputvalue == 'm':
menu()
elif inputvalue == '1':
print('attack function here')
elif inputvalue == '2':
print('search function here')
elif inputvalue == '3':
exit
else:
userinput()
This does not appear to be an ideal solution because the user cannot choose to view a map or exit the game at any time they want.
Is there a way to have a menu always running in the background?
I thought of using a while loop that would never close and all of the game would be held within that while loop but that doesn't seem economical by any means.
Any thoughts or help would be appreciated.
I took a stab at it. This is perhaps not the best structure for doing what you're looking for but I don't want my reply to get too complicated.
The "standard" approach for anything with a UI is to separate the model, the view and the control. Check out MVC architecture online. While it adds complexity at the start it makes life much simpler in the long run for anything with a non trivial UI.
Other points of note are:
you're not stripping whitespace from your input (potentially problematic "3 " won't do what you want)
you're input is case sensitive (you ask for "M" but check for "m") .. maybe use choice = choice.strip.lower()??
there's a difference between the way raw_input and input work between Python 2 and Python 3 which means your code doesn't work in python 2. What's the difference between raw_input() and input() in python3.x? I've changed my example to use raw_input. You may want to use this work around http://code.activestate.com/recipes/577836-raw_input-for-all-versions-of-python/ near the top of your code for portability.
Some code
# flag we set when we're done
finished = False
def finish():
# ask the user for confirmation?
global finished
finished = True
return
def handle_menu_input(choice):
handled = True
if choice == '1':
print('map needs to be made and shown')
elif choice == '2':
print('stats need to be made and assinged to choice 2 in def menu')
else:
handled = False
return handled
def menu():
finished_menu = False
while not finished_menu:
print('Press "1" for map >>> "2" for stats >>> "3" for exit')
choice = raw_input() # NOTE: changes behaviour in Python 3!
if handle_menu_input(choice):
# done
pass
elif choice == '3':
print('You are exiting the menu. Press "M" at any time to return to the menu')
finished_menu = True
else:
print('I did not recognize your command')
menu()
return
def userinput():
print('Press 1 to attack an enemy >>> 2 to search a room >>> 3 to exit game')
print('Press "M" for menu at any time')
choice = raw_input() # NOTE: changes behaviour in Python 3!
if choice == 'm':
menu()
elif choice == '1':
print('attack function here')
elif choice == '2':
print('search function here')
elif choice == '3':
finish()
# elif handle_menu_input(choice):
# # delegate menu functions?? ..
# # do this if you want to see maps anytime without going through the menu?
# # otherwise comment this elif block out.
# # (Problem is 1, 2 etc are overloaded)
# pass
else:
print('I did not recognize your command')
return
def main():
# main loop
while not finished:
userinput()
return
if __name__ == "__main__":
main()

Categories

Resources