]> git.sesse.net Git - wloh/blob - mcwordfeud.cpp
Take standard deviation of estimated mu into account when doing MC simulation.
[wloh] / mcwordfeud.cpp
1 #include <stdio.h>
2 #include <math.h>
3 #include <string.h>
4 #include <stdlib.h>
5
6 #include <map>
7 #include <vector>
8 #include <string>
9 #include <algorithm>
10
11 #include "ziggurat.hpp"
12
13 using namespace std;
14
15 #define MAX_PLAYERS 16
16
17 float match_variance = 70.0f * 70.0f;
18
19 struct player {
20         int player_index;
21         int points, margin;
22 };
23 struct highest_ranking {
24 public:
25         bool operator() (const player &a, const player &b) const {
26                 if (a.points != b.points) {
27                         return a.points > b.points;
28                 }
29                 return a.margin > b.margin;
30         }
31 };
32
33 #if 0
34 float draw_unit()
35 {
36         return rand() * (1.0f / RAND_MAX);
37 }
38
39 // FIXME: replace rejection method with a better method! this one can only ever go to [-5z, +5z]
40 // and is very slow.
41 float draw_gaussian(float stddev)
42 {
43         for ( ;; ) {
44                 float z = draw_unit() * 10.0f - 5.0f;
45                 float y = draw_unit();
46                 if (y < exp(-z*z)) {
47                         return z * stddev;
48                 }
49         }       
50 }
51 #else
52 float draw_gaussian(float mu, float stddev)
53 {
54         static bool inited = false;
55         static long unsigned seed = time(NULL);
56         static int kn[128];
57         static float fn[128], wn[128];
58         if (!inited) {
59                 r4_nor_setup(kn, fn, wn);
60                 inited = true;
61         }
62
63         return r4_nor(&seed, kn, fn, wn) * stddev + mu;
64 }
65 #endif
66
67 int main(int argc, char **argv)
68 {
69         int trials = atoi(argv[1]);
70         float match_stddev;
71
72         if (scanf("%f", &match_stddev) != 1) {
73                 fprintf(stderr, "Could't read match stddev\n");
74                 exit(1);
75         }
76
77         match_variance = match_stddev * match_stddev;
78
79         int num_players;
80         if (scanf("%d", &num_players) != 1) {
81                 fprintf(stderr, "Could't read number of players\n");
82                 exit(1);
83         }
84
85         if (num_players > MAX_PLAYERS) {
86                 fprintf(stderr, "Max %d players supported\n", MAX_PLAYERS);
87                 exit(1);
88         }
89
90         vector<string> players;
91         map<string, int> player_map;
92         float ratings[MAX_PLAYERS];
93         float ratings_variance[MAX_PLAYERS];
94         bool has_scores[MAX_PLAYERS][MAX_PLAYERS];
95         for (int pl1 = 0; pl1 < num_players; ++pl1) {
96                 for (int pl2 = 0; pl2 < num_players; ++pl2) {
97                         has_scores[pl1][pl2] = false;
98                 }
99         }
100
101         int scores[MAX_PLAYERS][MAX_PLAYERS];
102         for (int i = 0; i < num_players; ++i) {
103                 char buf[256];
104                 float rating, rating_stddev;
105                 int ret = scanf("%s %f %f", buf, &rating, &rating_stddev);
106                 if (ret < 1) {
107                         fprintf(stderr, "Couldn't read player %d\n", i);
108                         exit(1);
109                 }
110                 if (ret < 2) {
111                         rating = 1500.0f;
112                 }
113                 if (ret < 3) {
114                         rating_stddev = 0.0f;
115                 }
116
117                 players.push_back(buf);
118                 player_map[buf] = i;
119                 ratings[i] = rating;
120                 ratings_variance[i] = rating_stddev * rating_stddev;
121         }
122
123         for ( ;; ) {
124                 char pl1[256], pl2[256];
125                 int score1, score2;
126
127                 if (scanf("%s %s %d %d", pl1, pl2, &score1, &score2) != 4) {
128                         break;
129                 }
130
131                 if (player_map.count(pl1) == 0) {
132                         fprintf(stderr, "Unknown player '%s'\n", pl1);
133                         exit(1);
134                 }
135                 if (player_map.count(pl2) == 0) {
136                         fprintf(stderr, "Unknown player '%s'\n", pl2);
137                         exit(1);
138                 }
139
140                 scores[player_map[pl1]][player_map[pl2]] = score1;
141                 scores[player_map[pl2]][player_map[pl1]] = score2;
142                 has_scores[player_map[pl1]][player_map[pl2]] = true;
143                 has_scores[player_map[pl2]][player_map[pl1]] = true;
144         }
145
146         int placements[MAX_PLAYERS][MAX_PLAYERS];
147         for (int i = 0; i < num_players; ++i) {
148                 for (int j = 0; j < num_players; ++j) {
149                         placements[i][j] = 0;
150                 }
151         }
152
153         for (int i = 0; i < trials; ++i) {
154                 // draw the missing matches
155                 for (int pl1 = 0; pl1 < num_players; ++pl1) {
156                         for (int pl2 = pl1 + 1; pl2 < num_players; ++pl2) {
157                                 if (has_scores[pl1][pl2]) {
158                                         continue;
159                                 }
160
161                                 float mu = ratings[pl1] - ratings[pl2];
162                                 float stddev = sqrt(match_variance + ratings_variance[pl1] + ratings_variance[pl2]);
163                                 
164                                 int score = lrintf(draw_gaussian(mu, stddev));
165                                 scores[pl1][pl2] = score;
166                                 scores[pl2][pl1] = -score;
167                         }
168                 }
169
170                 // sum up the points and margin for each player
171                 player stats[MAX_PLAYERS];
172                 for (int pl1 = 0; pl1 < num_players; ++pl1) {
173                         stats[pl1].player_index = pl1;
174                         stats[pl1].points = 0;
175                         stats[pl1].margin = 0;
176                         for (int pl2 = 0; pl2 < num_players; ++pl2) {
177                                 if (pl1 == pl2) {
178                                         continue;
179                                 }
180                                 stats[pl1].margin += scores[pl1][pl2];
181                                 stats[pl1].margin -= scores[pl2][pl1];
182                                 if (scores[pl1][pl2] > scores[pl2][pl1]) {
183                                         stats[pl1].points += 2;
184                                 } else if (scores[pl1][pl2] == scores[pl2][pl1]) {
185                                         stats[pl1].points++;
186                                 }
187                         }
188                 }
189
190                 // order by points and then margin
191                 sort(stats, stats + num_players, highest_ranking());
192                 for (int j = 0; j < num_players; ++j) {
193                         ++placements[stats[j].player_index][j];
194                 }
195         }
196
197         for (int i = 0; i < num_players; ++i) {
198                 printf("%-15s", players[i].c_str());
199                 for (int j = 0; j < num_players; ++j) {
200                         printf(" %5d", placements[i][j]);
201                 }
202                 printf("\n");
203         }
204 }