Dice Race

Dice Race: Making Games lesson banner with Beep and Pixel

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

Beep and Pixel are racing! Each turn they roll a dice and zoom ahead by that many squares. The first one to reach 20 wins. You will not even need to type anything, because the computer plays both racers. This is called a simulation: a program that pretends to be something real so we can watch what happens.

Beep says I will go first because I am very excited. Is that fair? Hmm. We will find out at the end of the lesson. Beep boop!

What you need

  • A computer with Python 3 and IDLE
  • A real dice, if you would like to compare the program with real rolling (optional)
  • About 45 minutes

Grown-ups This game is a nice way to talk about fairness, which matters in game design. Ask your child what would make a race unfair. Later in the lesson the program tests it with a thousand pretend races, which is a first taste of how scientists and designers use computers to answer questions.

A dice in Python

A real dice has six faces. In Python we can write random.randint(1, 6) to get a whole number from 1 to 6. It can be 1 and it can be 6, and each number is equally likely.

We also need a way to remember where each racer is. A variable is a labelled box that holds a value. We will use beep and pixel for the positions, and turn to count the turns. They all start at 0.

The race

Each time round the loop is one turn. Beep rolls first. We add the roll to Beep’s position, print what happened and check for a win. If Beep has not won, Pixel gets a go.

The loop starts with while True:. Since True is always true, this loop would go on forever, so we need a way out. The word break means “stop the loop right now”. We use it as soon as somebody wins.

The program has random.seed(7) so that the race is the same every time and you can check your work. Delete that line to get a different race each time.

import random

random.seed(7)
beep = 0
pixel = 0
turn = 0

while True:
    turn = turn + 1
    roll = random.randint(1, 6)
    beep = beep + roll
    print("Turn", turn, "- Beep rolled", roll, "and is on", beep)
    if beep >= 20:
        print("Beep wins the race!")
        break
    roll = random.randint(1, 6)
    pixel = pixel + roll
    print("Turn", turn, "- Pixel rolled", roll, "and is on", pixel)
    if pixel >= 20:
        print("Pixel wins the race!")
        break
Turn 1 - Beep rolled 3 and is on 3
Turn 1 - Pixel rolled 2 and is on 2
Turn 2 - Beep rolled 4 and is on 7
Turn 2 - Pixel rolled 6 and is on 8
Turn 3 - Beep rolled 1 and is on 8
Turn 3 - Pixel rolled 1 and is on 9
Turn 4 - Beep rolled 5 and is on 13
Turn 4 - Pixel rolled 1 and is on 10
Turn 5 - Beep rolled 3 and is on 16
Turn 5 - Pixel rolled 5 and is on 15
Turn 6 - Beep rolled 1 and is on 17
Turn 6 - Pixel rolled 5 and is on 20
Pixel wins the race!

That was a close one. Look at the last two lines of the race. Beep was on 17 and Pixel rolled a 5 to reach exactly 20, just in time. Notice we wrote >= 20, which means “20 or more”. That way a racer who rolls past the finish line still wins.

Here are the new ideas:

CodeWhat it means
random.randint(1, 6)Roll a dice: a whole number from 1 to 6
beep = beep + rollMove Beep forward by the roll
beep >= 20Is Beep on 20 or more?
while True:Repeat until we say break
breakLeave the loop straight away

Pixel says Look at the code for Beep and the code for me. They are almost exactly the same. When two bits of code are copies of each other, a tidier trick usually exists. We will find tidier tricks later in this track. Meow!

Is going first fair?

Beep always rolls first. Does that help? In a race to 20, the first player might just get there a little sooner. Let us ask the computer to run 1000 races and count how often the player who goes first wins. The for race in range(1000) loop plays the races, and the while loop inside it plays one race.

import random

pixel_target = 20
beep_wins = 0
for race in range(1000):
    beep = 0
    pixel = 0
    while beep < 20 and pixel < pixel_target:
        beep = beep + random.randint(1, 6)
        if beep < 20:
            pixel = pixel + random.randint(1, 6)
    if beep >= 20:
        beep_wins = beep_wins + 1
print("Beep won", beep_wins, "of 1000 races")

There is no seed this time, so the number is a bit different each run. Your output might look like this:

Beep won 618 of 1000 races

If the race were perfectly fair, you would expect about 500. Beep usually wins somewhere around 600. That is a big advantage just for taking the first turn, and it is good to know before you make a game!

Did you know? Game designers test games with simulations like this one. They run thousands of pretend games to find out if one side wins too often, before real players ever see the game.

Challenges

Try it Make the race fairer. Change pixel_target in the simulation so that Pixel does not need to reach 20. What number gets Beep’s wins close to 500?

Show a hint

Pixel goes second, so give Pixel a head start by making the finish line a little closer. Try 19 first, then try 18.

Show the answer

Setting pixel_target = 18 makes the race very close to fair. Pixel’s wins and Beep’s wins are both near 500. A target of 19 still leaves Beep ahead, at about 550 wins. You can use the same program and only change the first line.

import random

pixel_target = 18
beep_wins = 0
for race in range(1000):
    beep = 0
    pixel = 0
    while beep < 20 and pixel < pixel_target:
        beep = beep + random.randint(1, 6)
        if beep < 20:
            pixel = pixel + random.randint(1, 6)
    if beep >= 20:
        beep_wins = beep_wins + 1
print("Beep won", beep_wins, "of 1000 races")

Try it In the first race program, change the finish line from 20 to 40, and change the dice to random.randint(1, 10). How many turns does a race take now? Remember that the number 20 appears in more than one place.

What you learned

  • random.randint(1, 6) works like a six-sided dice.
  • A variable remembers a score or position while the game runs.
  • while True: with break repeats until something happens that you choose.
  • A simulation lets the computer play a game many times to test it.
  • Going first can be an advantage, so a good designer checks that a game is fair.