A game booth claims its die is fair, but a few rolls cannot prove it. Your challenge is to build repeatable chance experiments, count what happens, and use those counts to estimate answers. By Lesson 3, the same random choices will steer a turtle on a walk that is different from an ordinary polygon.
You will learn
- Use
random.randintto roll a whole number andrandom.choiceto pick from a range or string. - Set a seed to repeat the same sequence of random choices.
- Put random choices in functions that run many trials and count outcomes.
- Use those counts to estimate a chance or a value such as π.
Lesson 1: Chance
A board game needs a six-sided die. We could type one fixed roll, but then the game would never surprise anyone. Python's random module can choose an integer for us.
A die we can test
First, bring in the random module so its tools are available.
import random
Notice
import random makes the module available; it has not chosen a value yet.
Now fix the starting point of the random number recipe with seed 4.
random.seed(4)
Notice
The same seed restarts the same sequence, which makes debugging and testing repeatable.
Choose one integer from 1 through 6. Both endpoints are possible.
print(random.randint(1, 6))
Output
2Notice
randint(1, 6) makes one die roll. The next choice continues the seeded sequence.
The function below restarts seed 4 and adds several rolls. Predict the total before running this cell.
import random
def roll_total(rolls):
random.seed(4)
total = 0
for roll_number in range(rolls):
roll = random.randint(1, 6)
total = total + roll
return total
print(roll_total(6))
Output
20Notice
The seed comes before the first random choice. Run the cell again: the total repeats because seed 4 restarts the same tested sequence. Change only the seed and the choices can change. During a real game we might not restart the seed inside the function, but seeded functions let this unit's tests compare exact results.
Try real input: number of rolls
This version reads a roll count and uses the function above.
Try it yourself
rolls = int(input("How many rolls? "))
print(roll_total(rolls))
Choose from a range or a string
random.choice(range(2)) chooses either 0 or 1. We can let 0 mean tails and 1 mean heads. random.randint(0, 1) is the everyday tool for choosing between those two integers, while random.choice(range(...)) can pick from any supplied run of values. random.choice can also choose one character from a string.
Try a two-character string to make a coin with H for heads and T for tails.
random.seed(4)
print(random.choice("HT"))
Output
HNotice
choice("HT") returns one character, either H or T. Seed 4 makes this example repeat the same way every time.
Now flip with random.choice(range(2)) many times and count how often 1 (heads) appears.
import random
def count_heads(flips):
random.seed(4)
heads = 0
for flip_number in range(flips):
coin = random.choice(range(2))
if coin == 1:
heads = heads + 1
return heads
print(count_heads(12))
Output
5Notice
Use module style: write import random, then names such as random.randint and random.choice. In this unit, choose with randint or with choice on a range or string.
Dice-and-coin score
Now the game has rounds. Each round rolls a die and flips a coin. Heads adds the roll; tails subtracts the roll. The score must survive from one round to the next, so it is a running total.
import random
def chance_score(rounds):
random.seed(4)
score = 0
for round_number in range(rounds):
roll = random.randint(1, 6)
coin = random.randint(0, 1)
if coin == 1:
score = score + roll
else:
score = score - roll
return score
print(chance_score(8))
Output
8Trace it: score starts once, before the loop. Each round reads the old score and stores the new score. If score = 0 were inside the loop, every round would erase the earlier rounds instead of keeping a cumulative score.
Lesson 2: Simulate & Estimate
The booth owner says, “Sixes happen about one-sixth of the time.” Instead of arguing from six rolls, we can simulate many trials and count every six.
Count an outcome
A trial is one repeat of an experiment. Here, total is an accumulator: it changes only when the condition is true.
import random
def count_sixes(trials):
random.seed(4)
total = 0
for trial in range(trials):
roll = random.randint(1, 6)
if roll == 6:
total = total + 1
return total
print(count_sixes(60))
print(count_sixes(600))
Output
6
87Notice
This is count by condition. The loop performs every trial, but total = total + 1 runs only for a six. The larger experiment gives more evidence, although its count is not required to be exactly one-sixth of the trials.
Try real input: number of trials
Read a trial count, then count the sixes.
Try it yourself
trials = int(input("How many trials? "))
print(count_sixes(trials))
Report a percentage
A raw count is hard to compare across experiment sizes. This function turns it into a percentage. max(trials, 1) keeps the divisor at least 1, and round(..., 1) reports one decimal place.
import random
def six_percent(trials):
random.seed(4)
total = 0
for trial in range(trials):
roll = random.randint(1, 6)
if roll == 6:
total = total + 1
safe_trials = max(trials, 1)
return round(100 * total / safe_trials, 1)
print(six_percent(60))
print(six_percent(600))
Output
10.0
14.5A quarter-circle picture for estimating π
Imagine a quarter-circle of radius 1000 inside a 1000-by-1000 square. The curved boundary runs from (0, 1000) to (1000, 0).
y
1000 *------. + outside corner
| `.
| ) quarter-circle edge
| .'
0 +-------* x
0 1000
The arc bulges outward, so the quarter-circle covers about 78.5% of the square — that fraction is π / 4, so multiply by 4. The square's area is 1000 * 1000, and the quarter-circle's area is π * 1000 * 1000 / 4. Count the inside fraction and multiply by 4 to estimate π.
First test one fixed point in a quarter-circle of radius 1: (0.3, 0.4). Compare the sum of its squared coordinates with 1 * 1.
x = 0.3
y = 0.4
print(x * x + y * y <= 1 * 1)
Output
TrueNotice
0.3 * 0.3 + 0.4 * 0.4 is at most 1, so this point is inside. The same comparison works when the radius is 1000.
For each point, choose x = random.randint(0, 1000) and y = random.randint(0, 1000). Each axis has 1001 possible integer values, including both 0 and 1000, so do not call this a “1000×1000 grid.” A point is inside when x*x + y*y <= 1000*1000.
import random
def estimate_pi(trials):
random.seed(4)
inside = 0
for trial in range(trials):
x = random.randint(0, 1000)
y = random.randint(0, 1000)
if x * x + y * y <= 1000 * 1000:
inside = inside + 1
safe_trials = max(trials, 1)
return round(4 * inside / safe_trials, 2)
print(estimate_pi(50))
print(estimate_pi(500))
print(estimate_pi(5000))
Output
3.12
3.0
3.1Notice
The result is an estimate close to π, not exactly π. Expect a value around 3.1, not exactly 3.14159. More trials usually make the estimate steadier, but randomness does not promise that every larger experiment is closer. Seed 4 gives the same result every time.
Lesson 3: Random Turtle Walk
A rescue robot can move a fixed distance, but debris forces it to turn left or right after every step. A regular polygon knows its next turn. This robot must choose. Can we make the route surprising and still make the program testable?
Build the walk as a real program
The walk runs from assets/l3_random_walk.py, just like the turtle programs in Unit 06. Its step length stays fixed. random.randint(0, 1) chooses a left or right turn. A random walk usually ends away from where it started.
Program
# Bring in the drawing and random-choice tools.
import turtle
import random
random.seed(4)
# Take a fixed step, then randomly choose a left or right turn.
step = 28
move_count = 24
turtle.pencolor("darkviolet")
turtle.pensize(3)
for move_number in range(move_count):
turtle.forward(step)
turn = random.randint(0, 1)
if turn == 0:
turtle.left(90)
else:
turtle.right(90)
turtle.done()
The real program (assets/l3_random_walk.py)
# Bring in the drawing and random-choice tools.
import turtle
import random
random.seed(4)
# Take a fixed step, then randomly choose a left or right turn.
step = 28
move_count = 24
turtle.pencolor("darkviolet")
turtle.pensize(3)
for move_number in range(move_count):
turtle.forward(step)
turn = random.randint(0, 1)
if turn == 0:
turtle.left(90)
else:
turtle.right(90)
turtle.done()
From this unit directory, run:
assets/l3_random_walk.py
Close the turtle window when you finish observing the route. Change only move_count, save, and rerun to see how a longer walk extends the same seeded route.
Notice
step, move_count, and turn have clear jobs. The turtle always moves with its pen down, so 24 loop trips make 24 drawn segments. Seed 4 makes the left/right choices repeat for testing. The route is intentionally open, unlike Unit 06's closed polygons.
Try real input: number of flips
Use the coin-counting function from Lesson 1 with a count entered by a reader.
Try it yourself
flips = int(input("How many flips? "))
print(count_heads(flips))
Put the ideas together
Random programs still need structure. A function gives an experiment inputs and returns its result. A loop runs the trials. An accumulator remembers a score or count. A condition decides which outcomes count. A fixed seed makes the experiment reproducible while you test it.
Recap
import randomgives you the module's chance tools.random.randint(1, 6)can choose either endpoint;random.choice("HT")picks one character.random.seed(4)restarts a sequence so the same experiment repeats.- A simulation counts many trials; its estimate can get steadier without matching the exact value every time.
You can now build a repeatable dice experiment and a wandering turtle route.