james.p
james.p

Reputation: 21

Problem with a rock, paper, scissors game in Python

I'm currently coding a little rock, paper, scissors game in Python, however I appear to have stumbled upon a problem. The game works, even though the code is a little rough, but I've tried to make the program inform the player they have made an error, and when I test this out, it randomly informs the player they have made an error, when they have not. Here is the block of code that is my problem, it is not the whole game.

def game(self):

    print "This is rock, paper, scissors!"

    rps = ('rock', 'paper', 'scissors')

    comp1 = raw_input("Rock, paper or scissors?\n> ")
    comp2 = random.choice(rps)

    if comp1 == 'rock' and comp2 == 'scissors' or comp1 == 'scissors' and comp2 == 'paper' or comp1 == 'paper' and comp2 == 'rock':
        print "You won! The computer chose %s" % comp2
        return "game"
    elif comp1 == 'rock' and comp2 == 'rock':
        print "In a stalemate, there are no winners, only losers :)\nThe computer also chose %s" % comp2
        return "game"
    elif comp1 == 'scissors' and comp2 == 'scissors':
        print "In a stalemate, there are no winners, only losers :)\nThe computer also chose %s" % comp2
        return "game"
    elif comp1 == 'paper' and comp2 == 'paper':
        print "In a stalemate, there are no winners, only losers :)\nThe computer also chose %s" % comp2
        return "game"
    elif comp1 != 'rock' or 'scissors' or 'paper':
        print "Try choosing between rock, paper and scissors next time. It might help.
        return "game"
    else:
        print "The computer %s. You have failed. Problem?" % comp2
        return "game"

Upvotes: 0

Views: 1330

Answers (4)

Ernesto
Ernesto

Reputation: 295

I think that this is a little more cleaned up version, although not the best implementation. I also added an option to keep playing, and changed it so the user input was case insensitive.

def game():
    import random
    import string
    print "This is rock, paper, scissors!"

    rps = ('rock', 'paper', 'scissors')

    comp1 = raw_input("Rock, paper or scissors? ")
    comp1 = comp1.lower()
    comp2 = random.choice(rps)

    if comp1 == 'rock' and comp2 == 'scissors' or comp1 == 'scissors' and comp2 == 'paper' or comp1 == 'paper' and comp2 == 'rock':
        print "You won! The computer chose %s" % comp2
    elif comp1 == comp2:
        print "In a stalemate, there are no winners, only losers :)\nThe computer also chose %s" % comp2
    elif comp1 not in rps:
        print "Try choosing between rock, paper and scissors next time. It might help."
    else:
        print "The computer chose %s. You have failed. Problem?" % comp2
    new_game = raw_input('Would you like to play again? ')
    new_game = new_game.lower()
    if new_game == 'yes':
        game()

Upvotes: 0

arunkumar
arunkumar

Reputation: 34153

The problem is with your logic here elif comp1 != 'rock' or 'scissors' or 'paper':. The strings 'scissors' and 'paper' are being evaluated to a boolean value, which is true because they are not null.

What you want is elif comp1 != 'rock' and comp1 != 'scissors' and comp1 != 'paper': or since you already have it in the rps tuple, you can do elif comp1 not in rps:

Upvotes: 1

D K
D K

Reputation: 5760

Change

elif comp1 != 'rock' or 'scissors' or 'paper':

to

elif comp1 not in rps:

What you were doing before was equivalent to:

elif (comp1 != 'rock') or 'scissors' or 'paper':

So why was the condition always met?

Have a close look at the or 'scissors' or 'paper' part.

1) In Python, non-empty strings are treated as True, and empty strings are treated as False. Have a look at this interactive session:

>>> bool('')
False
>>> bool('a')
True

2) Also in Python, if statements without a comparison (e.g. if var1:) are inexplicity checking if the expression is True. So,

if var1:

is the same as

if var1 == True:

If you combine these two ideas together:

if 'rock':
    # Always executed
if '':
    # Never executed

Back to your original if statement:

elif comp1 != 'rock' or 'scissors' or 'paper':

Both 'scissors' and 'paper' will always return True, so the contained statements will always be evaluated.

So what is the "in" operator?

The in operator in elif comp1 not in rps: will see if the contents of comp1 is an item in the tuple rps (which is equal to ('rock', 'paper', 'scissors')). The not in front of it will negate it, checking if the contents of comp1 is an item in the tuple rps. Therefore, the contained statements will only be executed if the user input stored in comp1 is invalid.

Upvotes: 9

Karoly Horvath
Karoly Horvath

Reputation: 96366

It should be

comp1 not in ['rock', 'scissors', 'paper']

'scissors' and 'paper' always evaluate to true (or in case of or to themselves)

comp1 != 'rock' or 'scissors' or 'paper'

Also, use comp1 == comp2, it's much more simple.

Upvotes: 2

Related Questions