I'm trying to make a rock-paper-scissors game, and am trying to verify the input.
def player1():
x = (raw_input("please select: Rock(r)/Paper(p)/Scissors(s): ")).lower()
if x == 'r' or x == 'p' or x == 's' or x == 'rock' or x == 'paper' or x == 'scissors':
return x[0]
else:
print "Error - wrong input!"
player1() #I know I can run a While loop, but I need to run it this way.
print(player1())
If I enter the right input on the first try, everything works fine.
But if I enter wrong input on first try, and enter the right input on the second time, I get None
in the output, instead of the first letter of the RPS options.
What am I missing?
You're going to want to loop on input. What you're doing currently is recursively calling player1
, and the recursive case doesn't have an explicit return value (hence, None
is returned).
The way you do this is simple: while there is invalid input, prompt again. I'm using a modified version of this in the vein of the "while True break" style; it accomplishes the same goal. We loop indefinitely, and if the condition we want is valid, we return; otherwise, we prompt for input and loop again.
def player1():
while True:
x = raw_input("please select: Rock(r)/Paper(p)/Scissors(s): ").lower()
if x == 'r' or x == 'p' or x == 's' or x == 'rock' or x == 'paper' or x == 'scissors':
return x[0]
else:
print "Error - wrong input!"
As an alternative to that if
statement, there is a slightly more clean way to express it via the in
operator.
if x in ('r', 'p', 's', 'rock', 'paper', 'scissors'):
As an addendum to your original question (as it says that you have to do it recursively), I must strongly caution you against doing any input evaluation through recursion. Python has a call stack size of around 1,000, which means that you have a very finite (yet reasonably large) amount of tries before the program irrecoverably crashes.
Not just that, but your operation stack will be unnecessarily filled with method calls that behave in a similar fashion to a loop. For memory's sake in addition to the absolute recursion ceiling, do not use recursion for this.
If you absolutely must, and again I strongly advise against doing this, then you simply have to return from your iterative case.
def player1():
x = (raw_input("please select: Rock(r)/Paper(p)/Scissors(s): ")).lower()
if x == 'r' or x == 'p' or x == 's' or x == 'rock' or x == 'paper' or x == 'scissors':
return x[0]
else:
print "Error - wrong input!"
return player1() #I know I can run a While loop, but I need to run it this way.
print(player1())
An improved version of @Makoto's example:
def player1():
x = raw_input("please select: Rock(r)/Paper(p)/Scissors(s): ").lower()
while True:
if x in ['r', 'p', 's', 'rock', 'paper', 'scissors']:
return x[0]
else:
print "Error - wrong input!"
x = raw_input("please select: Rock(r)/Paper(p)/Scissors(s): ").lower()
This is a little more concise than many or
expressions which gets a bit unwieldy if you have a lot of conditions you want to check!
A little explanation:
We're checking to see
x
(our user input) is in pre-defined list of valid inputs.
An even more generalized version of this which becomes reusable:
Example: (reusable, non-recursion:)
#!/usr/bin/env python
from __future__ import print_function # For Python 2/3 compat
try:
input = raw_input # For Python 2/3 compat
except NameError:
pass
def prompt(prompt="Enter: ", valid=None):
s = input(prompt)
while valid and s not in valid:
print("Invalid input! Please try again. Valid inputs are {0:s}".format(" ".join(valid)))
s = input(prompt)
return s
x = prompt("Enter action ([r]ock, [p]aper, [s]cissors): ", ["r", "p", "s", "rock", "paper", "scissors"])
Demo:
$ python foo.py
Enter action ([r]ock, [p]aper, [s]cissors): a
Invalid input! Please try again. Valid inputs are r p s rock paper scissors
Enter action ([r]ock, [p]aper, [s]cissors): foo
Invalid input! Please try again. Valid inputs are r p s rock paper scissors
Enter action ([r]ock, [p]aper, [s]cissors): r
$ python foo.py
Enter action ([r]ock, [p]aper, [s]cissors): a
Invalid input! Please try again. Valid inputs are r p s rock paper scissors
Enter action ([r]ock, [p]aper, [s]cissors): foo
Invalid input! Please try again. Valid inputs are r p s rock paper scissors
Enter action ([r]ock, [p]aper, [s]cissors): rock
PS: Sorry I didn't answer your question using recursion. IHMO this is not a good use-case for recursion. Oh well :) However; this is pretty easy to change:
Example: (reusable, recursive)
def userprompt(prompt="Enter: ", valid=None):
s = input(prompt)
while valid and s not in valid:
print("Invalid input! Please try again. Valid inputs are {0:s}".format(" ".join(valid)))
s = userprompt(prompt, valid)
return s
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With