-
Notifications
You must be signed in to change notification settings - Fork 1
/
elo.cpp
executable file
·118 lines (103 loc) · 2.28 KB
/
elo.cpp
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
/***
elo.cpp
Calculate Elo performance ratings for a series of paired game results.
Can be used to rank things: let the "game" be 'which item is better?',
get the results for each possible pair, and calculate the Elo.
Copyright (c) 2022 Chris Street.
***/
EloResult::EloResult(int winner, int loser) {
w = winner;
l = loser;
}
EloCalc::EloCalc() {
base_rating = 1000;
algorithm400 = 400;
min_i = INT32_MAX;
max_i = INT32_MIN;
ratings = nullptr;
cratings = 0;
}
EloCalc::EloCalc(int base_rating_, u32 algorithm400_) {
base_rating = base_rating_;
algorithm400 = algorithm400_;
min_i = INT32_MAX;
max_i = INT32_MIN;
ratings = nullptr;
cratings = 0;
}
EloCalc::~EloCalc() {
if (ratings != nullptr) {
delete ratings;
ratings = nullptr;
cratings = 0;
}
}
void EloCalc::add_result(const EloResult& er) {
if (er.w < min_i)
min_i = er.w;
if (er.l < min_i)
min_i = er.l;
if (er.l > max_i)
max_i = er.l;
if (er.w > max_i)
max_i = er.w;
results.push_back(er);
}
void EloCalc::clear() {
results.clear();
min_i = INT32_MAX;
max_i = INT32_MIN;
if (ratings != nullptr) {
delete ratings;
ratings = nullptr;
cratings = 0;
}
}
void EloCalc::calc_ratings(u32 max_iter) {
int ct = max_i - min_i + 1, e;
u32 i = 0;
if (cratings < ct) {
if (ratings != nullptr) {
delete ratings;
}
ratings = new int [ct];
cratings = ct;
}
for (i = 0; i < cratings; ++i)
ratings[i] = base_rating;
i = 0;
while (i < max_iter) {
int j;
for (j = min_i; j <= max_i; ++j) {
int w, l;
ct = 0; // total rating of j's opponents
w = 0; // j's wins
l = 0; // j's losses
for (const auto& r : results) {
if (r.w == j) {
++w;
ct += ratings[r.l - min_i];
} else if (r.l == j) {
++l;
ct += ratings[r.w - min_i];
}
}
if (0 == w + l)
continue;
/* j's new rating. */
ratings[j - min_i] = (ct + int(algorithm400) * (w - l)) / (w + l);
}
// perform multiple iterations to converge on the correct Elo ratings.
++i;
}
}
int EloCalc::elo_rating(int idx) const {
if (idx < min_i)
return base_rating;
if (idx > max_i)
return base_rating;
idx -= min_i;
if (idx >= cratings)
return base_rating;
return ratings[idx];
}