library(dplyr)
## 
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union

Chess ELO Expected Score Calculator

# Chess ELO Expected Score Calculator
# Formula source: Solon, Nate. "How Elo Ratings Actually Work." Zwischenzug, 
# https://zwischenzug.substack.com/p/how-elo-ratings-actually-work
# Expected Score = 1 / (1 + 10^((opponent_rating - player_rating)/400))

# Sample data structure - replace with your actual tournament data
chess_data <- data.frame(
  player_name = c("Player A", "Player B", "Player C", "Player D", "Player E"),
  player_rating = c(1800, 1650, 1900, 1750, 1600),
  actual_score = c(4.0, 3.5, 4.5, 2.5, 3.0),
  # Opponent ratings as lists (you'll need to format your data this way)
  opponent_ratings = I(list(
    c(1700, 1800, 1650, 1750, 1900),  # Player A's opponents
    c(1600, 1750, 1800, 1900, 1700),  # Player B's opponents
    c(1800, 1650, 1750, 1600, 1700),  # Player C's opponents
    c(1900, 1700, 1600, 1800, 1650),  # Player D's opponents
    c(1750, 1900, 1700, 1650, 1800)   # Player E's opponents
  ))
)

Function to calculate expected score

calculate_expected_score <- function(player_rating, opponent_ratings) {
  expected_scores <- sapply(opponent_ratings, function(opp_rating) {
    1 / (1 + 10^((opp_rating - player_rating) / 400))
  })
  return(sum(expected_scores))
}

# Calculate expected scores and performance differences
results <- chess_data %>%
  rowwise() %>%
  mutate(
    expected_score = calculate_expected_score(player_rating, opponent_ratings),
    performance_diff = actual_score - expected_score,
    over_under = ifelse(performance_diff > 0, "Overperformed", "Underperformed")
  ) %>%
  ungroup()

Analyze and display results

print("Chess Tournament Performance Analysis:")
## [1] "Chess Tournament Performance Analysis:"
print(results[, c("player_name", "actual_score", "expected_score", "performance_diff")])
## # A tibble: 5 × 4
##   player_name actual_score expected_score performance_diff
##   <chr>              <dbl>          <dbl>            <dbl>
## 1 Player A             4             2.77            1.23 
## 2 Player B             3.5           1.85            1.65 
## 3 Player C             4.5           3.76            0.739
## 4 Player D             2.5           2.64           -0.140
## 5 Player E             3             1.48            1.52
# Top 5 overperformers
top_over <- results %>%
  arrange(desc(performance_diff)) %>%
  head(5)

print("\nTop 5 Overperformers:")
## [1] "\nTop 5 Overperformers:"
print(top_over[, c("player_name", "performance_diff")])
## # A tibble: 5 × 2
##   player_name performance_diff
##   <chr>                  <dbl>
## 1 Player B               1.65 
## 2 Player E               1.52 
## 3 Player A               1.23 
## 4 Player C               0.739
## 5 Player D              -0.140
# Top 5 underperformers  
top_under <- results %>%
  arrange(performance_diff) %>%
  head(5)

print("\nTop 5 Underperformers:")
## [1] "\nTop 5 Underperformers:"
print(top_under[, c("player_name", "performance_diff")])
## # A tibble: 5 × 2
##   player_name performance_diff
##   <chr>                  <dbl>
## 1 Player D              -0.140
## 2 Player C               0.739
## 3 Player A               1.23 
## 4 Player E               1.52 
## 5 Player B               1.65