Python Arena
Step 3 of 3

Drawing without repeats, and seeds

A teacher picks three students to present their projects today, and nobody should present twice. Picking with choice three times looks like it should work, but nothing stops it from picking the same student again:

import random

random.seed(3)
students = ["Ada", "Ben", "Cy", "Di", "Eve", "Finn"]
for i in range(3):
    print(random.choice(students))
Output
Ben
Eve
Eve

Eve has to present twice. Every call of choice is independent: it doesn't know which students it picked before, so each pick can land on anyone. The same goes for randint.

sample

What the teacher needs is like drawing names out of a hat: a name that has been drawn isn't in the hat anymore. That's what random.sample(items, count) does. It picks count different items of items and returns them in a new list:

import random

random.seed(7)
students = ["Ada", "Ben", "Cy", "Di", "Eve", "Finn"]
presenters = random.sample(students, 3)
print("Presenting today:", presenters)
print("The class:", students)
Output
Presenting today: ['Cy', 'Ben', 'Di']
The class: ['Ada', 'Ben', 'Cy', 'Di', 'Eve', 'Finn']

Unlike shuffle, sample leaves the list it was given as it was. It never picks the same item of the list twice, so if the list has no repeated values, neither does the sample.

The items can be a range too. A puzzle game hides 4 mines on a board whose squares are numbered 1 to 25, and two mines can't share a square:

import random

random.seed(7)
mines = random.sample(range(1, 26), 4)
print("Mines on squares:", sorted(mines))
Output
Mines on squares: [5, 11, 13, 21]

The sample comes in the order it was drawn; sorted only makes it easier to read. There must be enough items to pick from. Asking for 5 different students out of 3 is an error, and the error message calls the items the population:

import random

students = ["Ada", "Ben", "Cy"]
print(random.sample(students, 5))
Python stops with
Traceback (most recent call last):
  File "main.py", line 4, in <module>
    print(random.sample(students, 5))
          ~~~~~~~~~~~~~^^^^^^^^^^^^^
ValueError: Sample larger than population or is negative

Where random numbers come from

A computer follows its instructions exactly, so it can't really roll a die. Instead, random calculates its numbers with a formula: each new number comes from the state the previous one left behind. The value the whole series starts from is called the seed. The same seed always gives the same series of numbers:

In the Python interpreter
>>> import random
>>> random.seed(42)
>>> random.randint(1, 100)
82
>>> random.randint(1, 100)
15
>>> random.seed(42)
>>> random.randint(1, 100)
82

When a program doesn't set a seed, Python picks one from something that changes all the time, which is why every run is different. Numbers made like this are called pseudorandom: they look random and are good enough for games and simulations, but whoever knows the seed can repeat them. (For passwords and other secrets, Python has the secrets module.)

A fixed seed is useful in its own right. A program that misbehaves only now and then can be made to misbehave on every run, so you can find the bug. The checks on this site use seeds the same way to test functions that use random numbers.

Your task

Challenge 1 of 3

What does this program print? Type each line it prints.

Challenge 2

A quiz app asks a few questions from its list in each round, and never the same one twice in a round. Write a function pick_questions(questions, count) that returns a list of count different questions picked at random from the list questions with random.sample. When count is larger than the number of questions, it returns all the questions, in a random order. The list questions must stay as it was.

The checks set the seed themselves before they call the function.

Challenge 3

Write a program that splits players into two random teams. It first asks for a seed and passes it to random.seed, then reads player names until an empty line. It shuffles the names with random.shuffle and prints the first half as team 1 and the rest as team 2. With an odd number of players, team 2 gets the extra player (len(names) // 2 names go to team 1). For example:

Seed: 3
Name: Ada
Name: Ben
Name: Cy
Name: Di
Name: Eve
Name:
Team 1:
Ada
Cy
Team 2:
Di
Eve
Ben