One frustrating error in a conditional statement in Python
like the title says, I have a single bug in a script for a game I'm making. I have, inside a defined function, an if statement that is supposed to run only if a variable is less than one. But when the function runs, even if this variable is equal to or greater than one, the if statement still runs, and doesn't go to else. Here's my source code:
from sys import exit
from sys import argv
from random import shuffle
import random
script = argv
#-------------------------------------------------------------------------
start_room = "your starting point"
top_room = "room with a magical orb"
top_hallway = "long hallway"
mask_room = "room with a golden mask"
fog_hallway = "hallway filled with fog"
fountain_hallway = "hallway with the magical fountain of life at the end"
bottom_room = "room with a magical fire burning in the centre"
bottom_hallway = "round tunnel infested with huge rats"
electric_hallway = "hallway with an electric feel, a crackling in the air"
i = 0
numbers = []
death_toll = 0
#-------------------------------------------------------------------------
def dead():
print "You died."
exit(0)
# next few lines to def cheat_death() will be for generating random numbers for use in cheat_death()
while i < 6:
numbers.append(random.randrange(1,9000))
i = i + 1
# Now, using the six numbers generated above, I'll turn the string list of numbers[], make it a floating number, and then put them into a question.
# Using this question, if the user answers correctly, they will be taken to start(). If not, they will go to dead().
def cheat_death(numbers):
shuffle(numbers)
question = "%d + %d - %d + %d - %d + %d" % tuple(numbers)
print "You have a single chance to cheat death. To live, please answer the question correctly below:"
print question
answer = eval(question)
print answer
user_answer = raw_input("> ")
death_toll == death_toll + 1
if str(user_answer) == str(answer) and death_toll < 1:
start()
else:
dead()
def end_of_hallway_four():
print "You come to the end of the hallway.\n\tYou find a big gold coin on the top of a pedestal, sitting on a padded seat."
print "Around the pedestal there is a wide circle of metal."
print "Would you like to take the expensive gold coin?"
take_coin = raw_input("> ")
if take_coin == "yes" or take_coin == "y" or take_coin == "sure" or take_coin == "yeah":
cheat_death(numbers)
elif take_coin == "no" or take_coin == "n":
print "Very wise indeed."
exit(0)
else:
cheat_death(numbers)
def hallway_four():
print "You are now in a %s" % electric_hallway
print "Would you like to see what's at the end of the hallway?"
end_of_hallway = raw_input("> ")
if end_of_hallway == "yes" or end_of_hallway == "y" or end_of_hallway == "sure":
end_of_hallway_four()
elif end_of_hallway == "no" or end_of_hallway == "n" or end_of_hallway == "nah":
print "You don't know what you're missing!"
exit(0)
else:
cheat_death(numbers)
def hallway_three():
print "You are now in a %s" % fountain_hallway
print "Would you care for a drink of the fountain of life?"
drink = raw_input("> ")
if drink == "yes" or drink == "y" or drink == "sure" or drink == "yeah":
print "You feel very much rejuvinated, and full of energy. You'll live forever!"
exit(0)
elif drink == "no" or drink == "n":
print "Feeling suddenly tired, you quit your journey for a quick nap."
exit(0)
else:
cheat_death(numbers)
def hallway_two():
print "You are now in a %s" % fog_hallway
print "Would you like to follow the door at the end of the hallway?"
hallway_two_door = raw_input("> ")
if hallway_two_door == "yes" or hallway_two_door == "y" or hallway_two_door == "yeah" or hallway_two_door == "sure":
hallway_three()
elif hallway_two_door == "no" or hallway_two_door == "n":
hallway_one()
else:
cheat_death(numbers)
def gold_room():
print "You are in a %s" % mask_room
print "Do you take the valuable mask?"
take_mask = raw_input("> ")
if take_mask == "yes" or take_mask == "y" or take_mask == "yeah" or take_mask == "sure":
cheat_death(numbers)
elif take_mask == "no" or take_mask == "n" or take_mask == "nah":
print "Wise indeed."
hallway_one()
else:
cheat_deaath()
def rat_hallway():
print "You are now in a %s" % bottom_hallway
print "Do you want to follow the light at the end of the tunnel?"
follow_light = raw_input("> ")
if follow_light == "yes" or follow_light == "y" or follow_light == "sure" or follow_light == "yeah":
print "You find yourself at the end of the tunnel, where there is a single door. You follow this door."
hallway_four()
elif follow_light == "no" or follow_light == "n":
exit(0)
else:
cheat_death(numbers)
def hallway_one():
print "You are now in a %s" % top_hallway
print "At the end of the %s, you find two doors. One looks gold plated, and the other one looks moist and mossy.\nWhich one do you take?" % top_hallway
top_hallway_door = raw_input("> ")
if top_hallway_door == "1":
gold_room()
elif top_hallway_door == "2":
hallway_two()
else:
cheat_death(numbers)
def fire_room():
print "You are now in a %s" % bottom_room
print "Would you like to go through door #1, or door #2?\nYou came from door #2."
fire_door = raw_input("> ")
if fire_door == "1":
rat_hallway()
elif fire_door == "2":
start()
else:
cheat_death(numbers)
def orb_room():
print "You are now in a %s" % top_room
print "There are two doors you could take. Which one do you choose?"
orb_door = raw_input("> ")
if orb_door == "1":
start()
elif orb_door == "2":
hallway_one()
else:
cheat_death(numbers)
def start_game_question():
print """
You will be asked a series of questions.
Your answer will either take you to a different room, or perform an action.
If you come to a point where you are exited from the game, don't quit!
There's many more rooms to discover!"""
print "\nTo answer questions, either enter the door number,\nor answer with a word if asked."
print "\nYour progress will NOT be saved."
print "To restart the game, just enter python %s." % script
print "\n\nAre you read to play?"
start_game = raw_input("> ")
if start_game == "yes" or start_game == "y" or start_game == "sure" or start_game == "yeah":
start()
elif start_game == "no" or start_game == "n" or start_game == "nah":
exit(0)
else:
"Please try again."
start_game_question()
def start():
print "You are now at %s." % start_room
print "Would you like to go through door #1 or door#2?"
starting_door = raw_input("> ")
start_door = starting_door
if start_door == 1:
orb_room()
elif start_door == 2:
fire_room()
else:
cheat_death(numbers)
start_game_question()
And here's the related functions in question:
i = 0
numbers = []
death_toll = 0
def dead():
print "You died."
exit(0)
# next few lines to def cheat_death() will be for generating random numbers for use in cheat_death()
while i < 6:
numbers.append(random.randrange(1,9000))
i = i + 1
# Now, using the six numbers generated above, I'll turn the string list of numbers[], make it a floating number, and then put them into a question.
# Using this question, if the user answers correctly, they will be taken to start(). If not, they will go to dead().
def cheat_death(numbers):
shuffle(numbers)
question = "%d + %d - %d + %d - %d + %d" % tuple(numbers)
print "You have a single chance to开发者_C百科 cheat death. To live, please answer the question correctly below:"
print question
answer = eval(question)
print answer
user_answer = raw_input("> ")
death_toll == death_toll + 1
if str(user_answer) == str(answer) and death_toll < 1:
start()
else:
dead()
The specific issue code:
def cheat_death(numbers):
shuffle(numbers)
question = "%d + %d - %d + %d - %d + %d" % tuple(numbers)
print "You have a single chance to cheat death. To live, please answer the question correctly below:"
print question
answer = eval(question)
print answer
user_answer = raw_input("> ")
death_toll == death_toll + 1
if str(user_answer) == str(answer) and death_toll < 1:
start()
else:
dead()
So I added inside the issue function the global descriptor, and edited a couple other lines, to get this function below:
def cheat_death(numbers): shuffle(numbers)
question = "%d + %d - %d + %d - %d + %d" % tuple(numbers)
print "You have a single chance to cheat death. To live, please answer the question correctly below:"
print question
answer = eval(question)
print answer
user_answer = raw_input("> ")
global death_toll
death_toll = death_toll +1
if str(user_answer) == str(answer) and death_toll == 1:
start()
else:
dead()
And here's the terminal output of the problem occuring:
nathan@jolicloud:~/Documents/python$ python gamenew.py
You will be asked a series of questions.
Your answer will either take you to a different room, or perform an action.
If you come to a point where you are exited from the game, don't quit!
There's many more rooms to discover!
To answer questions, either enter the door number,
or answer with a word if asked.
Your progress will NOT be saved.
To restart the game, just enter python ['gamenew.py'].
Are you read to play?
> yes
You are now at your starting point.
Would you like to go through door #1 or door#2?
> 3
You have a single chance to cheat death. To live, please answer the question correctly below:
4863 + 5960 - 4251 + 3934 - 2638 + 5900
13768
> 13768
You are now at your starting point.
Would you like to go through door #1 or door#2?
> 3
You have a single chance to cheat death. To live, please answer the question correctly below:
3934 + 4251 - 5900 + 4863 - 2638 + 5960
10470
> 10470
You died.
nathan@jolicloud:~/Documents/python$
As you can see, the correct way for it to run would be for it to ask for the answer to the question, and then upon getting it right, take the user back to the start, which it does. But then, if you get asked to answer the question again, which you shouldn't be in the first place, it'll say that the correct answer is wrong
So you can see, what I want to do is start out with death_toll
being 0
, meaning that the user has one chance to "die." Then, if the function cheat_death()
gets called, it should increase the variable death_toll
by 1
, meaning they have no more chances to "die." Am I doing this right? Because in the end, I want to have the user taken to else
if death_toll
is equal to, or greater than, 1
.
This statement does not increment death_toll
:
death_toll == death_toll + 1
It is a comparison that returns False
. You want:
death_toll = death_toll +1
Edit:
If I understand your various comments, etc., what you want is for the program to offer, throughout the entire runtime, one chance to "cheat death". If the player succeeds on that chance, they return to the start, but after that, if they try to "cheat death" again, they have no chance.
So, you have multiple problems. As has already been pointed out, you need to use the assignment operator when incrementing the death toll, and you need to use a global
declaration to access the global death toll counter within a function. It sounds like the third problem is that the order of statements in cheat_death
is simply wrong. If you don't want the player to have a chance once the death toll has been incremented, then yo need to check it at the beginning of the function.
I think that I would rewrite the whole function as follows:
def cheat_death(numbers):
global death_toll
if death_toll < 1:
# This counts as a used chance. Increment the counter.
death_toll = death_toll + 1
shuffle(numbers)
question = "%d + %d - %d + %d - %d + %d" % tuple(numbers)
print "You have a single chance to cheat death. To live, please answer the question correctly below:"
print question
answer = eval(question)
print answer
user_answer = raw_input("> ")
if str(user_answer) == str(answer):
start()
else:
dead()
else:
dead()
(Well, I'd probably rewrite it further to return something instead of calling start()
directly, but I'm not going to try to redesign the whole program.)
In python there is something that is not obvious at first.
If in a function you use an assignment or augmented-assignment operator (+=
, -=
and the like) with a variable then that variable is assumed to be a local variable of the function.
This is an unfortunate consequence of not having to declare local variables.
If you want to modify a variable that is "outside" you have to use the global
declaration:
toll = 0
def function_1():
toll = toll + 1 # ERROR, it's a local variable, not the one shown above
def function_2():
global toll
toll = toll + 1 # Ok, now works as you want
Also in your code there is a logic problem. The variable death_toll
is initialized to 0 but then it's immediately incremented (assuming you corrected the comparison ==
into an assignment =
) so the very first time you get to the if
it's already 1.
Then you allow to start only if it's less than 1... this is clearly impossible because you just incremented it the line above...
death_toll == death_toll + 1
This line compares death_toll to (death_toll + 1), then throws away the result of the comparison.
Obviously, you meant '=' rather than '=='.
I don't imagine this will help your overall problem, which is that you need to learn to carefully analyze, read through, and debug your own code.
However here is an obvious source of your error (I took out the print statements to make the code flow more evident):
global death_toll
death_toll = death_toll +1
if str(user_answer) == str(answer) and death_toll == 1:
start()
else:
dead()
I don't understand what you're doing here. You want to make it so the user has exactly one life? So they revert back to start if they lose their life, but only once? The way you have it here they increase their "death toll" (lose a life?) even if they get the question right.
It's hard to debug someone else's program if you don't really know what they were going for. Since you dumped your whole program I'm just gonna take it line by line and give you some suggestions for improvement. I hope you take these as lightheartedly as they are meant.
I'm going for a lives counter (as in you can only cheat death so many times) so I think I would call the global variable lives_left
and decrement it, for readability's sake. Note also that you probably don't need to convert your answers both to strings; int
might be more robust in the end, just in case you get funny user input:
lives_left = 3 # Three chances to cheat death before even math can't save you!
and then later on, in your function:
global lives_left
if int(user_answer) == int(answer) and lives_left:
lives_left -= 1
start()
else:
dead()
On an unrelated note, I also noticed that you had a few statements like this in your code:
if take_mask == "yes" or take_mask == "y" or take_mask == "yeah" or take_mask == "sure":
cheat_death(numbers)
elif take_mask == "no" or take_mask == "n" or take_mask == "nah":
print "Wise indeed."
hallway_one()
else:
cheat_deaath()
You could make this much more readable and organized by using an in
statement. Define your positive and negative answer string possibilities somewhere ahead of time:
answers{'positive':['yes', 'yeah', 'sure', 'y'], 'negative':['no', 'nah', 'n']}
and then reference these possibilities at any later point:
if take_mask in answers['positive']:
cheat_death(numbers)
elif take_mask in answers['negative']:
print "Wise indeed."
hallway_one()
else:
cheat_death()
Also note above that your cheat_death()
function MUST take a parameter!
I'll let you know if I see anything else!
精彩评论