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