Add chess-style Elo ratings for players
Each player's rating starts at 1500 and updates transactionally with every finished match: a team's rating is the mean of its two members and the standard K=32 formula decides the zero-sum delta applied to both members of a team. Ratings are per game type in a new player_rating table; match_player records each match's elo_delta. - GET /api/leaderboard exposes elo and sorts by it - GET /api/me/matches includes per-player elo deltas - new GET /api/me/ratings returns the caller's rating per game type - frontend: Elo column on the leaderboard, per-match delta in the history page, current rating in the lobby - python -m tavolo.backfill_elo recomputes all ratings from the recorded match history (one-off backfill for existing matches)
This commit is contained in:
@@ -72,6 +72,10 @@ pub fn HistoryPage() -> View {
|
||||
.collect::<Vec<_>>()
|
||||
.join(" & ");
|
||||
let outcome = if m.you_won { "Won" } else { "Lost" };
|
||||
let elo_delta = m
|
||||
.your_elo_delta
|
||||
.map(|d| if d >= 0 { format!("+{d}") } else { d.to_string() })
|
||||
.unwrap_or_else(|| "—".to_string());
|
||||
view! {
|
||||
tr {
|
||||
td { (m.finished_at.replace('T', " ").chars().take(16).collect::<String>()) }
|
||||
@@ -80,6 +84,9 @@ pub fn HistoryPage() -> View {
|
||||
td { (m.team_a_score) " – " (m.team_b_score) }
|
||||
td { "Team " (m.winner_team) }
|
||||
td(class=if m.you_won { "won" } else { "lost" }) { (outcome) }
|
||||
td(class=if m.you_won { "won" } else { "lost" }) {
|
||||
(elo_delta)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -94,6 +101,7 @@ pub fn HistoryPage() -> View {
|
||||
th { "Score" }
|
||||
th { "Winner" }
|
||||
th { "You" }
|
||||
th { "Elo" }
|
||||
}
|
||||
}
|
||||
tbody { (table_rows) }
|
||||
|
||||
Reference in New Issue
Block a user