When is an appropriate time to use and modify global variables? - python

I'd like to start out that I'm new to programming. I've never taken any classes on it. I just decided it sounded interesting and try it.
Anyway, I've been reading the "Learn Python the Hard Way" online and have gotten to exercise 36. This exercise involves making my own text-based game. Now, for the question. When is an appropriate time to use and modify global variables? I just started my adventure and want to add things that the player has to do before other events happen, such as pull a lever in a different room before the gate in the first room opens. And if the player wishes to return to the first room later on, the gate and lever still be triggered.
Here's the code so far. Mind you it's not fleshed out. Just wanted to know if it worked.
print "You are a lone adventurer with the bounty to clear out the crypt."
print "You come with nothing but your sword and a compass."
print "You enter the crypt."
print "To the north you have a gated portaculas and rooms to the west and east."
print "What do you do?"
gate = False
lever = False
def entrance():
global gate
while True:
choice = raw_input('> ')
if choice == 'west':
guard_shack()
elif choice == 'east':
lever_rm()
elif choice == 'north' and gate == False:
print "The gate is still closed and locked."
entrance()
elif choice == 'north' and gate == True:
fountain_rm()
else:
entrance(gate)
def lever_rm():
global lever
global gate
print "You enter the room."
print "What do you do"
while True:
choice = raw_input('> ')
if 'search' in choice:
print "You look around the room and notice a lever on the opposite wall."
elif "pull lever" in choice:
print "You pull the lever."
lever = True
gate = True
elif choice == 'west':
entrance()
else:
print '> '
def fountain_rm():
print "you're in the lever room!"
entrance()

Unfortunately, many tutorials (and professors) teach bad code in the name of simplicity (and they usually never bother to teach the right way later). In this case, the problem is exacerbated by the fact that you are directly executing top-level code instead of putting it in a main function and using if __name__ == '__main__': main() at the end.
You should try to avoid all global state that can be mutated. It's okay to declare constants, or even lists/sets/dicts that you're not allowed to change. But everything else should be either passed as a function parameter, or stored as an attribute on self of some class.
If nothing else, think about how you would write unit tests in the presence of mutable global variables (hint: it's impossible).
To transform code like you've given, indent everything and add a heading class CryptGame:, add self as the first argument to every function, and replace all variables declared global foo with self.foo.

Related

Python function (ifs and inputs) stops partway through, no error

I'm using a series of inputs and if statements to create a text game/ choose your own adventure where input decides what happens next within a function.
I was testing part of a function, and there should be a total of four strings that print with an input prompt, but after the first two it just moves onto the cell after the function. No error message. I'm using Jupyter Notebook with the latest version of Python. Any help appreciated in making the full function run. (Please ignore the goofy text, sorry for errors this is my first question)
start = input('Welcome to Witness Protection, enter HELP if you need help')
def helper():
if start == 'HELP':
answer= input('')
if answer == 'PICK':
answer= input('')
elif answer == 'WALK':
print('')
if answer == 'TRY':
answer= input('')
elif answer == 'WALK AWAY':
print('')
if answer == 'IN':
answer = input('')
elif answer == 'PUT':
print('')
if answer == 'ON':
answer = input('')
elif answer == 'BACK':
print('')
if start == 'HELP':
helper()
I have checked that I am using the right input, changed elifs to ifs nothing else came to mind that could be the issue any help appreciated
It looks like you want another input instead of a print after elif answer == 'WALK':. When you hit if answer == 'TRY' you haven't given them a chance to change the value of answer yet.
Also, you probably want a different kind of structure for your code. When you use if, only the code that is indented after the if and before the elif or else at the same level of indentation will get run. This means that if someone answers PICK, then none of the code below WALK will get run because the elif answer == 'WALK' section never gets entered. You may want to try a while loop with code that checks different variables to determine what to print at each loop (like what room they are in, what items they have, etc.), and then gets a new input from the user at the end of each loop.
Seems you have some mismatch with the nested if's.
you should indent the if's according to the flow of the questions, something like that:
def helper():
if start == 'HELP':
answer= input('Woah. As you are walking to the FBI office, you see a glistening penny on the floor. Something about it looks strange. What do you do? Enter PICK to pick it up or WALK to keep walking')
if answer == 'PICK':
answer= input('You reach down and grasp the penny, and try to pull it. It doesn’t move. Enter TRY to try again or WALK AWAY to walk away')
if answer == 'WALK AWAY':
print('You keep walking until you reach the FBI office. You make your way to the office of your agent, and sit down to wait for them.')
elif answer == 'TRY':
answer= input('The penny clicks out of place and slides along a track between the paving slabs. One of the slabs slides open. Enter IN to climb in or PUT to put the penny back where it was')
if answer == 'IN':
answer = input('A few metres down, you hit the floor, and see the opening above you close up. You find yourself in an ice cavern, surrounded by the bodies of slain ice dwarfs. Enter ON to walk on or BACK to back')
if answer == 'ON':
answer = input('You enter the realm of the evil wizard. He tells you he is thinking of giving up evil and asks you if you would like to join him in taking over the world and establishing a utopia. Enter YES for \'Of course I will join you, let’s do this!\' Enter THINK for \'That’s a big decision, I need some time to think about it\' Enter NO for \'Woah, sorry buddy, I’m just lost, I’m gonna have to bounce\'')
elif answer == 'BACK':
print('You scramble back to the surface and try to forget what just happened. You continue towards FBI HQ, and wait for your agent at their desk')
elif answer == 'PUT':
print('You move the penny back to where it was, and the slab slides back into place. You continue your walk towards the FBI offices, and wait for your agent in front of their desk')
elif answer == 'WALK':
print('You enter the building and make your way to the office of your agent, and sit down to wait for them.')

Python Function requesting input doesn't execute if statement - no error shown

I thoroughly searched for an answer to my question but couldn't find anything that would explain my results. I truly hope that anyone of you can point me in the right direction.
At the moment I am trying to program a text-based adventure game using Python 3 in order to better understand the language.
While doing so I created a function that should ask the user for input and print a specific statement depending on the users input. In case the users input is invalid the function should then keep asking for input until it is valid.
Unfortunately the function only seems to keep asking for input, without ever executing the if/elif statements within the function. Due to no errors being shown I am currently at a loss as to why this is the case...
print("If You want to start the game, please enter 'start'." + "\n" +
"Otherwise please enter 'quit' in order to quit the game.")
startGame = True
def StartGame_int(answer):
if answer.lower() == "start":
startGame = False
return "Welcome to Vahlderia!"
elif answer.lower() == "quit":
startGame = False
return "Thank You for playing Vahlderia!" + "\n" + "You can now close
the window."
else:
return "Please enter either 'r' to start or 'q' to quit the game."
def StartGame():
answ = input("- ")
StartGame_int(answ)
while startGame == True:
StartGame()
You fell into the scoping trap: you are creating a new variable startGame inside the function that is discarded after you leave it. You would instead need to modify the global one:
def StartGame_int(answer):
global startGame # you need to specify that you want to modify the global var
# not create a same-named var in this scope
# rest of your code
This other SO questions might be of interest:
Python scoping rules
Asking the user for input until they give a valid response
Use of global keyword
and my all time favorite:
How to debug small programs (#1) so you enable yourself to debug your own code.
The last one will help you figure out why your texts that you return are not printed and why the if does not work on 'r' or 'q' and whatever other problems you stumble into. It will also show you that your if are indeed executed ;o)
Other great things to read for your text adventure to avoid other beginner traps:
How to copy or clone a list
How to parse a string to float or int
How to randomly select an item from a list

How to define functions in python to repeat a prompt? (Beginner)

Im new to python so I decided to help myself learn by creating a basic game using python 3! My problem occurs whenever I try to use "def". When I try to run this program it skips all user input entirely because of the def. The goal of using a function in this case would be to return the player to the where it presents the two doors. Maybe its an issue related to indentation? If anyone could give it a shot and see if you can spot the error your help would be greatly appreciated! :D
def sec1 ():
print ("You have two doors in front of you. Do you choose the door on the left or right?")
room1 = input('Type L or R and hit Enter.')
if room1 == "L":
print ("********")
print ("Good choice",name)
elif room1 == "R":
print ("********")
print ("Uh oh. Two guards are in this room. This seems dangerous.")
print ("Do you want to retreat or coninue?")
roomr = input('Type R or C and hit enter.')
if roomr == "R":
print ("Good choice!")
sec1()
You have an indentation problem. Indentation matters in Python. According to the PEP8 styling guideline it is recommended to use 4 spaces instead of tabs for indentation. Also you are missing the name variable.
Below is a quick fix:
def sec1 ():
print("You have two doors in front of you. Do you choose the door on the left or right?")
room1 = input('Type L or R and hit Enter.')
name = "Player Name"
if room1 == "L":
print("********")
print("Good choice", name)
elif room1 == "R":
print("********")
print("Uh oh. Two guards are in this room. This seems dangerous.")
print("Do you want to retreat or coninue?")
roomr = input('Type R or C and hit enter.')
if roomr == "R":
print("Good choice!")
sec1()
sec1()
Why we have sec1() at then end?
Functions are like machines. It does nothing by it's own. Somebody has to operate it. sec1() (notice the parenthesis) at the end is sending a signal to start executing the function sec1 defined at the top.
I think the best way to learn is to put break points and use the debugger to learn which way the program flows.
Run the program in a debug mode and click on the icons to step through, step over etc. It sounds complicated but it is very easy and saves you a lot of time once you know how to do this feature.
Mathematical Functions
Maybe it is a bit off topic to mention Mathematical Functions here but I think, it's completely worth it. Functions in programming languages are heavily inspired by Mathematical Functions, however, in most of the programming languages these days (except functional programming languages like Haskell, F# etc) the concepts of the original Mathematical Functions are quite deviated over the year.
In Mathematics, the output of a function purely depends upon it's input and does not modify the values outside the function, however, in most of the programming languages this is not always the case and sometimes it can be a source of run time errors.
Tips
As you are a beginner, I highly recommend to use a proper IDE (Integrated Development Environment) if you haven't already. PyCharm has a free community version. IDEs come with a PEP8 style checker, debugger, profiler etc and help you to learn Python much more easily.
def sec1 ():
print ("You have two doors in front of you. Do you choose the door on the left or right?")
room1 = input('Type L or R and hit Enter.')
the function body should be indented
In Python, indentation is very important. Here's an example of your code with proper indentation (And a couple of liberties take on my part):
def sec1 ():
print ("You have two doors in front of you. Do you choose the door on the left or right?")
name = input('Enter your name.')
room1 = input('Type L or R and hit Enter.')
if room1 == "L":
print ("********")
print ("Good choice",name)
elif room1 == "R":
print ("********")
print ("Uh oh. Two guards are in this room. This seems dangerous.")
print ("Do you want to retreat or coninue?")
roomr = input('Type R or C and hit enter.')
if roomr == "R":
print ("Good choice!")
elif roomr == "C":
print ("Run!")
sec1()

English command [text RPG] - python

I am creating a text-RPG taking inspiration from older text adventures where the player enters an English command; such as 'pick up sword' and the like.
I have established a simple; enter 'A' to do this and enter 'B' to do this, but I would like to expand my system for more freedom.
I need to create a system that; when the player types in a command the program picks out key words.
I assume this would be achievable via the 'in' command.
Here is my code:
print "What would you like to do??"
input_loop_sleep = str('')
choice_sleep = raw_input(str('>>>'))
loop_sleep = False
table_time = False
bed_time = False
error_time = False
while loop_sleep == False:
if str('sleep') in choice_sleep or str('bed') in choice_sleep or str('goodnight') in choice_sleep or str('Sleep') in choice_sleep or str('tired') in choice_sleep:
while bed_time == False:
print "you decide to go back to sleep"
time.sleep(1)
print "..."
time.sleep(1)
print ""
time.sleep(1)
print "darkness"
time.sleep(1)
print ""
print "you wake up..."
time.sleep(1)
print "it is now 9:15am"
time == int(9.15)
time.sleep(1)
print "You are standing in your room, slightly more refreshed."
time.sleep(1)
print "there is a table with some things on it, stairs, and a wardrobe... with the doors wide open..."
time.sleep(1)
print "that's strange... you swear that they were shut when you went to sleep..."
break
else:
bed_time == True
break
bed_loop_choice = raw_input('>>>')
elif str('bedside') in choice_sleep or str('table') in str(choice_sleep):
while table_time == False:
print "You rub your eyes and pick up some belongings from a"
print "bedside table."
time.sleep(1)
print "Map added!"
time.sleep(1)
print "100 gold added!"
time.sleep(1)
print "Leather Bag added!"
cash == int(100)
time.sleep(1)
Map == str('map of', str(province))
Inventory == [str(Map)]
container == str('leather bag')
print "your", str(container), str("contains a"), str(Map), str('and'), str(cash)
break
else:
table_time == True
break
else:
print "invalid command!"
when I run the code, no matter what I type in it always goes with the 'sleep' option.
I probably just made some simple mistake!
can you please help me with what I did wrong and how I can fix it.
To answer your question about why the sleep loop is repeated all the time:
You're controlling the loop via
while bed_time == False:
but you never set bed_time to True in your loop (only in the else clause, but that clause is only executed when the loop exits normally, not when it's exited via break, as you're now doing - therefore bed_time will never change).
Furthermore, direct comparisons to a boolean value are usually frowned upon. The idiomatic way (in most languages, not just Python) would be while not bedtime:.
You should probably read some beginners' programming books and/or the Python tutorial before embarking on such a big project. There are several issues in your code that convey the impression that you really need to get a grasp on some basic programming principles and Python idioms.
For example,
int(9.15)
is not a good way to store a time - the result will be 9.
You're then using time == int(9.15), which means "compare the module time to the integer 9". I guess you meant time = int(9.15) which is already bad for the reasons stated above, but there would be even another problem: You would be overwriting the module name time, which will cause the subsequent time.sleep(1) command to fail with an AttributeError.
There's no need for most str() calls in your code because you're using it on objects that already are strings. Where you're not, it's incorrect: str('map of', str(province)) will raise TypeError (str takes only one argument).
You're using uppercase variable names for objects that aren't class instances.
Etc., etc...
I think this should be sufficient to sort out the problem
In [1]: str('bed') in "bedside"
Out[1]: True
So when you write bedside it gets inside the sleep option if condition and hence you are getting wrong answer .
You should write :
if str('bed') == choice_sleep or *other conditions* :
then got inside the sleep option
P.S: I am assuming you have imported the time module .
P.P.S: I checked the code with entering table it is working fine .

How can I use a GUI/Window with my current python code?

I have followed a tutorial on making a simple text based game in Python. I'm going to use what I learned from it to make a post-apocalyptic text adventure. Everything works, but I don't really want to use just the command console as the game. Instead, I want to use a window, which I know can be done with Tkinter. I just don't know how.
What I'm asking is if there's a way to add a GUI or window to my existing functions. The code is below:
#A simple text-based game test
global table
table=0
def start():
print 'Welcome'
global gold
gold=0
lobby()
def lobby():
print 'You are in the lobby.'
command=prompt()
if command=='north':
bedroom()
elif command=='gold':
currentGold()
lobby()
elif command=='end':
return
else:
lobby()
def prompt():
x=raw_input('Type a command: ')
return x
def currentGold():
global gold
print 'current gold: ', gold
def bedroom():
global gold, table
print 'You are in the bedroom'
command=prompt()
if command=='south':
lobby()
elif command=='bed':
print 'You return to your bed and find nothing'
bedroom()
elif command=='table':
if table==0:
print 'You go to the table and find 50 gold'
gold=gold+50
table=1
bedroom()
else:
print 'There is nothing else on the table'
bedroom()
elif command=='gold':
currentGold()
bedroom()
elif command=='end':
return
else:
bedroom()
start()
Basically, you start in a lobby, and then explore a bedroom (not really, it's just a simple test). I'd appreciate anyone's help or input.
In general, a GUI program has to be rewritten as an event loop, rather than just a sequence of code.
For example, if you write a function which just waits forever for input, then the entire GUI is waiting forever for input, which means you can't respond to mouse drags or anything else, and your window manager will display a beachball or pop up a "dead program" dialog or in some other way alert the user that your program is "frozen".
Instead, you have to write a function which just puts up an input dialog, attaches a handler or callback that gets run when the input comes in to the dialog, and then returns.
So, code that looks like this:
def lobby():
print 'You are in the lobby'
command=prompt()
if command == 'north':
bedroom()
elif command=='gold':
currentGold()
lobby()
elif command=='end':
return
else:
lobby()
… has to be split in half, like this:
def lobby():
display_text('You are in the lobby')
prompt_window = PromptWindow(handler = lobby_handler)
prompt_window.show()
def lobby_handler(command):
if command == 'north':
bedroom()
elif command=='gold':
currentGold()
lobby()
elif command=='end':
return
else:
lobby()
If this doesn't make sense, you probably want to follow some tutorials to build some simple GUI apps first, and only then come back to converting your existing program into a GUI app.
Just splitting functions in half is the quick & dirty way to turn sequential code into event-based code, but it isn't always the best. It's a great way to end up in "callback hell".
For example, what if currentGold is popping up a dialog and waiting for the user to click it, and we don't want to go back to lobby until they click it? The only way to make this work is for lobby_handler to pass lobby to currentGold, so currentGold can pass it to currentGoldHandler. And what if currentGold_handler needs to access local variables from currentGold? You have to define currentGold_handler locally so you can use it as a closure, or use functools.partial to bind them in. And so on. Before you know it, you've got code indented 60 characters, inconsistently using some callback-passing convention that you didn't design until you'd written 100 functions, 40 of which violate it in some subtle way.

Categories

Resources