]> git.sesse.net Git - wloh/blob - www/rating.pl
Show rating standard deviation.
[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>Modellen kan endre seg når som helst når jeg føler for det :-)
53       Ikke ta ratingen alt for alvorlig, selv om den er basert på
54       relativt fornuftige matematiske modeller. Husk at all statistikk
55       sier mer om fortiden enn om framtiden.</p>
56
57     <h2>Modellparametre</h2>
58
59     <p>For de som vet litt om slikt. Det finnes også en lengre, mer detaljert
60       <a href="/ratings-explained">forklaring</a> beregnet på ikke-matematikere.</p>
61
62     <ul>
63       <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>
64       <li>Rimelighetfunksjon, prior: Normalfordeling med µ=1500, &sigma;=%.1f (est.)</li>
65       <li>Rimelighetfunksjon, per kamp: Normalfordeling med µ=(score1 - score2), &sigma;=%.1f (est.)</li>
66       <li>Vekting: Inneværende sesong samt de tre siste vektes fullt ut
67         (likt med prior). Deretter eksponentielt synkende vekting, med
68         halveringstid på tre sesonger. Spill som er registrert med
69         150-0, 0-150 eller 150-150 ignoreres.</li>
70     </ul>
71
72     <h2>Divisjonsoversikt</h2>
73
74     <table>
75       <tr>
76         <th>Div.</th>
77         <th>Snitt</th>
78         <th>Std.avvik</th>
79       </tr>
80 EOF
81
82 $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');
83 $q->execute;
84
85 my $i = 0;
86 while (my $ref = $q->fetchrow_hashref) {
87         if (++$i % 2 == 0) {
88                 print "      <tr class=\"odd\">\n";
89         } else {
90                 print "      <tr class=\"even\">\n";
91         }
92         printf "        <th>%d.</th>\n", $ref->{'divisjon'};
93         printf "        <td class=\"num\">%.1f</td>\n", $ref->{'avg_rating'};
94         printf "        <td class=\"num\">%.1f</td>\n", $ref->{'stddev_rating'};
95         print "      </tr>\n";
96 }
97
98 print <<"EOF";
99     </table>
100
101   <h2>Rankingliste</h2>
102
103   <table>
104     <tr>
105       <th></th>
106       <th>Nick</th>
107       <th>Rating</th>
108       <th>Std.avvik</th>
109       <th>Sist sett</th>
110     </tr>
111 EOF
112
113 $q = $dbh->prepare('
114 SELECT *
115 FROM ratings
116   NATURAL JOIN kanonisk_navn
117   NATURAL JOIN siste_divisjon
118 ORDER BY rating DESC');
119 $q->execute;
120
121 $i = 0;
122 while (my $ref = $q->fetchrow_hashref) {
123         if (++$i % 2 == 0) {
124                 print "    <tr class=\"odd\">\n";
125         } else {
126                 print "    <tr class=\"even\">\n";
127         }
128         printf "      <th>%d.</th>\n", $i;
129         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'}));
130         printf "      <td class=\"num\">%.1f</td>\n", $ref->{'rating'};
131         printf "      <td class=\"num\">%.1f</td>\n", $ref->{'rating_stddev'};
132         printf "      <td><a href=\"http://wordfeud.aasmul.net/serie-%d\">%s</a></td>\n", $ref->{'serie_id'}, $ref->{'serie_navn'};
133         print "    </tr>\n";
134 }
135
136 print <<"EOF";
137     </table>
138   </body>
139 </html>
140 EOF
141
142 $match_stddev = $params{-2} * sqrt(2.0);
143
144 $dbh->rollback;