]> git.sesse.net Git - wloh/blob - www/rating.pl
Add a "ratings explained" page.
[wloh] / www / rating.pl
1 #! /usr/bin/perl
2 use strict;
3 use warnings;
4 no warnings qw(once);
5 use CGI;
6 use CGI::Carp qw( fatalsToBrowser );
7 use DBI;
8 use Encode;
9 use POSIX;
10 use HTML::Entities;
11 use utf8;
12 use locale;
13 require '../config.pm';
14
15 my $dbh = DBI->connect($config::local_connstr, $config::local_username, $config::local_password)
16         or die "connect: " . $DBI::errstr;
17 $dbh->{AutoCommit} = 0;
18 $dbh->{RaiseError} = 1;
19
20 binmode STDOUT, ':utf8';
21
22 # Find auxillary parameters.
23 my %params = ();
24 my $q = $dbh->prepare('SELECT * FROM ratings WHERE id < 0');
25 $q->execute;
26 while (my $ref = $q->fetchrow_hashref) {
27         $params{$ref->{'id'}} = $ref->{'rating'};
28 }
29 my $match_stddev = $params{-2} * sqrt(2.0);
30
31 print CGI->header(-type=>'text/html; charset=utf-8', -expires=>'+5m');
32 POSIX::setlocale(&POSIX::LC_ALL, 'nb_NO.UTF-8');
33
34 printf <<"EOF", $params{-3}, $match_stddev;
35 <html>
36   <head>
37     <title>WLoH-rating</title>
38     <link rel="stylesheet" href="/style" type="text/css" />
39   </head>
40   <body>
41     <h1>WLoH-rating</h1>
42
43     <p><em>Dette er et hobbyprosjekt fra tredjepart, og ikke en offisiell del av
44       <a href="http://wordfeud.aasmul.net/">Wordfeud Leage of Honour</a>.</em></p>
45
46     <p>Ratingen er dog basert på spilledata fra WLoH (takk til Lobotommy
47       for tilgang!), og oppdateres
48       hver hele time. Den er fullstendig uoffisiell, og har ingen innflytelse
49       på WLoH, men brukes for å estimere vinnersannsynligheter i
50       <a href="/">sannsynlighetsberegningen</a>.</p>
51
52     <p>Vær obs på at det
53       er betydelig usikkerhetsmargin, spesielt for spillere som ikke
54       har spilt spesielt mange kamper.</p>
55
56     <p>Modellen kan endre seg når som helst når jeg føler for det :-)
57       Ikke ta ratingen alt for alvorlig, selv om den er basert på
58       relativt fornuftige matematiske modeller. Husk at all statistikk
59       sier mer om fortiden enn om framtiden.</p>
60
61     <h2>Modellparametre</h2>
62
63     <p>For de som vet litt om slikt. Det finnes også en lengre, mer detaljert
64       <a href="/ratings-explained">forklaring</a> beregnet på ikke-matematikere.</p>
65
66     <ul>
67       <li>MLE-basert modell med én skalar (styrke) per spiller og to globale skalarer (begge standardavvik, se under), løst med syklisk MM (minorization-maximization). Antall iterasjoner før konvergens: $params{-1}.</li>
68       <li>Rimelighetfunksjon, prior: Normalfordeling med µ=1500, &sigma;=%.1f (est.)</li>
69       <li>Rimelighetfunksjon, per kamp: Normalfordeling med µ=(score1 - score2), &sigma;=%.1f (est.)</li>
70       <li>Vekting: Inneværende sesong samt de tre siste vektes fullt ut
71         (likt med prior). Deretter eksponentielt synkende vekting, med
72         halveringstid på tre sesonger. Spill som er registrert med
73         150-0, 0-150 eller 150-150 ignoreres.</li>
74     </ul>
75
76     <h2>Divisjonsoversikt</h2>
77
78     <table>
79       <tr>
80         <th>Div.</th>
81         <th>Snitt</th>
82         <th>Std.avvik</th>
83       </tr>
84 EOF
85
86 $q = $dbh->prepare('SELECT divisjon,AVG(rating) AS avg_rating,STDDEV(rating) AS stddev_rating FROM ratings NATURAL JOIN siste_divisjon GROUP BY divisjon ORDER BY divisjon');
87 $q->execute;
88
89 my $i = 0;
90 while (my $ref = $q->fetchrow_hashref) {
91         if (++$i % 2 == 0) {
92                 print "      <tr class=\"odd\">\n";
93         } else {
94                 print "      <tr class=\"even\">\n";
95         }
96         printf "        <th>%d.</th>\n", $ref->{'divisjon'};
97         printf "        <td class=\"num\">%.1f</td>\n", $ref->{'avg_rating'};
98         printf "        <td class=\"num\">%.1f</td>\n", $ref->{'stddev_rating'};
99         print "      </tr>\n";
100 }
101
102 print <<"EOF";
103     </table>
104
105   <h2>Rankingliste</h2>
106
107   <table>
108     <tr>
109       <th></th>
110       <th>Nick</th>
111       <th>Rating</th>
112       <th>Sist sett</th>
113     </tr>
114 EOF
115
116 $q = $dbh->prepare('
117 SELECT *
118 FROM ratings
119   NATURAL JOIN kanonisk_navn
120   NATURAL JOIN siste_divisjon
121 ORDER BY rating DESC');
122 $q->execute;
123
124 $i = 0;
125 while (my $ref = $q->fetchrow_hashref) {
126         if (++$i % 2 == 0) {
127                 print "    <tr class=\"odd\">\n";
128         } else {
129                 print "    <tr class=\"even\">\n";
130         }
131         printf "      <th>%d.</th>\n", $i;
132         printf "      <td><a href=\"http://wordfeud.aasmul.net/bruker-%d\">%s</a></td>\n", $ref->{'id'}, HTML::Entities::encode_entities(Encode::decode_utf8($ref->{'navn'}));
133         printf "      <td class=\"num\">%.1f</td>\n", $ref->{'rating'};
134         printf "      <td><a href=\"http://wordfeud.aasmul.net/serie-%d\">%s</a></td>\n", $ref->{'serie_id'}, $ref->{'serie_navn'};
135         print "    </tr>\n";
136 }
137
138 print <<"EOF";
139     </table>
140   </body>
141 </html>
142 EOF
143
144 $match_stddev = $params{-2} * sqrt(2.0);
145
146 $dbh->rollback;