Rock, Paper, Scissors

Rock, Paper, Scissors: Making Games lesson banner with Beep and Pixel

Track: Making Games  ·  Lesson 3 of 10  ·  Ages: 8+  ·  Time: 45 minutes

Rock, Paper, Scissors is a game where nobody can be sure of winning. That makes it a perfect game to teach a computer. Today you will build a best-of-three match against Beep, and you will learn how a program decides who wins.

Beep says I will pick my move with a very fair dice-like trick. I do not even know what I will pick until I pick it! Beep boop!

What you need

  • A computer with Python 3 and IDLE
  • You have met if, elif and else before
  • About 45 minutes

Grown-ups Play a few rounds of the real hand game with your child first, so they know the rules by heart. Then ask them to explain the winning rules to you as if you were the computer. A computer needs every rule spelled out, even the ones that seem obvious. Try typing a move in capital letters to see why we use .lower().

The rules

First write down the rules clearly. Computers cannot guess what we mean, so a game designer always starts here.

Your moveBeatsLoses to
rockscissorspaper
paperrockscissors
scissorspaperrock

If both players pick the same move, it is a draw and nobody scores.

Step 1: let Beep choose

A list holds several things in order. We put the three moves in a list, then random.choice picks one item from it, completely at random.

This program picks five moves with random.seed(4) at the top, so you can check that your output matches:

import random

random.seed(4)
choices = ["rock", "paper", "scissors"]
for pick_number in range(5):
    print(random.choice(choices))
rock
paper
rock
scissors
paper

Remember from the last lesson that a seed makes the random picks come out the same every time. (If you have a different version of Python, your list could be different. That is OK!) Without the seed line, the moves are different each time you run it.

Pixel says Notice that I do not need an if for each move. One list and one random.choice does the whole job. Short code means fewer bugs. Meow!

Step 2: who wins?

There are nine possible pairs of moves: three draws, three wins for you and three wins for Beep. We do not want nine if lines. Instead we write down only the winning pairs for the player, as short pieces of text in another list:

"rock scissors"     means rock beats scissors
"scissors paper"    means scissors beats paper
"paper rock"        means paper beats rock

To test a pair we join the two moves with a space in the middle, using +, and ask Python whether that text is in the list. If it is not a draw and not in the list, then Beep must have won.

Step 3: the best-of-three match

In a best of three match, the first player to win two rounds wins the whole match. We do not know how many rounds it will take, because draws do not count, so we use a while loop. It keeps going while both players still have fewer than two points.

This version has a seed, so Beep makes the same choices every time and we can test the game properly. When you are happy it works, delete the random.seed(7) line to get a different game every time. To follow along, type the moves rock, Paper and SCISSORS when the game asks.

import random

random.seed(7)
choices = ["rock", "paper", "scissors"]
winning_pairs = ["rock scissors", "scissors paper", "paper rock"]
player_score = 0
beep_score = 0

while player_score < 2 and beep_score < 2:
    player = input("rock, paper or scissors? ").lower()
    beep = random.choice(choices)
    print("Beep chose", beep)
    if player == beep:
        print("A draw! Nobody scores.")
    elif player + " " + beep in winning_pairs:
        print("You win this round!")
        player_score = player_score + 1
    else:
        print("Beep wins this round!")
        beep_score = beep_score + 1
    print("Score: you", player_score, "- Beep", beep_score)

if player_score == 2:
    print("You win the match!")
else:
    print("Beep wins the match!")

Here is the game when you type those moves:

rock, paper or scissors? rock
Beep chose paper
Beep wins this round!
Score: you 0 - Beep 1
rock, paper or scissors? Paper
Beep chose rock
You win this round!
Score: you 1 - Beep 1
rock, paper or scissors? SCISSORS
Beep chose paper
You win this round!
Score: you 2 - Beep 1
You win the match!

Check each round against the rules table. In round 1, paper beats rock, so Beep scores. In round 2, your paper beats Beep’s rock. In round 3, your scissors cut Beep’s paper. Two points to one, so you win.

Here is what the new ideas do:

  • .lower() turns whatever the player typed into small letters, so Paper and PAPER both become paper.
  • player + " " + beep glues the two moves together with a space, for example "rock scissors".
  • in winning_pairs asks “is this text one of the items in the list?”
  • player_score < 2 and beep_score < 2 keeps the loop going until somebody reaches two.

Did you know? If Beep picks completely at random, no plan can beat it. Whatever you play, you win about one round in three, lose about one in three and draw about one in three. Winning for a long time takes luck!

A bug to hunt

What happens if you type banana? It is not a draw. It is not in the winning list. So the program decides Beep wins! That is not very fair. Games should check what players type.

Try it Make the game ask again until the player types rock, paper or scissors. Hint: the tiny program below shows a loop that keeps asking.

Show the answer

This loop keeps asking while the typed move is not in the list of choices. Use it in place of the player = input(...) line.

choices = ["rock", "paper", "scissors"]
player = input("rock, paper or scissors? ").lower()
while player not in choices:
    player = input("Please type rock, paper or scissors: ").lower()
print("You chose", player)

Try it Change the game to a best of five. How many points does a player need to win?

Show the answer

In a best of five, the first player to reach 3 points wins. Change both < 2 checks to < 3 and change player_score == 2 to player_score == 3.

What you learned

  • A list can hold the possible moves, and random.choice picks one.
  • .lower() makes typed text easy to compare.
  • if, elif and else decide between draw, win and loss.
  • A while loop is perfect when you do not know how many rounds will be played.
  • Games should always handle surprising input, like banana.