---
title: "NFL Punt Analytics Competition"
output: html_document
---

```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
```

## Introduction

The NFL Punt Analytics Competition aims to use various data sources to hypothesise rules that may reduce the amount of injuries that occur during punt plays. The biggest challenge of this is to suggest rule changes without ruining the integrity or value of the game. Below I have outlined two rule changes that aim to decrease injuries but still maintain the value of the punt play and punt returns. To achieve this I used a combination of the NGS data, player role data and the injury and control plays provided by the NFL.

``` {r load_libraries, include=FALSE}
# Load any libraries we need to use
library(data.table)
library(dplyr)
library(ggplot2)
library(ggrepel)

```

```{r data_ingestion, echo=FALSE}
# Read in the data in this section, but ensure it does not get printed

# Get the list of files
file_list = list.files("../input/", pattern="csv", full.names=T, recursive=T)

# Read in the video review information to start
video_control_data = fread(file.path(file_list[15]))
video_injury_data = fread(file.path(file_list[16]))
video_review_data = fread(file.path(file_list[17]))

# Now read in the data for the position and Role of the players during the punt
player_role_punt_data = fread(file.path(file_list[13]))
player_position_punt_data = fread(file.path(file_list[14]))

# Now merge the two
player_position_and_role_punt_data = merge(player_role_punt_data,
                                           player_position_punt_data[,c("GSISID","Position")] %>% unique(),
                                           by="GSISID", all.x=T) %>% data.table()

# Let's look at the role that is injured the most and break it down by coverage and return
video_review_data_player_roles_data = video_review_data %>% merge(player_position_and_role_punt_data,by=c("GameKey","PlayID","GSISID"),all.x=T)

# Lets list out the punt coverage and punt return positons
punt_coverage_positions = c("P", "PPR","PPRi", "PPRo", "PPL", "PPLi", "PPLo","PC", "PLW","PRW","GL", "GLi",
                            "GLo",  "GR",   "GRi",  "GRo","GR","PLT","PLG","PLS","PRG","PRT")
punt_return_positions = c("PR", "PFB", "VL", "PDL1", "PDL2", "PDL3", "PDL4", "PDL5", "PDL6",
                          "PDR1", "PDR2", "PDR3", "PDR4", "PDR5", "PDR6","PLL", "PLL1", "PLL2", "PLL3",
                          "PLR","PLM1", "PLR1", "PLR2", "PLR3","PLM","VRi","VRo","VR","VLi", "VLo", "PDM")

```

## Punt Coverage and Punt Return Injuries
The first area of analysis is determining the distribution of Punt Return vs Punt Coverage Injuries. As shown in the chart below, 73% of injuries occur to the Punt Coverage team, whereas 27% of injuries occur to the Punt Return team. Whilst it would be ideal to analyse the Punt Coverage injuries, my first area of focus was on the punt return injuries and due to time and resource constraints I was unable to properly analyse the Punt Coverage Injuries at an appropriate level. 

```{r pressure, echo=FALSE}

# We want to show the breakdown of Punt Return vs Punt Coverage Concussions
video_review_data_player_roles_data$Coverage_or_Return = "NA"
video_review_data_player_roles_data[Role %in% punt_coverage_positions]$Coverage_or_Return = "Punt Coverage"
video_review_data_player_roles_data[Role %in% punt_return_positions]$Coverage_or_Return = "Punt Return"

# Get a table of coverage or return percentages
Coverage_or_Return_data = table(video_review_data_player_roles_data$Coverage_or_Return) %>% data.table()
Coverage_or_Return_data$Percentage = round(Coverage_or_Return_data$N/sum(Coverage_or_Return_data$N) * 100)

# Now let Show the Percentage of Punt Coverage vs Punt Return concussions
ggplot(Coverage_or_Return_data, aes("", Percentage, fill = V1)) +
    geom_bar(width = 1, size = 1, color = "white", stat = "identity") +
    coord_polar("y") +
    geom_text(aes(label = paste0(round(Percentage), "%")), 
              position = position_stack(vjust = 0.5)) +
    labs(x = NULL, y = NULL, fill = NULL, 
         title = "Percentage of Injuries by Coverage or Return Team") +
    guides(fill = guide_legend()) +
    #scale_fill_manual(values = c("#ffd700", "#bcbcbc", "#ffa500", "#254290", "#666666", "#666666")) +
    theme_classic() +
    theme(axis.line = element_blank(),
          axis.text = element_blank(),
          axis.ticks = element_blank(),
          plot.title = element_text(hjust = 0.5, color = "#666666"))
```

## Punt Return Injuries

For the duration of this report, we will look at the injuries that occurred to the punt return team. Breaking this down by Role and Player Activity that led to the injury, we can see that there is a substantial amount (50%) of punt return injuries that are happening to the "Punt Returner" role. This may make logical sense, as the player receiving the ball will be the player with the most attention, however interestingly enough, as the graph shows the injuries occurred every time they were tackled. This indicates that the Punt Returner is unable to control the cause of their injuries as they are the target of the Punt Coverage team. It is also interesting to note that all other injuries on the Punt Return team were due to blocking. The position of Punt Returner and the data and actions surrounding this role is thus the focus of the rest of our report as they are put in an extremely vulnerable position when it comes to injuries.

```{r punt_return_concussions, include = FALSE}
# First let us inspect the number of concussions by Role for the punt return team
punt_return_concussions_by_role = video_review_data_player_roles_data[Role %in% punt_return_positions][,.(Number_of_Concussions = length(unique(PlayID))), by=c("Role","Player_Activity_Derived")][order(-Number_of_Concussions)]

# Add the percentage of concussions in
punt_return_concussions_by_role[,Percentage_of_Concussions := Number_of_Concussions/sum(punt_return_concussions_by_role$Number_of_Concussions)*100]


```

```{r echo=FALSE}
ggplot(punt_return_concussions_by_role,aes(x=reorder(Role, -Number_of_Concussions),y = Number_of_Concussions, fill=Player_Activity_Derived)) +geom_bar(stat = "identity") + xlab("Punt Return Role") + ylab("Number of Concussions") + ggtitle("Number of Concussions by Punt Return Role") + theme(plot.title = element_text(hjust = 0.5)) + scale_fill_discrete(name = "Cause of Concussion")


```

## Punt Returner Injuries

We need to drill down into this further, and compare this to the control data to see if there is anything significantly different that may shed light as to why Punt Returners are more prone to injuries. Below is a plot of the location of the Punter and the Punt Returner on each of the injured plays and where they ran once they received the ball. Visually we can see that the punts occurred in similar position, catches occurred around the same area and yardage gained seems minimal.

``` {r punt_returners, echo=FALSE}
# Read in the NGS Master data - This has been combined outside of this kernel and contains the NGS data from all punt plays
NGS_Master_Data = fread(file.path(file_list[18]))

# Get the Game and Plays of the Punt Returner Concussions with Punter
injured_punt_returner_data = video_review_data_player_roles_data[Role=="PR"]

injured_punt_returner_NGS = NGS_Master_Data[GameKey %in% injured_punt_returner_data$GameKey & 
                                    PlayID %in% injured_punt_returner_data$PlayID &
                                    GSISID %in% injured_punt_returner_data$GSISID]

# Now get the punters in each of these games
punter_data = player_role_punt_data[Role=="P" & GameKey %in% injured_punt_returner_data$GameKey & 
                                    PlayID %in% injured_punt_returner_data$PlayID]

# Now let us create the data for the punt return mapping
punt_return_mapping_data = injured_punt_returner_NGS[Event %in% c("kick_received","punt_received","play_submit","punt_land")][order(Time)]

# Get the punter mapping data
punter_mapping_data = NGS_Master_Data[GameKey %in% punter_data$GameKey & 
                                    PlayID %in% punter_data$PlayID &
                                    GSISID %in% punter_data$GSISID &
                                    Event=="punt"]

# If the x is greater than 60 flip it around, i.e do 120 minus it
punter_mapping_data[x>=60]$x = 120 - punter_mapping_data[x>=60]$x
# Do the opposite for the punt_return_mapping_data
punt_return_mapping_data[x<=60]$x = 120 - punt_return_mapping_data[x<=60]$x

# Now join the two for a plot
punter_mapping_data$Role = "Punter"
punt_return_mapping_data$Role = "Punt Returner"
injured_punt_return_plotting_data = rbind(punter_mapping_data[,c("GameKey","PlayID","GSISID", "x","y","Role","Event")], punt_return_mapping_data[,c("GameKey","PlayID","GSISID", "x","y","Role","Event")])

# Now let us map the x and y coordinates of the punter
ggplot(data = injured_punt_return_plotting_data) + geom_point(aes(x = x, y=y, color=Role)) + coord_cartesian(xlim=c(0, 100), ylim=c(0,60)) + geom_line(aes(x = x, y=y, group=paste(PlayID,GSISID), color = Role)) + geom_label_repel(aes(x=x,y=y,label = GameKey),
                  nudge_x = 0.3,
                  na.rm = TRUE) + xlab("Length of Field") + ylab("Width of Field")

```

``` {r control_punt_returners, echo=FALSE}
# Look at control

# Get the GSISID of the Punter and returner from control plays
control_punt_NGS_gamekeys = player_role_punt_data[paste(GameKey,PlayID) %in% paste(video_control_data$gamekey,video_control_data$playid) & Role %in% c("PR","P")]

# Get the Game and Plays of the Punt Returner Controls
control_punt_NGS = NGS_Master_Data[paste(GameKey,PlayID,GSISID) %in% paste(control_punt_NGS_gamekeys$GameKey, 
                                   control_punt_NGS_gamekeys$PlayID,
                                   control_punt_NGS_gamekeys$GSISID)]

# Merge the role into the NGS data
control_punt_NGS = merge(control_punt_NGS,control_punt_NGS_gamekeys,by=c("GameKey", "PlayID", "GSISID"),all.x=T)

# Now let us create the data for the punt return mapping
control_punt_return_mapping_data = control_punt_NGS[Event %in% c("kick_received","punt_received","play_submit","punt_land","punt")][order(Time)]

# If the x is greater than 60 flip it around, i.e do 120 minus it
control_punt_return_mapping_data[Role=="P"&x>=60]$x = 120 - control_punt_return_mapping_data[Role=="P"&x>=60]$x
# Do the opposite for the punt returner
control_punt_return_mapping_data[Role=="PR"&x<=60]$x = 120 - control_punt_return_mapping_data[Role=="PR"&x<=60]$x

# Now join the two for a plot
control_punt_return_mapping_data[Role=="P"]$Role = "Punter"
control_punt_return_mapping_data[Role=="PR"]$Role = "Punt Returner"

```

## Factors Involved In Punt Returner Injuries

Now that we can visualise the location of the punts, the receptions and the distance travelled by each player before being injured, our next logical step is to look into these three factors that attributed to the injury of the punt returner.

### Location of Punt

Punt plays can be an extremely significant momentum booster for teams during pivotal moments of the game. If the defence has done its job and limited the opposition to minimal yardage, then it is the role of the punt returners to capitalise on this and return the ball for maximum yards. Our first factor we look into is the location of the punt. If the team punting is punting the ball from deep inside their own half, the punt returner may feel pressured or obliged to return the ball as much as they can to capitalise on this, rather than take a fair catch.

Below we have looked into this firstly and compared the locations of the 'control' punts and the punts that resulted in a punt returner being injured. As shown in the graph below, all the punts that resulted in a punt returner being injured occurred when the punt was within 20 yards of the end zone. Therefore the location of the punt being so close to the end zone may have an impact on punt returner injuries.

``` {r punt_return, echo=FALSE}
# Now let us merge the control and injured data
injured_punt_return_plotting_data$Injured_or_Control = "Injured"
control_punt_return_mapping_data = control_punt_return_mapping_data[,c("GameKey","PlayID","GSISID", "x","y","Role","Event")] 
control_punt_return_mapping_data$Injured_or_Control = "Control"
merged_punt_return_data = rbind(injured_punt_return_plotting_data,control_punt_return_mapping_data)

# Now subset out just the locations of the punt and distance from end zone
merged_punt_return_data[Role=="Punter"&Event=="punt"]$x = merged_punt_return_data[Role=="Punter"&Event=="punt"]$x-10
punt_location = merged_punt_return_data[Role=="Punter"&Event=="punt"]

# Now plot this as a graph
ggplot(punt_location,aes(x=reorder(paste(GameKey, PlayID), -x),y=x, fill=Injured_or_Control)) +geom_bar(stat = "identity") + xlab("NFL Punt Play") + ylab("Yards from End Zone") + ggtitle("Yards from End Zone by Punt Play") + theme(plot.title = element_text(hjust = 0.5)) + scale_fill_discrete(name = "Injured or Control Data") + scale_x_discrete(breaks = seq(0, 48, 2)) 

```


### Location of Reception

Just as we did with the location of the punt, it is also important to understand the location of the reception. For punt plays that resulted in the punt returner being injured, punts are generally received from within the 30 yard line, with one exception. Visually, we can see that this is about average for punt plays, so we must still look into other factors to gain value out of this insight.


``` {r , echo=FALSE}

# Now subset out just the locations of the punt reception and distance from end zone
punt_reception = merged_punt_return_data[Role=="Punt Returner"&Event!="punt"&Event!="play_submit"]
punt_reception$x = 120 - punt_reception$x
punt_reception$x = punt_reception$x - 10
punt_reception = punt_reception[order(x)]
punt_reception = punt_reception[!duplicated(paste(GameKey, PlayID, GSISID)),]

# Now plot this as a graph
ggplot(punt_reception,aes(x=reorder(paste(GameKey, PlayID, GSISID), -x),y=x, fill=Injured_or_Control)) +geom_bar(stat = "identity") + xlab("NFL Return Play") + ylab("Yards from End Zone") + ggtitle("Yards from End Zone by Return Play") + theme(plot.title = element_text(hjust = 0.5)) + scale_fill_discrete(name = "Injured or Control Data") + scale_x_discrete(breaks = seq(0, 48, 2)) 


```

### Distance of Punt to Reception

The distance of the punt will also play a key part as longer punts will generally result in a reception as the punt returner has more time to return the ball, whereas short punts result in a fair catch.  As shown there is a fairly regular distribution of the distance of the punt between 'control' and 'injured' scenarios. Each punt was over 50 yards however which is interesting to note.

``` {r, echo=FALSE}
merge_punt_yardage = merge(punt_reception,punt_location, by=c("GameKey", "PlayID"))
# Now change the first x to out of 100
merge_punt_yardage$x.x = 100 - merge_punt_yardage$x.x

# Work out the yardage
merge_punt_yardage$Yardage = merge_punt_yardage$x.x - merge_punt_yardage$x.y

# Now plot this as a graph
ggplot(merge_punt_yardage,aes(x=reorder(paste(GameKey, PlayID), -Yardage),y=Yardage, fill=Injured_or_Control.x)) +geom_bar(stat = "identity") + xlab("NFL Punt Play") + ylab("Distance From Punt To Reception") + ggtitle("Distance per Punt Play") + theme(plot.title = element_text(hjust = 0.5)) + scale_fill_discrete(name = "Injured or Control Data") + scale_x_discrete(breaks = seq(0, 48, 2)) 
```

### Distance after Reception

Our final key factor to look into is the distance after the reception for both 'control' and 'injury' punt plays. As we can observe, 10 yards is the maximum distance gained on these punt plays where the punt returner was injured, which is quite low when compared to 'control' punts. This potentially means that the punt returner did not have a lot of space after catching the ball to run and thus was injured quite easily. As shown in the previous graphs, the punt returner generally caught it deep in their own half and were fielding a punt that was kicked deep in opposition territory, thus their reason for returning the punt rather than calling a fair catch.

``` {r, echo=FALSE}
# Now let us look at yards gained on each punt
punt_yards_gained = merged_punt_return_data[order(GameKey,PlayID,GSISID,Event)][Role!="Punter"][Event!="punt"]

# Get the min x minus the max x in each situation to get the yards gaine
punt_yards_gained = punt_yards_gained[,.(Yards_Gained = max(x) - min(x)), by=c("GameKey","PlayID","GSISID","Injured_or_Control")]

# Remove any of the 0s
punt_yards_gained = punt_yards_gained[Yards_Gained!=0]

# Now plot this as a graph
ggplot(punt_yards_gained,aes(x=reorder(paste(GameKey, PlayID), -Yards_Gained),y=Yards_Gained, fill=Injured_or_Control)) +geom_bar(stat = "identity") + xlab("NFL Punt Play") + ylab("Yards Gained After Reception") + ggtitle("Yards Gained per Punt Play") + theme(plot.title = element_text(hjust = 0.5)) + scale_fill_discrete(name = "Injured or Control Data") + scale_x_discrete(breaks = seq(0, 48, 2)) 
```

## Rule Number 1 - Adjustment to the Fair Catch Rule for the Protection of Punt Returners

As we can observe the instances where punt returners caught the ball and were injured resulted in only a gain of 10 yards. These cases were also punted inside the 20 yard line and generally received inside the 30 yard line. As shown in the graphs above and summarised in the graph below, Control plays did not have a similar distribution of location, rather they were either punter further out and received deeper than injured plays, or punted extremely close to the end zone and received 40-50 yards from the end zone.

This rule change would only affect punts in the bottom left quadrant of the graph, thus not impacting the majority of punts, but still having an impact on those punt plays that result in injury. The rule change would involve adjusting the fair catch rule so that if a punt was kicked from inside the 20 yard line and caught inside the 30 yard line on the other side of the field, the fair catch would result in a 10 yard gain for the person calling it from the spot of reception, rather than the ball being placed at the spot of the fair catch.

In this way the value and integrity of the game would still remain, as this rule would not hinder on too many punt plays, and would still encourage the return team to return the ball in other instances, but also allow protection of the punt returner without the pressure of having to return the ball to capitalise on the defensive play of his team.


``` {r, echo=FALSE}

quadrant_data = merge(punt_reception,punt_location,by=c("GameKey", "PlayID"))
ggplot(quadrant_data, aes(x=x.y, y=x.x)) +
  geom_point(aes(color = factor(Injured_or_Control.x))) +
  #lims(x=c(1,10),y=c(1,10)) +
  theme_minimal() +
  coord_fixed() +  
  geom_vline(xintercept = 20) + geom_hline(yintercept = 32) + xlab("Yards From End Zone of Punter") + ylab("Yards From End Zone For Punt Returner") + ggtitle("Punt Location vs Punt Reception") + theme(plot.title = element_text(hjust = 0.5))+labs(color = "Injured or Control Data")


```

## Positioning of Players on Punt Return

In order for the rule above to work effectively, the punt returner must know that the defence is close in order to call for a fair catch. The punt returner generally has his eyes on the ball and is not entirely aware of the location of players around him. In regards to the hypothesised rule above, we do not want the player calling a fair catch and not realising they had the opportunity to run for more than 10 yards.

As shown visually in the graph below, we can see that more than 60% of the time, the player closest to the punt returner is a player on the punt coverage team. This leads me to my next hypothesis that a protective player, most likely in the 'PFB' position is compulsory or required to provide protection for the punt returner and be within at least 10 yards of them until the ball is received. 

``` {r, echo=FALSE}

# Get all the catches behind the 30 yard line and assign them a key
punt_reception$Behind_30 = "No"
punt_reception[x<=30]$Behind_30 = "Yes"
punt_yards_gained$key = paste(punt_yards_gained$GameKey,punt_yards_gained$PlayID)
punt_reception$key = paste(punt_reception$GameKey,punt_reception$PlayID)

# Now get the NGS Master data with these keys
punt_return_NGS = NGS_Master_Data %>% copy()
punt_return_NGS$key = paste(punt_return_NGS$GameKey,punt_return_NGS$PlayID)
punt_return_NGS = merge(punt_return_NGS,punt_reception[,c("key","Behind_30")],by=c("key"))
punt_return_NGS = punt_return_NGS[Event %in% c("kick_received","punt_received","punt_land")]


# Add the role in based on the GSISID
player_role_punt_data$key = paste(player_role_punt_data$GameKey,player_role_punt_data$PlayID)
player_role_punt_data$GSISID_key = paste(player_role_punt_data$GameKey,player_role_punt_data$PlayID,player_role_punt_data$GSISID)
punt_return_NGS$GSISID_key = paste(punt_return_NGS$GameKey,punt_return_NGS$PlayID, punt_return_NGS$GSISID)

# Merge the two to get the Role
punt_return_NGS = punt_return_NGS %>% merge(player_role_punt_data[,c("GSISID_key","Role")],by="GSISID_key") %>% data.table()

# Get the x and y coordinates of each PR
punt_return_NGS = punt_return_NGS %>% merge(punt_return_NGS[Role=="PR"&Time!="2017-09-17 20:53:19.400"][,c("key","x","y")],by="key")

# Add in whether it is punt return or coverage team
punt_return_NGS$Side_of_Ball = "NA"
punt_return_NGS[Role %in% punt_return_positions]$Side_of_Ball = "Punt Return"
punt_return_NGS[Role %in% punt_coverage_positions]$Side_of_Ball = "Punt Coverage"

# Now get the distance of x and y coordinates
#sqrt((x2-x1)^2 + (y2-y1)^2)
punt_return_NGS[,Distance := sqrt((x.x - x.y)^2 + (y.x - y.y)^2)]

# Remove Distance as 0 and get the min distance
merge_punt_return_NGS = punt_return_NGS[Distance != 0] %>% 
  group_by(key) %>% 
  slice(which.min(Distance))
merge_punt_return_NGS = merge_punt_return_NGS %>% merge(punt_yards_gained[,c("Injured_or_Control", "Yards_Gained","key")],by="key") %>% data.table()

# Create a table of the injured and side of ball facts
merge_punt_return_NGS_table = merge_punt_return_NGS[,.(Count=length(unique(key))),by=c("Behind_30","Side_of_Ball","Injured_or_Control")]

ggplot(merge_punt_return_NGS_table,aes(x=reorder(Side_of_Ball, -Count),y = Count, fill=Injured_or_Control)) +geom_bar(stat = "identity") + xlab("Team Closest to Punt Returner") + ylab("Number of Plays") + ggtitle("Team Closest to the Punt Returner When Ball is Caught") + theme(plot.title = element_text(hjust = 0.5)) + scale_fill_discrete(name = "Injured or Control Data")


```

### Current Plays With and Without Blockers/PFBs

In the the 74 plays recorded by the control and injury data (37 each), only 7 of them (less than 10%) had a player listed in the 'PFB' position. As shown in the graph below, 3 of these plays resulted in injuries and 4 were control data. Of the injured plays, only 1 resulted in the injury of the PFB when they were blocking, the other two were not affected by this positioning. Therefore more data is needed to test the effectiveness of this idea that placing a PFB or a blocker within 10 yards of the Punt Returner may be an effective way to protect them.


```{r, echo=FALSE}

# Now get the NGS Master data with these keys
punt_return_NGS = NGS_Master_Data %>% copy()
punt_return_NGS$key = paste(punt_return_NGS$GameKey,punt_return_NGS$PlayID)
punt_return_NGS$Reception_Behind_30 = "No"
punt_return_NGS[key %in% unique(punt_reception[Behind_30=="Yes"]$key)]$Reception_Behind_30 = "Yes"

#punt_return_NGS = punt_return_NGS[Event %in% c("kick_received","punt_received","punt_land")]

# Add the role in based on the GSISID
punt_return_NGS$GSISID_key = paste(punt_return_NGS$GameKey,punt_return_NGS$PlayID, punt_return_NGS$GSISID)

# Merge the two to get the Role
punt_return_NGS = punt_return_NGS %>% merge(player_role_punt_data[,c("GSISID_key","Role")],by="GSISID_key") %>% data.table()

pfb_keys = punt_return_NGS[Role=="PFB"]$key %>% unique() %>% sort()

video_injury_data$key = paste(video_injury_data$gamekey,video_injury_data$playid)
video_control_data$key = paste(video_control_data$gamekey,video_control_data$playid)


video_injury_data$source = "Injury"
video_control_data$source = "Control"

# Now merge them into one
PFB_data = rbind(video_injury_data[,c("key","source")],video_control_data[,c("key","source")])

PFB_data[,PFB:=ifelse(key %in% pfb_keys,"PFB","No PFB")]

# Count it all up
count_PFB_data = PFB_data[,length(unique(key)),by=c("source","PFB")]

# Now plot it
ggplot(count_PFB_data,aes(x=reorder(source, -V1),y = V1, fill=PFB)) +geom_bar(stat = "identity") + xlab("Injury or Control Data") + ylab("Number of Plays") + ggtitle("Number of NFL Punt Plays with  PFB in Punt Return Team") + theme(plot.title = element_text(hjust = 0.5)) + scale_fill_discrete(name = "PFB Label")

```

## Rule 2 - PFB Compulsory Requirement on Punt Returns

Therefore my final proposed rule is that on punt returns must have a blocker or another teammate within 10 yards until reception in order to help block and protect the Punt Returner from injury. More data is needed to test this effectiveness, but it can help the Punt Returner make a decision as to whether a fair catch is an appropriate call. This rule may impact upon the integrity and value of the game, however the most important part is that it protects the Punt Returner.

## Summary

In conclusion, after analysing all the data provided, I have proposed two rule changes. The first rule change involved adjusting the fair catch rule when the ball is punted within the 20 yard line and received inside the opposing 30 yard line. This would allow a 10 yard gain from the point of the catch.

The second rule would involve adjusting formations for the receiving team to ensure a blocker is permanently placed in front of the Punt Returner to assist with these fair catch calls and to block for the Punt Returner who is generally surrounded by an opposition player at the point of reception.  