I am using Python and I am trying to write a simple program that simulates a rock, paper, scissors game. Everything works except for when I enter an invalid response (someth
As other users have pointed out, you need to change your validation in is_valid_guess
to:
if guess == 'rock' or guess == 'paper' or guess == 'scissors':
While this won't solve your immediate problem, it is good (upvote-worthy) advice, and will let you avoid some errors you would have run into.
Additionally, no matter what the user inputs, you always return what they type in. To prevent this, you must return user_guess()
in your else
block:
if is_valid_guess(guess):
#if/elif statement
#assign 1 to rock
if guess == 'rock':
number = 1
#assign 2 to paper
elif guess == 'paper':
number = 2
#assign 3 to scissors
elif guess == 'scissors':
number = 3
return number
else:
print('That response is invalid.')
return user_guess() # <-- right here
Just change input
to raw_input
Here's your problem:
if guess == 'rock' or 'paper' or 'scissors':
This line in is_valid_guess
doesn't do what you think it does. Instead, it always returns True
. What you're looking for is something like this:
if guess == 'rock' or guess == 'paper' or guess == 'scissors':
or more concisely:
if guess in ('rock', 'paper', 'scissors'):
The problem is that what you have always returns True
because of how Python evaluates strings in a boolean context. The line if guess == 'rock' or 'paper' or 'scissors':
evaluates as:
if (guess == 'rock') or ('paper') or ('scissors'):
What this means is that Python checks to see if guess == 'rock'
. If that's true, the conditional evaluates to True
. If it's false, the interpreter tries to evaluate bool('paper')
. This always evaluates to True
because all non-empty strings are "truthy". Therefore, your whole conditional is always True
, and every string is "valid".
As a result, your code considers all strings "valid" and then blows up when it fails to assign a number to a guess that is not actually supported.
As a final note, your is_valid_guess
method could be trimmed a bit, since you're just returning the result of your boolean expression. Rather than using the status
variable as an intermediate, you can just compute the expression and return it right away. I also use the lower()
method of string objects to allow for case-insensitive guessing, in case that's something you want to allow.
def is_valid_guess(guess):
return guess.lower() in ('rock', 'paper', 'scissors')
You've got another issue, which you mentioned in the comments: you've implemented user_guess
in a recursive fashion, so that it calls itself if the user enters an invalid guess. However, in this case, it does not return the result of the recursive call. You need to either return the recursive result by changing the last line of user_guess
to:
return user_guess()
Or else you should make that function use a loop instead of recursion, which is what I would do, since the function is not inherently recursive. You can do something like this:
def user_guess():
# get first guess
guess = input("Choose 'rock', 'paper', or 'scissors' by typing that word. ")
# If that guess is invalid, loop until we get a valid guess.
while not is_valid_guess(guess):
print('That response is invalid.')
guess = input("Choose 'rock', 'paper', or 'scissors' by typing that word. ")
# Now assign the (valid!) guess a number
# This dictionary is just shorthand for your if/elif chain.
guess_table = {
'rock' : 1,
'paper' : 2,
'scissors' : 3
}
# Return the number associated with the guess.
return guess_table[guess.lower()]
Change
if guess == 'rock' or 'paper' or 'scissors':
to
if guess == 'rock' or guess == 'paper' or guess == 'scissors':
In fact, to make the function as streamlined as possible, just do this:
def is_valid_guess(guess):
return guess == 'rock' or guess == 'paper' or guess == 'scissors'