4
\$\begingroup\$

I started reading a book about python two days ago and today I wrote my first code. It's supposed to be a rock, paper, scissors game and from the tests I've done so far it works quite well.

However since I'm new I had to google a lot stuff and I'm 100% sure that there are a lot of things I could have done better, especially regarding the amount of elif-statements that I needed in order to cover every possible outcome.

Any advice is appreciated!

#Imports the random module
import random

#Prints the introduction to the game
print("Welcome! This program allows you to play the famous game: Rock, paper, scissors! \n")

#Asks the user for input
a = input("Now it's your time to choose, what will you take? Rock, paper or scissors? ")

#Repeats the users choice for aesthetic reasons
print ("You chose", a, "!")

#Turns the users input into a lowercase word for an easier use later on
a = a.lower()

#Creates a list of choices for the computer to "choose" from
game_list = ["Rock", "Paper", "Scissors"]

#Lets the computer choose a random option
b = random.choice(game_list)

#Shows the user which option the computer choose
print("The computer chose", b, "!")

#Turns the computers choice into a lowercase word for an easier use later on
b = b.lower()

#All the possible outcomes and conditions the computer has to check
if a == "rock" and b == "rock":
    print("It's a draw!")
elif a == "rock" and b == "paper":
        print("You lost!")
elif a == "rock" and b == "scissors":
    print("You won!")
elif a == "paper" and b == "rock":
    print("You won!")
elif a == "paper" and b == "paper":
    print("It's a draw!")
elif a == "paper" and b == "scissors":
    print("You lost!")
elif a == "scissors" and b == "rock":
    print("You lost!")
elif a == "scissors" and b == "paper":
    print("You won!")
elif a == "rock" and b == "scissors":
    print("It's a draw!")
else:
    print("Something went wrong.")
    print("Have you typed in your choice correctly?")
    
#The computer says goodbye  
print("Thank you for playing, I hope you had fun!") 

I'll also add my "worksheet" or whatever you want to call it. I've seen a video on Youtube of a guy saying that it's important to first think about what the program has to do, before you start coding.

So here is what I wrote before I started and what I wrote after I was done (corrections) and after I had to add more things that I didn't think of before:

  1. The program introduces the game to the player.
  2. The program has to ask the player for input (Rock, paper or scissors).
  3. It has to save the input as a variable to use it later on.
  4. The program itself has to choose an option by itself (randomly).
  5. The program needs to create conditions for outcomes for every possible combination of decisions the player and the computer can make.
  6. The program has to test the human input and computer choice under the conditions.
  7. The computer has to tell the player what the outcome is (output).
  8. The computer should say goodbye.

Corrections:

  1. I had to import the random module first.
  2. I decided that it looks better if the program repeats the user input.
  3. I decided that it was smarter to turn the user input into an lowercase word, so that the program wouldn't run into trouble later on (during the conditions).
  4. Creating a list made the random choice easier.
  5. I decided that it looks better if the program outputs the computer choice.
  6. Lowercase word again.

Advice here is appreciated too, especially regarding my way of writing down what the program has to do.

\$\endgroup\$
5
\$\begingroup\$

Organize code in commented paragraphs or small sections. It's good that you are being methodical in your approach and that you have embraced code comments. However, every good thing can be taken to unhelpful extremes. A comment-per-line or a comment-per-step is probably too much. Comments do not help much if they merely duplicate what's already clear from the code. They work much better as organizational devices, as mechanisms to provide a high-level summary of the code's purpose and main points, or to clarify tricky details. Think of comments the way you might think of subheadings in an long email message (organizational) or as ways to elaborate on complex portions of the code (explanatory). Since nothing in this program is very complex algorithmically, your comments can be mostly organizational.

Normalize your internal data. Your code needs a list of the choices. Store them either lowercase or uppercase -- whichever makes computation easier. If you need them capitalized differently for presentation to the user, Python has many ways to do that easily. The idea is to standardize your data so that the code logic is simpler.

Use data structures to eliminate repetition. Your code has a big if-else structure than can be reduced to a simple dict-lookup. This game has a small number of cases to handle: put them in a dict that maps every pair of choices to the correct outcome.

Aim for variable names that communicate well. Naming is never easy, but it is important for writing clear, easy-to-read, easy-to-maintain code. Your current names strike me as too abstract (a and b) and less specific and direct than they could be (game_list).

Favor less chatty messages. This is a bit of a stylistic point, but most humans don't want to slog through long messages from their computer overlords. Also, code is easier to maintain and edit if your messages are concise. Get to the point in as few words as possible.

Validate user input. Rather than having a mystery outcome (something went wrong), just tell the user they goofed up.

Why limit the fun? Wrap a while True loop around your code and let the user play as long as they like.

import random

# Set up the choices and outcomes.

CHOICES = ['rock', 'paper', 'scissors']

DRAW = 'Draw.'
WON = 'You won!'
LOST = 'You lost!'

OUTCOMES = {
    ('rock', 'rock'): DRAW,
    ('rock', 'paper'): LOST,
    ('rock', 'scissors'): WON,
    ('paper', 'rock'): WON,
    ('paper', 'paper'): DRAW,
    ('paper', 'scissors'): LOST,
    ('scissors', 'rock'): LOST,
    ('scissors', 'paper'): WON,
    ('scissors', 'scissors'): DRAW,
}

# Play game.

while True:
    # Get human choice and validate.
    human = input('Rock, paper, or scissors? ').lower().strip()
    if not human:
        break
    elif human not in CHOICES:
        print("Invalid choice.")
        continue

    # Computer choice.
    computer = random.choice(CHOICES)
    print(f"The computer chose {computer}.")

    # Game outcome.
    print(OUTCOMES[human, computer])

Future improvements you might consider. Keep track of wins and losses. Let the user freely abbreviate their choice (eg, entering just r for rock, etc).

\$\endgroup\$
4
  • \$\begingroup\$ Oh wow. So simple. Very nice. \$\endgroup\$ – Jenia Jun 17 at 19:57
  • \$\begingroup\$ I saw this and couldn't resist eliminating the manually defined OUTCOMES array. I'm not sure it's the neatest style, but I'd offer the following: ENDGAMES = ['Draw.', 'You lost!', 'You won!'] OUTCOMES = {(first, second): ENDGAMES[(second_i-first_i) % len(CHOICES)] for first_i, first in enumerate(CHOICES) for second_i, second in enumerate(CHOICES)} \$\endgroup\$ – yoniLavi Jun 18 at 0:16
  • 1
    \$\begingroup\$ @yoniLavi Yes, I was briefly tempted as well. \$\endgroup\$ – FMc Jun 18 at 0:35
  • 1
    \$\begingroup\$ Wow, thank you a lot! I'll need some time to understand the code you wrote, but it's incredible that you can create the same game with less code while also adding stuff to the game itself. I wrote down every advice you gave me and I'll try to apply it in my next project that I'll post in a few hours. :) Thanks again! \$\endgroup\$ – Xinite Jun 18 at 6:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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