10 #include <Eigen/Cholesky>
11 #include <Eigen/Dense>
13 #include "ziggurat.hpp"
16 using namespace Eigen;
18 #define MAX_PLAYERS 16
20 float match_stddev = 70.0f;
26 struct highest_ranking {
28 bool operator() (const player &a, const player &b) const {
29 if (a.points != b.points) {
30 return a.points > b.points;
32 return a.margin > b.margin;
39 return rand() * (1.0f / RAND_MAX);
42 // FIXME: replace rejection method with a better method! this one can only ever go to [-5z, +5z]
44 float draw_gaussian(float stddev)
47 float z = draw_unit() * 10.0f - 5.0f;
48 float y = draw_unit();
55 float draw_gaussian(float mu, float stddev)
57 static bool inited = false;
58 static long unsigned seed = time(NULL);
60 static float fn[128], wn[128];
62 r4_nor_setup(kn, fn, wn);
66 return r4_nor(&seed, kn, fn, wn) * stddev + mu;
70 int main(int argc, char **argv)
72 int trials = atoi(argv[1]);
74 if (scanf("%f", &match_stddev) != 1) {
75 fprintf(stderr, "Could't read match stddev\n");
80 if (scanf("%d", &num_players) != 1) {
81 fprintf(stderr, "Could't read number of players\n");
85 if (num_players > MAX_PLAYERS) {
86 fprintf(stderr, "Max %d players supported\n", MAX_PLAYERS);
90 vector<string> players;
91 map<string, int> player_map;
92 Matrix<float, Dynamic, 1, 0, MAX_PLAYERS, 1> ratings(num_players);
93 bool has_scores[MAX_PLAYERS][MAX_PLAYERS];
94 for (int pl1 = 0; pl1 < num_players; ++pl1) {
95 for (int pl2 = 0; pl2 < num_players; ++pl2) {
96 has_scores[pl1][pl2] = false;
100 int scores[MAX_PLAYERS][MAX_PLAYERS];
101 for (int i = 0; i < num_players; ++i) {
104 int ret = scanf("%s %f", buf, &rating);
106 fprintf(stderr, "Couldn't read player %d\n", i);
113 players.push_back(buf);
118 Matrix<float, Dynamic, Dynamic, 0, MAX_PLAYERS, MAX_PLAYERS> ratings_cov(num_players, num_players);
119 for (int i = 0; i < num_players; ++i) {
120 for (int j = 0; j < num_players; ++j) {
122 if (scanf("%f", &f) != 1) {
123 fprintf(stderr, "Couldn't read covariance matrix element (%d,%d)\n", i, j);
126 ratings_cov(i, j) = f;
129 Matrix<float, Dynamic, Dynamic, 0, MAX_PLAYERS, MAX_PLAYERS> ratings_cholesky =
130 ratings_cov.llt().matrixLLT();
133 char pl1[256], pl2[256];
136 if (scanf("%s %s %d %d", pl1, pl2, &score1, &score2) != 4) {
140 if (player_map.count(pl1) == 0) {
141 fprintf(stderr, "Unknown player '%s'\n", pl1);
144 if (player_map.count(pl2) == 0) {
145 fprintf(stderr, "Unknown player '%s'\n", pl2);
149 scores[player_map[pl1]][player_map[pl2]] = score1;
150 scores[player_map[pl2]][player_map[pl1]] = score2;
151 has_scores[player_map[pl1]][player_map[pl2]] = true;
152 has_scores[player_map[pl2]][player_map[pl1]] = true;
155 int placements[MAX_PLAYERS][MAX_PLAYERS];
156 for (int i = 0; i < num_players; ++i) {
157 for (int j = 0; j < num_players; ++j) {
158 placements[i][j] = 0;
162 for (int i = 0; i < trials; ++i) {
163 // draw true strength for all players
164 Matrix<float, Dynamic, 1, 0, MAX_PLAYERS, 1> drawn_normals(num_players);
165 for (int p = 0; p < num_players; ++p) {
166 drawn_normals(p) = draw_gaussian(0.0f, 1.0f);
168 Matrix<float, Dynamic, 1, 0, MAX_PLAYERS, 1> drawn_ratings = ratings_cholesky * drawn_normals + ratings;
170 // draw the missing matches
171 for (int pl1 = 0; pl1 < num_players; ++pl1) {
172 for (int pl2 = pl1 + 1; pl2 < num_players; ++pl2) {
173 if (has_scores[pl1][pl2]) {
177 float mu = drawn_ratings(pl1) - drawn_ratings(pl2);
179 int score = lrintf(draw_gaussian(mu, match_stddev));
180 scores[pl1][pl2] = score;
181 scores[pl2][pl1] = -score;
185 // sum up the points and margin for each player
186 player stats[MAX_PLAYERS];
187 for (int pl1 = 0; pl1 < num_players; ++pl1) {
188 stats[pl1].player_index = pl1;
189 stats[pl1].points = 0;
190 stats[pl1].margin = 0;
191 for (int pl2 = 0; pl2 < num_players; ++pl2) {
195 stats[pl1].margin += scores[pl1][pl2];
196 stats[pl1].margin -= scores[pl2][pl1];
197 if (scores[pl1][pl2] > scores[pl2][pl1]) {
198 stats[pl1].points += 2;
199 } else if (scores[pl1][pl2] == scores[pl2][pl1]) {
205 // order by points and then margin
206 sort(stats, stats + num_players, highest_ranking());
207 for (int j = 0; j < num_players; ++j) {
208 ++placements[stats[j].player_index][j];
212 for (int i = 0; i < num_players; ++i) {
213 printf("%-15s", players[i].c_str());
214 for (int j = 0; j < num_players; ++j) {
215 printf(" %5d", placements[i][j]);