Python Forum

Full Version: Problem restricting user input in my rock paper scissors game
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Okay, I am a new Python Programmer, I am a beginner, I started doing this a few months ago. I have been working through various Python challenges I found on the internet to practice and learn. So, I am working on this one, it is a rock, paper scissors game, and I managed to get the code to work. But in order for me to call it complete I felt I needed to add some code to ensure that the user only enters in one of the three, rock, paper or scissors.

If figured at first that a while loop would work great for this, so I tried it, and here is the code:
def start():
player1 = input("Player one, What is your name? ")
user1="rock"
while user1 != "rock" or user1 != "paper" or user1 != "scissors":
user1 = input(player1 + ", you are up, what's it going to be, rock, paper or scissors? ")
user1 = user1.lower()
clear()
player2 = input("Player two, What is your name? ")
user2 = input(player2 + ", you are up, what's it going to be, rock, paper or scissors? ")
user2 = user2.lower()
return (player1, user1, player2, user2)

Please note, that I only added the while loop for the first input because I wanted to test it makes sure it worked before adding it for player two. This somehow makes the loop infinite and no matter what I enter it cycles back to the same question. I ran it through a debugger and it appears that as though my boolean arguments are being ignored. I figured that as long as the input was NOT rock, paper, or scissors then it should stay in the loop. if it's rock or paper or scissors it should exit the loop. Apparently this is not the case. Any suggestions?

I would appreciate more knowledge on how this loop works, most of the information i found in the internet was very simple with regards to this while loop so it may only work with single arguments, but this is why I am reaching out to you guys for help.

Okay, so failing that I figured an IF statement might work instead so I changed the code to read like this:
def start():
player1 = input("Player one, What is your name? ")
def player1_input():
user1 = input(player1 + ", you are up, what's it going to be, rock, paper or scissors? ")
user1 = user1.lower()
if user1 != "rock" or user1 != "paper" or user1 != "scissors":
print("Please enter one of the three: Rock, Paper or Scissors")
player1_input()
return user1
player1_input()
clear()
player2 = input("Player two, What is your name? ")
user2 = input(player2 + ", you are up, what's it going to be, rock, paper or scissors? ")
user2 = user2.lower()
return (player1, user1, player2, user2)

UGGH!!! Same problem!! So now I know that there is a problem with my conditions in that line. So it's not the while loop, it is the way I have written it. Please explain why this isn't working.

Okay, so here's the thing. I could have simply done it as a multiple choice, by having them enter 1, 2 or 3, and assigning the rock, paper scissors to each number and got it to work that way but I chose not to do that as I wanted to learn more about how to do exactly what I am explaining right now. Using the 1,2,3 idea was too easy basically.

So the goal is to allow the program to continue execution when one of the three words are entered and reject the rest. I am open to other methods and suggestions of how to do this other then the multiple choice input I had mentioned above.

I have written the code using the https://www.onlinegdb.com/, and when I am at home (I practice at work too, that's why I use GDB), I was using the Thonny IDE, so, the latest version of Thonny is python 3.7 and gdb, I never checked.

Thank you for you help.
I would make a separate function to keep looping until it got a valid input and then return that string, like this:

def get_valid_input (player) :
	acceptable_answers = ('rock', 'paper', 'scissors')
	prompt = ", you are up, what's it going to be, rock, paper or scissors? "
	answer = 'BashBedlam was here.'
	while answer not in acceptable_answers :
		answer = input ('\n' + player +  prompt)
		answer = answer.lower ()
	return answer

def start():
	player1 = input("Player one, What is your name? ")
	player2 = input("Player two, What is your name? ")
	user1 = get_valid_input (player1)
	user2 = get_valid_input (player2)
	return (player1, user1, player2, user2)

print (start ())
Since you are just starting this is a good time to write an input function that you can reuse in future projects.
def get_input(prompt, valid_values=None, converter=None):
    while True:
        value = input(prompt)
        if converter:
            try:
                value = converter(value)
            except:
                print('Invalid input')
                continue
        if valid_values:
            if not value in valid_values:
                print('Invalid input')
                continue

        return value

print(get_input('Enter a number ', converter=float))
print(get_input('Enter an integer ', converter=int))
print(get_input('Enter integer in range [1..10] ',
                converter=int, valid_values=range(1,11)))
print(get_input('Enter (R)ock, (P)aper, (S)cissor ',
                converter=lambda a: a.upper()[0], valid_values=('RPS')))
Output:
Enter a number a Invalid input Enter a number 3.14 3.14 Enter an integer 4.6 Invalid input Enter an integer 6 6 Enter integer in range [1..10] 11 Invalid input Enter integer in range [1..10] 10 10 Enter (R)ock, (P)aper, (S)cissor Lizard Invalid input Enter (R)ock, (P)aper, (S)cissor rock R
Used in the context of your game it might look something like this:
def get_input(prompt, valid_values=None, converter=None):
    while True:
        value = input(prompt)
        if converter:
            try:
                value = converter(value)
            except:
                print('Invalid input')
                continue
        if valid_values:
            if not value in valid_values:
                print('Invalid input')
                continue

        return value

def player(prompt):
    name = input(prompt)
    play = get_input(name + ' enter (R)ock, (P)aper or (S)cissor ',
                      converter=lambda a: a.upper()[0],
                      valid_values=('RPS'))
    return name, play

print(player("Player one, What is your name? "))
print(player("Player two, What is your name? "))
Write code for the general case. In your example you had a bunch of code for getting some input from player 1 and then a bunch of code for getting some input from player 2. Are player 1 and player 2 different? Does player one have any special requirements that are not shared by player two? Are the differences between player one and player two germane to playing Rock-Paper-Scissor?

Stop thinking that there is a Player One and a Player Two. There are two Players. They are the same. Especially so in a game like Rock-Player-Scissor where the players play at the same time. You should not have special code for each player. If you see repeated code it should make your eyes itch. It bothered me that I repeated the same line changing only "one" to "two". Think about what code you need for a player, write that code, and then reuse the code for each player.
It works! But I have one question: When I programmed in C many years ago, the "user1 != "rock"...." line worked perfectly and also worked when I played with BASIC back in the day. Why doesn't it work with Python? Why do I have to resort to creating a list and executing the while statement or even the for statement from a list?

(Mar-18-2021, 02:26 PM)BashBedlam Wrote: [ -> ]I would make a separate function to keep looping until it got a valid input and then return that string, like this:

def get_valid_input (player) :
	acceptable_answers = ('rock', 'paper', 'scissors')
	prompt = ", you are up, what's it going to be, rock, paper or scissors? "
	answer = 'BashBedlam was here.'
	while answer not in acceptable_answers :
		answer = input ('\n' + player +  prompt)
		answer = answer.lower ()
	return answer

def start():
	player1 = input("Player one, What is your name? ")
	player2 = input("Player two, What is your name? ")
	user1 = get_valid_input (player1)
	user2 = get_valid_input (player2)
	return (player1, user1, player2, user2)

print (start ())
(Mar-19-2021, 10:58 AM)ashergreen Wrote: [ -> ]It works! But I have one question: When I programmed in C many years ago, the "user1 != "rock"...." line worked perfectly and also worked when I played with BASIC back in the day. Why doesn't it work with Python?

You have an issue with your logic, not your Python code. This line will always evaluate to True, unless user1 is somehow simultaneously equal to all three values at once (not possible):
user1 != "rock" or user1 != "paper" or user1 != "scissors"
You could use and instead of or to fix this, or you could use in to evaluate the variable against a group of options (a tuple in this case):
user1 not in ("rock", "paper", "scissors")
(Mar-19-2021, 11:14 AM)GOTO10 Wrote: [ -> ]
(Mar-19-2021, 10:58 AM)ashergreen Wrote: [ -> ]It works! But I have one question: When I programmed in C many years ago, the "user1 != "rock"...." line worked perfectly and also worked when I played with BASIC back in the day. Why doesn't it work with Python?

You have an issue with your logic, not your Python code. This line will always evaluate to True, unless user1 is somehow simultaneously equal to all three values at once (not possible):
user1 != "rock" or user1 != "paper" or user1 != "scissors"
You could use and instead of or to fix this, or you could use in to evaluate the variable against a group of options (a tuple in this case):
user1 not in ("rock", "paper", "scissors")

I tried the OR instead of AND and it didn't work. It appears that doing the list/tuple thing seems to be the only way to get it to work.
This is an incorrect conclusion.
Quote:I tried the OR instead of AND and it didn't work. It appears that doing the list/tuple thing seems to be the only way to get it to work.
That you did not get it to work is no proof that any logical statement has to be written using "in". It is usually shorter, and in my opinion clearer, but an expression using "in" can be written using multiple comparisons strung together with "and" or "or", and maybe some parenthesis. I think your failing may be that you think C and Python logical expressions work the same way. If you don't really understand how "and" and "or" work in Python it is easy to get confusing results. Logically consistent, but not obvious to the new Python programmer.

Here is input verification using "and"
def player_input(player):
    inp = input(player + ' enter Rock, Paper or Scissor ').lower()
    while inp != "rock" and inp != "paper" and inp != "scissor":
        inp = input("Please enter Rock, Paper or Scissor ").lower()
    return inp

names = [input('Name for player 1 '), input('Name for player 2 ')]
plays = [player_input(name) for name in names]