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.pyfile from the terminal. - Familiarity with
ifif/elifelif/elseelseandinput()input().
Concepts You Will Use
| Concept | Purpose |
|---|---|
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 + breakbreak | Replay loop until the user quits. |
| Dictionary lookups | Replace long ifif/elifelif chains with a clean data structure. |
| F-strings | Format output cleanly. |
Getting Started
Create the project
- Make a folder named
rockpaperscissors-gamerockpaperscissors-game. - Inside it, create
rockpaperscissors.pyrockpaperscissors.py. - Open the folder in your editor.
Write the code
Rock Paper Scissors
Source# 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 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:
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!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
import randomimport randomrandom.choice([...])random.choice([...]) picks one item from a list uniformly at random.
2. Build the option list
options = ["ROCK", "PAPER", "SCISSORS"]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
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()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
computer_choice = random.choice(options)computer_choice = random.choice(options)5. Decide the winner
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!")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
while True:
play()
if input("Do you want to play again? (y/n): ").lower() != "y":
print("Thanks for playing!")
breakwhile True:
play()
if input("Do you want to play again? (y/n): ").lower() != "y":
print("Thanks for playing!")
breakCleaner Rules with a Dictionary
A growing elifelif chain is a smell. Replace it with a dictionary that maps each choice to “what it beats”:
BEATS = {
"ROCK": "SCISSORS",
"SCISSORS": "PAPER",
"PAPER": "ROCK",
}
def winner(user, computer):
if user == computer:
return "tie"
return "user" if BEATS[user] == computer else "computer"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
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"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 = {"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 = {"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:
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_choiceCOUNTER = {"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_choiceNaive 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
| Problem | Cause | Fix |
|---|---|---|
User typing rockrock is rejected | Forgot .upper().upper() | Normalize both sides to one case |
| Always loses to Scissors | Typo in the rules table | Compare against a single dictionary |
| Loop never exits | Wrong indentation of breakbreak | Make sure breakbreak is inside the ifif |
| Score persists between runs but should reset | Globals are reused on replay | Reset score inside the replay loop |
Variations to Try
1. Best of N rounds
First to 3 wins takes the match:
while score["user"] < 3 and score["computer"] < 3:
play_round()
print("You won the match!" if score["user"] == 3 else "Computer wins the match.")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 match —
play_round()play_round()andplay_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 validpattern. - 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
GameGameclass 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:
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 coffeeWas this page helpful?
Let us know how we did
