Super Simple Soccer Simulator

I think that the fate of our sports teams is determined by luck much more than we believe. While it's fun to blame the front office or the manager or the players, a lot of variation in performance can come just from luck.

In this script, I simulate 1000 seasons of a soccer team which plays 36 games per season.

In each game, they have 4 attempts on goal, each of which has a 50% chance of going in. Their opponent is an identical team, with the same parameters. Let's see what happens.

In [6]:
import random
import statistics

# For every game played, if Team 1 got more goals, they get 3 points.
# If it's tied, they get 1 point. Otherwise, they get 0 points.
def play_game(t1_attempts, t1_likelihood, t2_attempts, t2_likelihood):
    t1_score = num_goals(t1_attempts, t1_likelihood)
    t2_score = num_goals(t2_attempts, t2_likelihood)
    if t1_score == t2_score:
        return 1
    elif t1_score > t2_score:
        return 3
    else:
        return 0

# In each game, figure out how many goals the team scored. This is done
# by taking a number of attempts, and flipping a weighted coin to figure
# out if the attempt results in a goal
def num_goals(attempts, likelihood):
    return len([x for x in 
                [random.random() for _ in range(attempts)]
                if x < likelihood])


# The first range is the number of games per season. The second is the
# number of seasons to simulate.
results = [sum([play_game(4,.5, 4, .5) for _ in range(36)]) 
           for _ in range(1000)]
print("Out of {} simulated seasons, here's how we did: ".format(len(results)))
print("Mean number of points: {}".format(statistics.mean(results)))
print("Standard Deviations: {}".format(statistics.stdev(results)))
print("Season with the most points: {}".format(max(results)))
print("Season with the fewest points: {}.".format(min(results)))
Out of 1000 simulated seasons, here's how we did: 
Mean number of points: 49.077
Standard Deviations: 7.861480386916568
Season with the most points: 75
Season with the fewest points: 28.
In [7]:
%matplotlib inline

import matplotlib
import numpy as np
import matplotlib.pyplot as plt

plt.hist(results);

Results

In this plot, you can see that there is a huge range of seasons that can occur just from luck. Most seasons are mediocre, but some are phenomenal and others abysmal. The top seasons would lead to championships and the worst to firings and reorganizations, but all of it is just a result of luck.

In real life, it's impossible to distinguish luck from real skill (or lack thereof), but this shows just how powerful luck can be.