Home > Mobile >  In a RPSLS game, if statement always make else be true
In a RPSLS game, if statement always make else be true

Time:12-14

I'm building a RPSLS game and I have an error that I am running into. Regardless of what input player 1 selects, player 2 always win.

# 10 winning pairs, defined as (winner,loser)
winningPairs = [("scissors,paper"),
                ("scissors,lizard"),
                ("Spock,scissors"),
                ("Spock,rock"),
                ("lizard,Spock"),
                ("lizard,paper"),
                ("rock,lizard"),
                ("rock,scissors"),
                ("paper,rock"),
                ("paper,Spock")]

# ask players for their name
print()
namePlayerOne = input("Player 1, enter your name: ")
namePlayerTwo = input("Player 2, enter your name: ")
print()

# Options that can be selected by any user
options = ["Rock","Paper","Scissors","Lizard","Spock"]

# set two variables for keeping score
playerOneScore = 0
playerTwoScore = 0

while True:
    # asking players for their choice
    playerOneOption = input(f"{namePlayerOne} select your option (scissors, Spock, lizard, rock, paper): ").lower()
    playerTwoOption = input(f"{namePlayerTwo} select your option (scissors, Spock, lizard, rock, paper): ").lower() 
    if playerOneOption == playerTwoOption: # if both players select the same option, it's always a draw
        results = "Draw"
    elif (playerOneOption,playerTwoOption) in winningPairs: # check if the order of the input is the same as an element in the winningPairs list, if it is Player one wins (who selects first)
        results = f"{namePlayerOne} wins" # print their win
        playerOneScore  = 1 # add 1 score to their name
    else: # if the elif is not true, it means player two wins
        results = f"{namePlayerTwo} wins" # print their win
        playerTwoScore  = 1 # add 1 score to their name

    print("-"*20)
    print(f"{namePlayerOne} chose {playerOneOption}\n{namePlayerTwo} chose {playerTwoOption}") # print each player's pick
    print(results) # print results
    print()
    print(f"{namePlayerOne} score: {playerOneScore}\n{namePlayerTwo} score: {playerTwoScore}") # print player scores
    print("-"*20)

    playAgain = input("Play again? (y/n): ") # ask if players want to play again
    if playAgain.lower() != "y":
        break

Below is the output of what happens. The player selects their names and subsequently picks their options.

Player 1, enter your name: name1
Player 2, enter your name: name2

name1 select your option (scissors, Spock, lizard, rock, paper): rock
name2 select your option (scissors, Spock, lizard, rock, paper): scissors
--------------------
name1 chose rock    
name2 chose scissors
name2 wins

name1 score: 0      
name2 score: 1      
--------------------
Play again? (y/n): n

In this example, player 1 selects rock, and player 2 selects scissors, which means that player 1 should win.

CodePudding user response:

Your winning pairs must be defined as a list of tuples, which contain 2 strings:

winningPairs = [("scissors","paper"),
                ("scissors","lizard"),
                ("Spock","scissors"),
                ("Spock","rock"),
                ("lizard","Spock"),
                ("lizard","paper"),
                ("rock","lizard"),
                ("rock","scissors"),
                ("paper","rock"),
                ("paper","Spock")]

To clarify, this is because you are checking whether a tuple of two strings, player1 and player2's choices respectively, is in the list. The list now contained just strings, since a tuple of 1 element is defined as (item,). But, replace your winningPairs list with this one and it will be all good.

CodePudding user response:

Let's define the "winningPairs" as tuples (a pair of strings in beating order) and extract your crucial algorithm, the evaluation of win, into a function:

# pair (A,B) means: A beats B
def beating_tuples = [
    ("paper", "rock"),
    ("rock", "scissor"),
    # etc.
    ]


# returns a result statement
def evaluate_winner(player1_choice, player2_choice):
    if player1_choice == player2_choice:
       return "Draw"
    
    if (player1_choice, player2_choice) in beating_tuples:
        player1_score  = 1
        return f"{player1_name} wins"
    
    if (player2_choice, player1_choice) in beating_tuples:
        player2_score  = 1
        return f"{player2_name} wins"

    return f"Error: Choices of both unequal or not in beating-pairs (player2, player1): {(player2_choice, player1_choice)}"

Note: Instead of a defaulting else a final catching return indicates failure.


Further improvements could be a Player class, where each player object has common attributes as name, choice, score.

See also:

  • Related