Skip to content

Rock Paper Scissors Game

Abstract

Rock Paper Scissors is one of the oldest decision games still in play — and one of the best for teaching beginners how to model rules in code. In this project you will build a command-line version of the game where you play against the computer. Along the way you will learn how to pick a random item from a list, validate user input, model game rules cleanly (avoiding huge ifif/elifelif chains), and grow the program with score keeping, replay, and even a basic AI opponent.

You will leave this tutorial comfortable with:

  • random.choice()random.choice() for picking from a list.
  • Loops with input validation.
  • Dictionary-driven rules instead of chained conditionals.
  • Counting wins / losses / ties across rounds.
  • The Markov-chain trick that lets an AI start beating humans.

The Rules

  • Rock crushes Scissors.
  • Scissors cut Paper.
  • Paper covers Rock.
  • Same choice → tie.

That is the entire game. The challenge is encoding those rules so the program is readable and easy to extend (Rock-Paper-Scissors-Lizard-Spock anyone?).

Prerequisites

  • Python 3.6 or above.
  • A text editor or IDE (VS Code recommended).
  • Comfort running a .py.py file from the terminal.
  • Familiarity with ifif/elifelif/elseelse and input()input().

Concepts You Will Use

ConceptPurpose
random.choice(list)random.choice(list)Pick a random element from a sequence.
.upper().upper() / .lower().lower()Normalize user input so case does not matter.
while Truewhile True + breakbreakReplay loop until the user quits.
Dictionary lookupsReplace long ifif/elifelif chains with a clean data structure.
F-stringsFormat output cleanly.

Getting Started

Create the project

  1. Make a folder named rockpaperscissors-gamerockpaperscissors-game.
  2. Inside it, create rockpaperscissors.pyrockpaperscissors.py.
  3. Open the folder in your editor.

Write the code

Rock Paper ScissorsSource
Rock Paper Scissors
# Rock, Paper, Scissors Game
 
# Import Libraries
import random
 
# Creating a list of options
options = ["ROCK", "PAPER", "SCISSORS"]
 
# Creating a function to play the game
def play():
    # Getting the user's choice
    user_choice = input("Choose Rock, Paper or Scissors: ").upper()
    
    # Getting the computer's choice
    computer_choice = random.choice(options)
    
    # Checking if the user's choice is valid
    while user_choice not in options:
        user_choice = input("Invalid input. Choose Rock, Paper or Scissors: ").upper()
    
    # Checking the user's choice against the computer's choice    
    if user_choice.upper() == computer_choice.upper():
        print(f"Computer chose {computer_choice}. It's a tie!")
    elif user_choice.upper() == "ROCK" and computer_choice.upper() == "SCISSORS":
        print(f"Computer chose {computer_choice}. You win!")
    elif user_choice.upper() == "PAPER" and computer_choice.upper() == "ROCK":
        print(f"Computer chose {computer_choice}. You win!")
    elif user_choice.upper() == "SCISSORS" and computer_choice.upper() == "PAPER":
        print(f"Computer chose {computer_choice}. You win!")
    else:
        print(f"Computer chose {computer_choice}. You lose!")
        
        
# Playing the game
while True:
    play()
    play_again = input("Do you want to play again? (y/n): ")
    if play_again.lower() != "y":
        break
    
print("Thanks for playing!")
Rock Paper Scissors
# Rock, Paper, Scissors Game
 
# Import Libraries
import random
 
# Creating a list of options
options = ["ROCK", "PAPER", "SCISSORS"]
 
# Creating a function to play the game
def play():
    # Getting the user's choice
    user_choice = input("Choose Rock, Paper or Scissors: ").upper()
    
    # Getting the computer's choice
    computer_choice = random.choice(options)
    
    # Checking if the user's choice is valid
    while user_choice not in options:
        user_choice = input("Invalid input. Choose Rock, Paper or Scissors: ").upper()
    
    # Checking the user's choice against the computer's choice    
    if user_choice.upper() == computer_choice.upper():
        print(f"Computer chose {computer_choice}. It's a tie!")
    elif user_choice.upper() == "ROCK" and computer_choice.upper() == "SCISSORS":
        print(f"Computer chose {computer_choice}. You win!")
    elif user_choice.upper() == "PAPER" and computer_choice.upper() == "ROCK":
        print(f"Computer chose {computer_choice}. You win!")
    elif user_choice.upper() == "SCISSORS" and computer_choice.upper() == "PAPER":
        print(f"Computer chose {computer_choice}. You win!")
    else:
        print(f"Computer chose {computer_choice}. You lose!")
        
        
# Playing the game
while True:
    play()
    play_again = input("Do you want to play again? (y/n): ")
    if play_again.lower() != "y":
        break
    
print("Thanks for playing!")

Save the file, open a terminal in the folder, run:

command
C:\Users\username\PythonCentralHub\projects\beginners\rockpaperscissorsgame> python rockpaperscissors.py
Choose Rock, Paper or Scissors: Rock
Computer chose SCISSORS. You win!
Do you want to play again? (y/n): y
Choose Rock, Paper or Scissors: paper
Computer chose PAPER. It's a tie!
Do you want to play again? (y/n): n
Thanks for playing!
command
C:\Users\username\PythonCentralHub\projects\beginners\rockpaperscissorsgame> python rockpaperscissors.py
Choose Rock, Paper or Scissors: Rock
Computer chose SCISSORS. You win!
Do you want to play again? (y/n): y
Choose Rock, Paper or Scissors: paper
Computer chose PAPER. It's a tie!
Do you want to play again? (y/n): n
Thanks for playing!

Step-by-Step Explanation

1. Import randomness

rockpaperscissors.py
import random
rockpaperscissors.py
import random

random.choice([...])random.choice([...]) picks one item from a list uniformly at random.

2. Build the option list

rockpaperscissors.py
options = ["ROCK", "PAPER", "SCISSORS"]
rockpaperscissors.py
options = ["ROCK", "PAPER", "SCISSORS"]

Capitalize all entries up front. Then normalize the user’s input to uppercase too — comparisons become trivial.

3. Read the player’s choice

rockpaperscissors.py
user_choice = input("Choose Rock, Paper or Scissors: ").upper()
while user_choice not in options:
    user_choice = input("Invalid input. Choose Rock, Paper or Scissors: ").upper()
rockpaperscissors.py
user_choice = input("Choose Rock, Paper or Scissors: ").upper()
while user_choice not in options:
    user_choice = input("Invalid input. Choose Rock, Paper or Scissors: ").upper()

The whilewhile loop is a validation loop. It refuses to move on until the user types something valid. No try/excepttry/except needed because we are only checking membership in a list.

4. Computer picks a choice

rockpaperscissors.py
computer_choice = random.choice(options)
rockpaperscissors.py
computer_choice = random.choice(options)

5. Decide the winner

rockpaperscissors.py
if user_choice == computer_choice:
    print(f"Computer chose {computer_choice}. It's a tie!")
elif (user_choice == "ROCK" and computer_choice == "SCISSORS") \
  or (user_choice == "PAPER" and computer_choice == "ROCK") \
  or (user_choice == "SCISSORS" and computer_choice == "PAPER"):
    print(f"Computer chose {computer_choice}. You win!")
else:
    print(f"Computer chose {computer_choice}. You lose!")
rockpaperscissors.py
if user_choice == computer_choice:
    print(f"Computer chose {computer_choice}. It's a tie!")
elif (user_choice == "ROCK" and computer_choice == "SCISSORS") \
  or (user_choice == "PAPER" and computer_choice == "ROCK") \
  or (user_choice == "SCISSORS" and computer_choice == "PAPER"):
    print(f"Computer chose {computer_choice}. You win!")
else:
    print(f"Computer chose {computer_choice}. You lose!")

That elifelif is doing a lot. The next section shows a cleaner way.

6. Replay loop

rockpaperscissors.py
while True:
    play()
    if input("Do you want to play again? (y/n): ").lower() != "y":
        print("Thanks for playing!")
        break
rockpaperscissors.py
while True:
    play()
    if input("Do you want to play again? (y/n): ").lower() != "y":
        print("Thanks for playing!")
        break

Cleaner Rules with a Dictionary

A growing elifelif chain is a smell. Replace it with a dictionary that maps each choice to “what it beats”:

cleaner_rules.py
BEATS = {
    "ROCK":     "SCISSORS",
    "SCISSORS": "PAPER",
    "PAPER":    "ROCK",
}
 
def winner(user, computer):
    if user == computer:
        return "tie"
    return "user" if BEATS[user] == computer else "computer"
cleaner_rules.py
BEATS = {
    "ROCK":     "SCISSORS",
    "SCISSORS": "PAPER",
    "PAPER":    "ROCK",
}
 
def winner(user, computer):
    if user == computer:
        return "tie"
    return "user" if BEATS[user] == computer else "computer"

Reading top to bottom: “Rock beats Scissors. Scissors beat Paper. Paper beats Rock.” Adding a new option later (e.g., Lizard, Spock) means one more line per option, not a combinatorial explosion of elifelifs.

Bonus: Rock-Paper-Scissors-Lizard-Spock

rpsls.py
BEATS = {
    "ROCK":     ["SCISSORS", "LIZARD"],
    "PAPER":    ["ROCK", "SPOCK"],
    "SCISSORS": ["PAPER", "LIZARD"],
    "LIZARD":   ["PAPER", "SPOCK"],
    "SPOCK":    ["SCISSORS", "ROCK"],
}
 
def winner(user, computer):
    if user == computer:
        return "tie"
    return "user" if computer in BEATS[user] else "computer"
rpsls.py
BEATS = {
    "ROCK":     ["SCISSORS", "LIZARD"],
    "PAPER":    ["ROCK", "SPOCK"],
    "SCISSORS": ["PAPER", "LIZARD"],
    "LIZARD":   ["PAPER", "SPOCK"],
    "SPOCK":    ["SCISSORS", "ROCK"],
}
 
def winner(user, computer):
    if user == computer:
        return "tie"
    return "user" if computer in BEATS[user] else "computer"

Five-option variant from The Big Bang Theory. Same code shape, more fun.

Add Score Tracking

score.py
score = {"user": 0, "computer": 0, "tie": 0}
 
def play_round():
    # … existing logic …
    result = winner(user_choice, computer_choice)
    score[result] += 1
    print(f"Score — You: {score['user']}  Computer: {score['computer']}  Ties: {score['tie']}")
score.py
score = {"user": 0, "computer": 0, "tie": 0}
 
def play_round():
    # … existing logic …
    result = winner(user_choice, computer_choice)
    score[result] += 1
    print(f"Score — You: {score['user']}  Computer: {score['computer']}  Ties: {score['tie']}")

After each round you see the running totals. When the user quits, print a final summary.

A Smarter Computer

Random play means the computer wins 33 % of the time. Humans have patterns. A simple Markov-chain AI tracks what the player typed last round and bets on the same again:

ai.py
COUNTER = {"ROCK": "PAPER", "PAPER": "SCISSORS", "SCISSORS": "ROCK"}
last_user_move = None
 
def ai_pick():
    global last_user_move
    if last_user_move is None:
        return random.choice(options)
    return COUNTER[last_user_move]    # counter the player's previous move
 
# after the round:
last_user_move = user_choice
ai.py
COUNTER = {"ROCK": "PAPER", "PAPER": "SCISSORS", "SCISSORS": "ROCK"}
last_user_move = None
 
def ai_pick():
    global last_user_move
    if last_user_move is None:
        return random.choice(options)
    return COUNTER[last_user_move]    # counter the player's previous move
 
# after the round:
last_user_move = user_choice

Naive but surprisingly effective — most beginners do repeat their previous move. For a real upgrade, track the transition matrix (what move follows what) and predict accordingly.

Common Mistakes

ProblemCauseFix
User typing rockrock is rejectedForgot .upper().upper()Normalize both sides to one case
Always loses to ScissorsTypo in the rules tableCompare against a single dictionary
Loop never exitsWrong indentation of breakbreakMake sure breakbreak is inside the ifif
Score persists between runs but should resetGlobals are reused on replayReset score inside the replay loop

Variations to Try

1. Best of N rounds

First to 3 wins takes the match:

bo3.py
while score["user"] < 3 and score["computer"] < 3:
    play_round()
print("You won the match!" if score["user"] == 3 else "Computer wins the match.")
bo3.py
while score["user"] < 3 and score["computer"] < 3:
    play_round()
print("You won the match!" if score["user"] == 3 else "Computer wins the match.")

2. Two human players

Ask each player privately for their move (clear the terminal between turns).

3. Animated countdown

Use time.sleeptime.sleep and print("...", end="\r")print("...", end="\r") to print “Rock… Paper… Scissors!”.

4. GUI version

Tkinter with three big buttons. The label shows the result.

5. Network play

Build a simple Flask backend (see Basic Web Server) so two players in different places submit moves and the server decides the winner.

6. Hand-gesture version

Use OpenCV to detect the user’s hand pose with a webcam. See Gesture Recognition System for the techniques.

7. Statistics dashboard

After 100 rounds, plot the user’s move distribution. Are you secretly a “rock-loving” player?

Real-World Applications

  • Tutorial for finite-state game logic.
  • Demonstrations of probability and game-theory mixed strategies.
  • Onboarding example for new game programmers.
  • A great first project for teaching simple AI / pattern detection.

Best Practices Demonstrated

  • Normalize input early so all comparisons assume one form.
  • Encode rules as data (a dictionary) instead of code (a chain of ififs).
  • Separate the round from the matchplay_round()play_round() and play_match()play_match() should be different functions.
  • Track state explicitly — score in a dictionary, not three scattered variables.

Educational Value

This project teaches:

  • Game loops — round, match, replay.
  • Data-driven rules — the heart of every config-driven system.
  • Input validation — the while not validwhile not valid pattern.
  • Random vs. deterministic AI — a fast intro to game-playing agents.

Next Steps

  • Add score-based difficulty: after 5 losses, the AI eases off.
  • Implement tournament mode with brackets.
  • Wrap state in a GameGame class to learn OOP. See the Hangman project for a similar refactor.
  • Build a web version that two players in different browsers can join.

Try it here

Click your move — the computer picks at random. Paper beats rock, scissors beats paper, rock beats scissors:

sketch Play rock-paper-scissors p5.js
Click your move; the computer picks at random. The winner is decided by the classic rules.

Conclusion

You wrote a complete game, refactored its rules into a clean data structure, added score keeping, and even gave the computer a tiny brain. The same patterns — validation loops, dictionary-driven rules, score state — turn up in every game and many non-game projects. Full source on GitHub. Find more beginner projects on Python Central Hub.

If this helped you, consider buying me a coffee ☕

Buy me a coffee

Was this page helpful?

Let us know how we did