txt <- readLines("tournamentinfo.txt")
## Warning in readLines("tournamentinfo.txt"): incomplete final line found on
## 'tournamentinfo.txt'
raw <- paste(txt, collapse = "\n")
blocks <- str_split(raw, "-{5,}\\s*\\n", simplify = TRUE) |>
  as.vector() |>
  keep(~ str_squish(.x) != "")

# Parser for a single two-line player block
parse_player <- function(block) {
  name_line <- str_match(block,
    "(?m)^\\s*(\\d+)\\s*\\|\\s*([A-Z' .-]+?)\\s*\\|\\s*([0-9.]+)\\s*\\|(.*)\\|\\s*$"
  )
  state_line <- str_match(block,
    "(?m)^\\s*([A-Z]{2})\\s*\\|\\s*\\d+\\s*/\\s*R:\\s*(\\d+)[A-Z]*\\d*\\s*->\\s*\\d+"
  )

  if (any(is.na(name_line)) || any(is.na(state_line))) return(NULL)

  pairNum   <- as.integer(name_line[2])
  name      <- str_squish(name_line[3])
  totalPts  <- as.numeric(name_line[4])
  roundsStr <- name_line[5]
  state     <- state_line[2]
  preRating <- as.integer(state_line[3])

  # Extract opponent pair numbers from W/L/D results
  opps <- str_match_all(roundsStr, "[WLD]\\s*(\\d+)")[[1]]
  opps <- if (length(opps)) as.integer(opps[,2]) else integer()

  tibble(pairNum, name, state, totalPts, preRating, opps = list(opps))
}

players <- map(blocks, parse_player) |> compact()

players <- bind_rows(players)
stopifnot(is_tibble(players), nrow(players) > 0)

ratingByPair <- setNames(players$preRating, players$pairNum)

avgOpp <- map_dbl(players$opps, function(os) {
  if (length(os) == 0) return(NA_real_)
  round(mean(ratingByPair[as.character(os)]))
})

out <- players |>
  mutate(
    `Player Name` = str_to_title(name),
    `Player State` = state,
    `Total Points` = totalPts,
    `Pre Rating` = preRating,
    `Average Opponent Pre Rating` = avgOpp
  ) |>
  select(`Player Name`, `Player State`, `Total Points`, `Pre Rating`, `Average Opponent Pre Rating`) |>
  arrange(desc(`Total Points`), `Player Name`)

write_csv(out, "tournament_results.csv")
out %>% head(10)
## # A tibble: 10 × 5
##    `Player Name`       `Player State` `Total Points` `Pre Rating`
##    <chr>               <chr>                   <dbl>        <int>
##  1 Aditya Bajaj        MI                        6           1384
##  2 Dakshesh Daruri     MI                        6           1553
##  3 Gary Hua            ON                        6           1794
##  4 Hanshi Zuo          MI                        5.5         1655
##  5 Patrick H Schilling MI                        5.5         1716
##  6 Anvit Rao           MI                        5           1365
##  7 Ezekiel Houghton    MI                        5           1641
##  8 Gary Dee Swathell   MI                        5           1649
##  9 Hansen Song         OH                        5           1686
## 10 Stefano Lee         ON                        5           1411
## # ℹ 1 more variable: `Average Opponent Pre Rating` <dbl>