# BINGO Probability: Controlling average game duration

I wandered over here from StackOverflow and my understanding of advanced mathematics is limited, so bear with me...

A standard, BINGO game card has 24 numbers arranged in a 5x5 format. The center of the card has a free space. The numbers range from 1 to 75. Each column has 1/5 of the numbers (1-15, 16-30, etc). Every round results in a single number being called. To win, a player must have 5 numbers in a row, column, or diagonal for a total of 12 possible ways to win.

My understanding is that a single player will on average call bingo in 41.36 rounds. See Wizard of Odds.

1. As the number of players increase, does the average rounds to win decrease?
2. Would proportionally increasing the number range (e.g. 1-85 instead of 1-75) cancel the effect of the increased number of players? If so, how is it related?

GOAL: Given a fixed set of players P and a desired number of rounds R, how large should the set of numbers N be?

Example: For 100 players, how large should the set of numbers be for the game to last, on average, 50 rounds?

• I don't understand your second paragraph. (1) if each column has a 1/5 of the numbers, do you mean each column has 5 numbers randomly selected from 1 to 75 without repeating any other numbers on the card? Or something else: I wasn't sure about your statement in brackets: 1-15, 16-30, etc. (2) What is the role of the free space in the center? How can there be 12 ways to win with 5 numbers in a row, when the centre row and centre column and 2 diagonals can only contain 4 numbers? Feb 22 '14 at 14:07
• If the game has 75 numbers total, numbers 1-15 will be in the first column, 16-30 in the second column, etc. E.g. Number 7 can only ever occur in the first column...this is how standard American bingo is setup. Feb 22 '14 at 20:34
• OK, and what is the role of the free space in the center? Feb 22 '14 at 20:34
• 12 ways for straight lines bingo...5 columns or 5 rows or both diagonals...12 total. Feb 22 '14 at 20:35
• Free space counts as a marked spot...so everyone starts out with one spot marked for free. Feb 22 '14 at 20:36

1. Yes, but it can not be made arbitrarily small. As the number of players increases, the expected number of turns to finish the game will approach $4$.

2. Yes it would, the average game length can be made arbitrarily long if enough numbers are used for the balls. The exact relationship is probably very complicated.

I've opted for a numerical approach, since the probabilities for BINGO are extremely not obvious. I wrote a Python program which (approximately) answers the question: "How many total numbers do we need to make a game last Nturns given that we have Nplayers people playing?" Note that the number of numbers needs to be a multiple of $5$, otherwise one column would be biased. Since $50$ turns seems to be a good average length for a game, if we just set $R = 50$, I've found an experimental fit for $1\leq P \leq 100$. See this graph:

Note that to answer your example question, the model gives $N \approx 256.5$, so we probably need $255$ numbers. Here is the program if you want to compute some results more accurately; simply change the arguments of how_many_numbers(Nplayers, Nturns).

from random import shuffle, sample

# General plan: card represented as 5x5 arrays of ints, with
# filled spaces represented by 0's and called numbers being
# represented by [column number, actual number].
# Bingo is obtained with straight lines (including diagonals)

def generate_card(N): # makes fresh card with N numbers (mod 5)
N_per_col = N/5 # numbers per column
card = []
for x in range(0, 5):
card.append(sample(range(1 + x*N_per_col, N_per_col + 1 + x*N_per_col), 5))
card[2][2] = 0 # free space
return card

def generate_draws(N): # makes randomized list of balls to be drawn
# for N numbers/card (mod 5)
N_per_col = N/5
draws = []
for x in range(0, 5):
for y in range(1 + x*N_per_col, N_per_col + 1 + x*N_per_col):
draws.append([x, y])
shuffle(draws)
return draws

def did_i_win(card, filled): # simulates player checking
# whether or not they won after adding "filled". Player
# only checks the row an column of the last number he filled,
# or the diagonal if necessary.
for column in range(0, 5):
if card[filled[0]][column] != 0:
for row in range(0, 5):
if card[row][filled[1]] != 0:
if filled[0] == filled[1] or filled[0] + filled[1] == 4:
for x in range(0, 5):
if card[x][x] != 0:
for y in range(0, 5):
if card[y][4 - y] != 0:
return 0
return 1
return 1
else:
return 0
return 1
return 1

def update_card(mycard, called): # simulates player
# updating all their cards with the most
# recently called number; returns 1 if BINGO
newcard = mycard
for row in range(0, 5):
if newcard[called[0]][row] == called[1]:
newcard[called[0]][row] = 0
if did_i_win(newcard, [called[0], row]) == 1:
return 1
return newcard

def grid_print(card): # Prints a card out as a grid, only used for debugging
for x in range(0, 5):
print card[0][x], card[1][x], card[2][x], card[3][x], card[4][x]

def play_game(Nplayers, Nnumbers): # Simulates the players playing a game,
# returns the number of turns taken for the game to finish
hands = [] # all players' hands
for x in range(0, Nplayers):
hands.append(generate_card(Nnumbers))
undrawn = generate_draws(Nnumbers) # balls in wheel
Nturns = 0
while True: # while no one has won
Nturns = Nturns + 1
card = undrawn.pop(0) # Ball drawn and discarded
for x in range(0, Nplayers): # Players update their hands
hands[x] = update_card(hands[x], card)
if hands[x] == 1: # if a player won
return Nturns

def Exp_N(Ntrials, Nplayers, Nnumbers): # Runs Ntrials simulations and returns
# the expected number of turns until a bingo is reached in a game with
# Nplayers players and Nnumbers available for the cards
turns = 0
for x in range(0, Ntrials):
turns = turns + play_game(Nplayers, Nnumbers)
return float(turns)/Ntrials

def how_many_numbers(Nplayers, Nturns): # Determines how many numbers
# are needed for a game with Nplayers to last Nturns
N = 25
while True:
Nturns_N = Exp_N(10, Nplayers, N) # change the 10 to 100 for greater accuracy
if Nturns_N > Nturns:
best_N = N
score = abs(Nturns_N - Nturns)
for N2 in range(N - 25, N + 25 + 1, 5):
d = abs(Exp_N(100, Nplayers, N2) - Nturns) # change the 100 to
# 1000 for greater accuracy
if d < score:
best_N = N2
score = d
return best_N

N = N + 5

print how_many_numbers(1, 42)

• Running this with Players = 1 and Rounds = 41.36, I would expect the number to be close to 75, even if this is a rough estimate. I got 105. Can you explain why this could be? Feb 23 '14 at 15:43
• @JeremySmith Yes, there's a deep and elegant reason for that discrepancy: I apparently don't know how to program. I fixed it now though, and it returns $N=75$ fairly consistently for $P = 1$ and $R = 41$ even in "low accuracy" mode. Feb 23 '14 at 19:29
• A programmatic approach to the equation...now you're speaking my language! I've migrated the concepts into another application and am producing the exact same results. Many thanks @mr! Feb 24 '14 at 4:30
• @JeremySmith No problem! :) Feb 24 '14 at 4:47