5
\$\begingroup\$

I created a "2-player" rock-paper-scissors game in Python mainly using if statements and a single while loop. The program is really simple, but I was wondering if using switch statements or perhaps another format would make it less cluttered/quicker/etc.

again = 'y'

while (again == 'y'):

    p1 = input("Player 1 --> Rock, Paper, or Scissors? ")
    p1 = p1.lower()

    print()

    p2 = input("Player 2 --> Rock, Paper, or Scissors? ")
    p2 = p2.lower()

    print()

    if (p1 == "rock"):
        if (p2 == "rock"):
            print("The game is a draw")
        elif (p2 == "paper"):
            print("Player 2 wins!")
        elif (p2 == "scissors"):
            print("Player 1 wins!")
    elif (p1 == "paper"):
        if (p2 == "rock"):
            print("Player 1 wins!")
        elif (p2 == "paper"):
            print("The game is a draw")
        elif (p2 == "scissors"):
            print("Player 2 wins!")
    elif (p1 == "scissors"):
        if (p2 == "rock"):
            print("Player 2 wins!")
        elif (p2 == "paper"):
            print("Player 1 wins!")
        elif (p2 == "scissors"):
            print("The game is a draw")
    else:
        print("Invalid input, try again")

    again = input("Type y to play again, anything else to stop: ")

    print()
\$\endgroup\$
0

2 Answers 2

3
\$\begingroup\$

Remove Redundant Parenthesis

In this line:

while (again == 'y'):

The parenthesis are unneeded and can (should) be removed.

Use a dict to drive the stacked if/else

Whenever I see a stacked if/else I look to restructure the code using a dict (mapping) instead. The net results of the if/else structure in your code can be put into a dict like so:

results = {
    "rock": {
        "rock": "The game is a draw",
        "paper": "Player 2 wins!",
        "scissors": "Player 1 wins!",
    },
    "paper": {
        "rock": "Player 1 wins!",
        "paper": "The game is a draw",
        "scissors": "Player 2 wins!",
    },
    "scissors": {
        "rock": "Player 2 wins!",
        "paper": "Player 1 wins!",
        "scissors": "The game is a draw",
    },
}

If the results are mapped this way, then the interactions with the user becomes more clear and your loop can simply become:

while again == 'y':

    p1 = input("Player 1 --> Rock, Paper, or Scissors? ").lower()
    print()

    p2 = input("Player 2 --> Rock, Paper, or Scissors? ").lower()
    print()

    result = results.get(p1, {}).get(p2, "Invalid input, try again")
    print(result)

    again = input("Type y to play again, anything else to stop: ")
    print() 

This is an example of separating the UI (User Interface) from the Business Logic.

\$\endgroup\$
1
  • \$\begingroup\$ Interesting, I didn't even think about using a dict in this way. Thank you! \$\endgroup\$
    – am2021
    Apr 17, 2021 at 20:11
2
\$\begingroup\$

Listing all possible permutations seems to violate the DRY principle. Plus, it is difficult to extend the logic when additional options are added.

For a sorted list of choices, a player wins with a choice preceding player's 2 choice. Using modulus (%) allows cycling through choices:

C = ['rock', 'paper', 'scissors']
R = ['It\'s a draw!', 'Player 1 wins!', 'Player 2 wins!']

again = 'y'

while again.lower() == 'y':
  p1 = input('Player 1 ~~ Rock, Paper, Scissors ~~ choose:' )
  p2 = input('Player 2 ~~ Rock, Paper, Scissors ~~ choose:' )

  winner = (len(C) + (C.index(p1.lower()) - C.index(p2.lower()))) % len(C)
  
  print(R[winner])
  again = input('Play again [Y]:')
\$\endgroup\$
2
  • \$\begingroup\$ winner = C.index(p1.lower()) - C.index(p2.lower()) would work as well. \$\endgroup\$
    – Manuel
    Apr 18, 2021 at 9:53
  • \$\begingroup\$ I'm impressed how short this solution is, very useful - I'll keep this structure in mind \$\endgroup\$
    – am2021
    Apr 18, 2021 at 15:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.