1pub mod elo {
2 pub enum MatchWinner {
3 PlayerB = 0,
4 PlayerA = 1,
5 }
6
7 pub struct EloRank {
8 pub k: i32,
9 }
10
11 impl EloRank {
12
13 fn calculate_expected(&self, score_a: f64, score_b: f64) -> f64 {
14 1.0 / (1.0 + (10f64.powf((score_b - score_a) / 400.0)))
15 }
16
17 fn winner_to_score(&self, winner: MatchWinner) -> (f64, f64) {
18 match winner {
19 MatchWinner::PlayerA => (1.0, 0.0),
20 MatchWinner::PlayerB => (0.0, 1.0),
21 }
22 }
23
24 pub fn calculate(&self, player_a: f64, player_b: f64, winner: MatchWinner) -> (f64, f64) {
25 let k = self.k as f64;
26
27 let expected_a = self.calculate_expected(player_a, player_b);
28 let expected_b = self.calculate_expected(player_b, player_a);
29
30 println!("{} {}", player_a, expected_a);
31 println!("{} {}", player_b, expected_b);
32
33 let (score_a, score_b) = self.winner_to_score(winner);
34 let new1 = player_a + k * (score_a - expected_a);
35 let new2 = player_b + k * (score_b - expected_b);
36
37 (new1.round(), new2.round())
38 }
39 }
40}
41
42#[cfg(test)]
43mod tests {
44 use crate::elo::{EloRank, MatchWinner};
45
46 #[test]
47 fn calculates_correct_ratings() {
48 let elo = EloRank { k: 32 };
49 let (player_a_new, player_b_new) = elo.calculate(1200.0, 1400.0, MatchWinner::PlayerA);
50 assert_eq!(player_a_new, 1224.0);
51 assert_eq!(player_b_new, 1376.0);
52
53 let (player_a_new, player_b_new) = elo.calculate(1200.0, 1400.0, MatchWinner::PlayerB);
54 assert_eq!(player_a_new, 1192.0);
55 assert_eq!(player_b_new, 1408.0);
56 }
57
58 #[test]
59 fn rounds_ratings_properly() {
60 let elo = EloRank { k: 32 };
61 let (player_a_new, player_b_new) = elo.calculate(1802.0, 1186.0, MatchWinner::PlayerA);
62 assert_eq!(player_a_new, 1803.0);
63 assert_eq!(player_b_new, 1185.0);
64 }
65}