[Python] Penalty Kicks Simulator

“Action Bias Among Elite Soccer Goalkeepers: The Case of Penalty Kicks’. Thompson reported: The academics analyzed 286 penalty kicks and found that 94 per cent of the time the goalies dived to the right or the left – even though the chances of stopping the ball were highest when the goalie stayed in the center. If that’s true, why do goalies almost always dive off to one side? Because, the academics theorised, the goalies are afraid of looking as if they’re doing nothing – and then missing the ball. Diving to one side, even if it decreases the chance of them catching the ball, makes them appear decisive. ‘They want to show that they’re doing something,’ says Michael Bar-Eli, one of the study’s authors. ‘Otherwise they look helpless, like they don’t know what to do.’”

Pippa Malmgren, Signals: How Everyday Signs Can Help Us Navigate the World’s Turbulent Economy


Penalty Kicks - Econowmics

Foto von Pixabay von Pexels


Penalty kicks are exciting, especially if they are awarded to the side that you are supporting. No matter how good the penalty takers or the goalkeepers of both sides are, luck still plays a major role in penalty shootouts. Many famous players with large streaks of scoring their penalties have lost a very important one, like Roberto Baggio who missed his penalty against Brazil in 1994 World Cup Finals.





A very simplified model of penalty kicks could be to consider two random variables (the goalkeeper and the penalty kicker), where each randomly choose a value (a direction to shoot or to dive). If these two values are the same (both shoot and dive to the same direction), the penalty is saved and otherwise it is scored. It is a very simplified model, since it does not take into account many other probabilities, such as if the kicker and the keeper both go for the same direction but nevertheless the keeper cannot save the ball and it is scored. However, the model should be enough for a basic analysis of penalty kicks.

Let’s jump to the code:


#Penalty Kick Simulation

#Importing the modules I need
import random

#The Penalty is taken here
def Penalty_kick(n):
    """This function simulates n Penalty Kick(s)"""
    #Initializing a storage for all the results
    total = []
    for i in range(1,n+1):
        #The goalkeeper will either stay in the center or jump to any of the 6 possible states
        Goalkeeper = random.choice(['LB', 'LT', 'Center', 'RB', 'RT'])
        #The penalty taker can shoot the ball to any of the 6 possible places
        Penalty = random.choice(['LB', 'LT', 'Center', 'RB', 'RT', 'Out'])
        #Checking to see if the penalty is saved or if it is in fact scored
        if Goalkeeper == Penalty or Penalty == 'Out':
            total.append([Goalkeeper, Penalty, "Saved!"])
            total.append([Goalkeeper, Penalty, "Goal!"])
    #return total
    return total


So, what does the code do?

I begin by importing the ‘random’ module, which will help me assign random values to a variable. Then the function for the penalty kicks is defined, which works as follows:

First an empty vector is created to store the result of all taken penalties. Then, I run a loop for n times, where in each iteration the penalty kicker randomly kicks the ball in one of the possible alternatives: [Left Bottom, Left Top, Center, Right Bottom, Right Top, Out]. Similarly, in each iteration the keeper would choose a direction from the same set of alternatives, only without ‘out’.

At the final step, the random values assigned to the two variables ‘Penalty’ and ‘Goalkeeper’ are compared. If the two variables have the same value, or if the player has kicked the penalty out, then the penalty is considered to be saved, otherwise it is regarded as scored.


Now that we have the function, let’s quickly analyze a simple scenario. If we have 10000 penalties, how many of the penalties that have been shot to the right bottom corner are saved?

Penalties = Penalty_kick(10000)

#Empty variables used for counting
RB_total = 0
RB_scored = 0

#For loop to go through every one of the items in the total list
for Penalty in Penalties:
    if Penalty[1] == 'RB':
        RB_total += 1
        if Penalty[2] == "Goal!":
            RB_scored += 1

print ("Total Penalties in the right-bottom corner: {} \n Scored: {} \n Saved: {} \n Percent scored: {}" \
        .format(RB_total, RB_scored, RB_total - RB_scored, RB_scored/RB_total ))


Here I simply loop through all penalties, and for those of them which have been shot to the right bottom I check if they have been scored. then using formatting I print the desired output. This is how the final result looks like:

Econowmics - Penalty Kicks