1pub struct EloRank {
2 pub k: i32,
3 pub players: Vec<f64>,
4 pub score_base: f64,
5}
6
7impl Default for EloRank {
8 fn default() -> EloRank {
9 EloRank {
10 k: 32,
11 players: vec![1000f64, 1000f64],
12 score_base: 1.0,
13 }
14 }
15}
16
17impl EloRank {
18 fn calculate_expected(&self) -> Vec<f64> {
19 let amount_of_players = self.players.len() as f64;
20 let mut expected_array: Vec<f64> = vec![];
21 for (i, _) in self.players.iter().enumerate() {
22 let sum = self.players.iter().enumerate().fold(0f64, |s, (j, p)| {
23 if i == j {
24 s
25 } else {
26 s + 1.0 / (1.0 + 10f64.powf((p - self.players[i]) / 400f64))
27 }
28 });
29 let expected = sum / ((amount_of_players * (amount_of_players - 1f64)) / 2f64);
30 expected_array.push(expected)
31 }
32 expected_array
33 }
34
35 fn calculate_scores(&self) -> Vec<f64> {
36 let amount_of_players = self.players.len() as f64;
37 let mut scores: Vec<f64> = vec![];
38 for (i, _) in self.players.iter().enumerate() {
39 let score: f64;
40 if self.score_base == 1.0 {
41 score = (amount_of_players - (i as f64 + 1f64))
42 / (amount_of_players * (amount_of_players - 1f64) / 2f64);
43 } else {
44 score = (self.score_base.powf(amount_of_players - (i + 1) as f64) - 1f64)
45 / (self.players.iter().enumerate().fold(0.0, |s, (j, _)| {
46 s + (self.score_base.powf(amount_of_players - (j + 1) as f64) - 1f64)
47 }));
48 }
49 scores.push(score);
50 }
51 scores
52 }
53
54 pub fn calculate(&self) -> Vec<f64> {
55 let amount_of_players = self.players.len() as f64;
56 let expected = self.calculate_expected();
57 let scores = self.calculate_scores();
58 let mut new_elo: Vec<f64> = vec![];
59 for (i, p) in self.players.iter().enumerate() {
60 new_elo
61 .push(p + (self.k as f64) * (amount_of_players - 1f64) * (scores[i] - expected[i]));
62 }
63 new_elo
64 }
65}
66
67#[cfg(test)]
68mod tests {
69 use crate::EloRank;
70 #[test]
71 fn test_elo() {
72 let elo = EloRank {
73 players: vec![897.0, 978.0],
74 ..Default::default()
75 };
76 assert_eq!(elo.calculate(), vec![916.6640435522738, 958.3359564477262]);
77
78 let elo = EloRank {
79 players: vec![897.0, 978.0],
80 score_base: 2.0,
81 ..Default::default()
82 };
83
84 assert_eq!(elo.calculate(), vec![916.6640435522738, 958.3359564477262]);
85
86 let elo = EloRank {
87 players: vec![978.0, 897.0],
88 ..Default::default()
89 };
90 assert_eq!(elo.calculate(), vec![990.3359564477262, 884.6640435522738]);
91
92 let elo = EloRank {
93 players: vec![1000.0, 1000.0, 1000.0],
94 ..Default::default()
95 };
96 assert_eq!(
97 elo.calculate(),
98 vec![1021.3333333333334, 1000.0, 978.6666666666666]
99 );
100
101 let elo = EloRank {
102 players: vec![1000.0, 1000.0, 1000.0],
103 score_base: 1.5,
104 ..Default::default()
105 };
106 assert_eq!(
107 elo.calculate(),
108 [1024.3809523809523, 996.952380952381, 978.6666666666666]
109 );
110
111 let elo = EloRank {
112 players: vec![897.0, 978.0, 982.0, 995.0, 1017.0, 1034.0, 1096.0],
113 ..Default::default()
114 };
115 assert_eq!(
116 elo.calculate(),
117 vec![
118 933.4271852776218,
119 998.2520240277877,
120 992.7510517787325,
121 995.4420183323965,
122 1006.3245067439552,
123 1012.6627230848082,
124 1060.140490754698
125 ]
126 );
127 }
128}