]> git.sesse.net Git - wloh/blob - mcwordfeud.cpp
Show rating standard deviation.
[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_stddev = 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
71         if (scanf("%f", &match_stddev) != 1) {
72                 fprintf(stderr, "Could't read match stddev\n");
73                 exit(1);
74         }
75
76         int num_players;
77         if (scanf("%d", &num_players) != 1) {
78                 fprintf(stderr, "Could't read number of players\n");
79                 exit(1);
80         }
81
82         if (num_players > MAX_PLAYERS) {
83                 fprintf(stderr, "Max %d players supported\n", MAX_PLAYERS);
84                 exit(1);
85         }
86
87         vector<string> players;
88         map<string, int> player_map;
89         float ratings[MAX_PLAYERS];
90         bool has_scores[MAX_PLAYERS][MAX_PLAYERS];
91         for (int pl1 = 0; pl1 < num_players; ++pl1) {
92                 for (int pl2 = 0; pl2 < num_players; ++pl2) {
93                         has_scores[pl1][pl2] = false;
94                 }
95         }
96
97         int scores[MAX_PLAYERS][MAX_PLAYERS];
98         for (int i = 0; i < num_players; ++i) {
99                 char buf[256];
100                 float rating;
101                 int ret = scanf("%s %f", buf, &rating);
102                 if (ret < 1) {
103                         fprintf(stderr, "Couldn't read player %d\n", i);
104                         exit(1);
105                 }
106                 if (ret != 2) {
107                         rating = 1500.0f;
108                 }
109
110                 players.push_back(buf);
111                 player_map[buf] = i;
112                 ratings[i] = rating;
113         }
114
115         for ( ;; ) {
116                 char pl1[256], pl2[256];
117                 int score1, score2;
118
119                 if (scanf("%s %s %d %d", pl1, pl2, &score1, &score2) != 4) {
120                         break;
121                 }
122
123                 if (player_map.count(pl1) == 0) {
124                         fprintf(stderr, "Unknown player '%s'\n", pl1);
125                         exit(1);
126                 }
127                 if (player_map.count(pl2) == 0) {
128                         fprintf(stderr, "Unknown player '%s'\n", pl2);
129                         exit(1);
130                 }
131
132                 scores[player_map[pl1]][player_map[pl2]] = score1;
133                 scores[player_map[pl2]][player_map[pl1]] = score2;
134                 has_scores[player_map[pl1]][player_map[pl2]] = true;
135                 has_scores[player_map[pl2]][player_map[pl1]] = true;
136         }
137
138         int placements[MAX_PLAYERS][MAX_PLAYERS];
139         for (int i = 0; i < num_players; ++i) {
140                 for (int j = 0; j < num_players; ++j) {
141                         placements[i][j] = 0;
142                 }
143         }
144
145         for (int i = 0; i < trials; ++i) {
146                 // draw the missing matches
147                 for (int pl1 = 0; pl1 < num_players; ++pl1) {
148                         for (int pl2 = pl1 + 1; pl2 < num_players; ++pl2) {
149                                 if (has_scores[pl1][pl2]) {
150                                         continue;
151                                 }
152
153                                 float mu = ratings[pl1] - ratings[pl2];
154                                 
155                                 int score = lrintf(draw_gaussian(mu, match_stddev));
156                                 scores[pl1][pl2] = score;
157                                 scores[pl2][pl1] = -score;
158                         }
159                 }
160
161                 // sum up the points and margin for each player
162                 player stats[MAX_PLAYERS];
163                 for (int pl1 = 0; pl1 < num_players; ++pl1) {
164                         stats[pl1].player_index = pl1;
165                         stats[pl1].points = 0;
166                         stats[pl1].margin = 0;
167                         for (int pl2 = 0; pl2 < num_players; ++pl2) {
168                                 if (pl1 == pl2) {
169                                         continue;
170                                 }
171                                 stats[pl1].margin += scores[pl1][pl2];
172                                 stats[pl1].margin -= scores[pl2][pl1];
173                                 if (scores[pl1][pl2] > scores[pl2][pl1]) {
174                                         stats[pl1].points += 2;
175                                 } else if (scores[pl1][pl2] == scores[pl2][pl1]) {
176                                         stats[pl1].points++;
177                                 }
178                         }
179                 }
180
181                 // order by points and then margin
182                 sort(stats, stats + num_players, highest_ranking());
183                 for (int j = 0; j < num_players; ++j) {
184                         ++placements[stats[j].player_index][j];
185                 }
186         }
187
188         for (int i = 0; i < num_players; ++i) {
189                 printf("%-15s", players[i].c_str());
190                 for (int j = 0; j < num_players; ++j) {
191                         printf(" %5d", placements[i][j]);
192                 }
193                 printf("\n");
194         }
195 }