]> git.sesse.net Git - wloh/blob - www/rating.pl
Properly take locale into account when calculating division averages.
[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 require '../common.pm';
15
16 my $dbh = DBI->connect($config::local_connstr, $config::local_username, $config::local_password)
17         or die "connect: " . $DBI::errstr;
18 $dbh->{AutoCommit} = 0;
19 $dbh->{RaiseError} = 1;
20
21 binmode STDOUT, ':utf8';
22
23 my $cgi = CGI->new;
24 my $locale = wloh_common::get_locale($cgi);
25
26 my $aux_parms = wloh_common::get_auxillary_parameters($dbh, $locale);
27 my $match_stddev = $aux_parms->{'score_stddev'} * sqrt(2.0);
28
29 print CGI->header(-type=>'text/html; charset=utf-8', -expires=>'+5m');
30 POSIX::setlocale(&POSIX::LC_ALL, 'nb_NO.UTF-8');
31
32 print <<"EOF";
33 <?xml version="1.0" encoding="UTF-8" ?>
34 <!DOCTYPE
35   html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
36   "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
37 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="no">
38   <head>
39     <title>WLoH-rating</title>
40     <link rel="stylesheet" href="style" type="text/css" />
41   </head>
42   <body>
43 EOF
44
45 wloh_common::print_navbar($cgi, $dbh, $locale);
46
47 printf <<"EOF", $aux_parms->{'rating_prior_stddev'}, $match_stddev;
48     <h1>WLoH-rating</h1>
49
50     <p><em>Dette er et hobbyprosjekt fra tredjepart, og ikke en offisiell del av
51       <a href="http://wordfeud.aasmul.net/">Wordfeud Leage of Honour</a>.</em></p>
52
53     <p>Ratingen er dog basert på spilledata fra WLoH (takk til Lobotommy
54       for tilgang!), og oppdateres
55       hver hele time. Den er fullstendig uoffisiell, og har ingen innflytelse
56       på WLoH, men brukes for å estimere vinnersannsynligheter i
57       <a href="index">sannsynlighetsberegningen</a>.</p>
58
59     <p>Modellen kan endre seg når som helst når jeg føler for det :-)
60       Ikke ta ratingen alt for alvorlig, selv om den er basert på
61       relativt fornuftige matematiske modeller. Husk at all statistikk
62       sier mer om fortiden enn om framtiden.</p>
63
64     <h2>Modellparametre</h2>
65
66     <p>For de som vet litt om slikt. Det finnes også en lengre, mer detaljert
67       <a href="ratings-explained">forklaring</a> beregnet på ikke-matematikere.</p>
68
69     <ul>
70       <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: $aux_parms->{num_iterations}.</li>
71       <li>Rimelighetfunksjon, prior: Normalfordeling med µ=500, &sigma;=%.1f (est.)</li>
72       <li>Rimelighetfunksjon, per kamp: Normalfordeling med µ=(score1 - score2), &sigma;=%.1f (est.)</li>
73       <li>Vekting: Inneværende sesong samt de tre siste vektes fullt ut
74         (likt med prior). Deretter eksponentielt synkende vekting, med
75         halveringstid på tre sesonger. Spill som er registrert med
76         0-0, 150-0, 0-150 eller 150-150 ignoreres.</li>
77     </ul>
78
79     <h2>Divisjonsoversikt</h2>
80
81     <table>
82       <tr>
83         <th>Div.</th>
84         <th>Snitt</th>
85         <th>Std.avvik</th>
86       </tr>
87 EOF
88
89 my $season = wloh_common::get_max_season($dbh, $locale);
90
91 # Pick up all the subdivisions' ratings.
92 my %subdivision_ratings = ();
93 my $q = $dbh->prepare('SELECT divisjon, avdeling, serie_id, AVG(rating) AS avg_rating FROM ratings NATURAL JOIN siste_divisjon NATURAL JOIN spiller_kultur WHERE kultur=? AND sesong=? GROUP BY divisjon, avdeling, serie_id ORDER BY divisjon, avdeling');
94 $q->execute($locale, $season);
95
96 while (my $ref = $q->fetchrow_hashref) {
97         my $division = $ref->{'divisjon'};
98         my $rating = $ref->{'avg_rating'};
99         my $id = $ref->{'serie_id'};
100
101         push @{$subdivision_ratings{$division}}, [ $id, $rating ];
102 }
103
104 $q = $dbh->prepare('SELECT divisjon,AVG(rating) AS avg_rating,STDDEV(rating) AS stddev_rating FROM ratings NATURAL JOIN siste_divisjon NATURAL JOIN spiller_kultur WHERE kultur=? AND sesong=? GROUP BY divisjon ORDER BY divisjon');
105 $q->execute($locale, $season);
106
107 my $i = 0;
108 while (my $ref = $q->fetchrow_hashref) {
109         if (++$i % 2 == 0) {
110                 print "      <tr class=\"odd\">\n";
111         } else {
112                 print "      <tr class=\"even\">\n";
113         }
114         printf "        <th>%d.</th>\n", $ref->{'divisjon'};
115         printf "        <td class=\"num\">%.1f</td>\n", $ref->{'avg_rating'};
116         printf "        <td class=\"num\">%.1f</td>\n", $ref->{'stddev_rating'};
117
118         for my $arr (@{$subdivision_ratings{$ref->{'divisjon'}}}) {
119                 my ($id, $rating) = @$arr;
120                 printf "        <td class=\"num\"><a href=\"http://wordfeud.aasmul.net/serie-%d\">%.1f</a></td>\n", $id, $rating;
121         }
122         print "      </tr>\n";
123 }
124
125 print <<"EOF";
126     </table>
127
128   <h2>Rankingliste</h2>
129
130   <table>
131     <tr>
132       <th></th>
133       <th>Nick</th>
134       <th>Rating</th>
135       <th>Std.avvik</th>
136       <th>Sist sett</th>
137     </tr>
138 EOF
139
140 $q = $dbh->prepare('
141 SELECT *
142 FROM ratings
143   NATURAL JOIN kanonisk_navn
144   NATURAL JOIN siste_divisjon
145   NATURAL JOIN spiller_kultur
146 WHERE kultur=?
147 ORDER BY rating DESC');
148 $q->execute($locale);
149
150 $i = 0;
151 while (my $ref = $q->fetchrow_hashref) {
152         if (++$i % 2 == 0) {
153                 print "    <tr class=\"odd\">\n";
154         } else {
155                 print "    <tr class=\"even\">\n";
156         }
157         printf "      <th>%d.</th>\n", $i;
158         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'}));
159         printf "      <td class=\"num\">%.1f</td>\n", $ref->{'rating'};
160         printf "      <td class=\"num\">%.1f</td>\n", $ref->{'rating_stddev'};
161         printf "      <td><a href=\"http://wordfeud.aasmul.net/serie-%d\">%s</a></td>\n", $ref->{'serie_id'}, $ref->{'serie_navn'};
162         print "    </tr>\n";
163 }
164 print "    </table>\n";
165
166 wloh_common::output_last_sync($dbh);
167
168 print <<"EOF";
169   </body>
170 </html>
171 EOF
172
173 $dbh->rollback;