Revert change to wrong branch.
[ccbs] / html / do-finish-tournament.pl
1 #! /usr/bin/perl
2
3 use ccbs;
4 use strict;
5 use warnings;
6
7 ccbs::admin_only();
8
9 my $dbh = ccbs::db_connect();
10 my $cgi = new CGI;
11
12 $dbh->{AutoCommit} = 0;
13
14 my $tournament = $cgi->param('tournament');
15 my %already_ordered = ();
16 my $ranking = 1;
17 my $points = 100;
18
19 # Find all last rounds with only one group per round
20 my $srounds = ccbs::db_fetch_all($dbh, 'SELECT round FROM groups WHERE tournament=? GROUP BY round HAVING COUNT(*) = 1 ORDER BY round DESC', $tournament);
21
22 my $last_sround;
23 for my $sr (@$srounds) {
24         # only accept strict ordering
25         last if (defined($last_sround) && $sr->{'round'} != $last_sround - 1);
26         $last_sround = $sr->{'round'};
27
28         # Grab the highscore list from this round
29         my $scores = ccbs::db_fetch_all($dbh, 'SELECT player,SUM(score) AS score FROM scores WHERE tournament=? AND round=? GROUP BY parallel,player ORDER BY SUM(score) DESC',
30                 $tournament, $sr->{'round'});
31         for my $s (@$scores) {
32                 next if ($already_ordered{$s->{'player'}});
33                 $dbh->do('INSERT INTO tournamentrankings (tournament, ranking, player, points) VALUES (?,?,?,?)',
34                         undef, $tournament, $ranking, $s->{'player'}, points_for_place($ranking));
35                 $ranking++;
36                 $already_ordered{$s->{'player'}} = 1;
37         }
38 }
39
40 # This should never happen
41 if (!defined($last_sround)) {
42         ccbs::user_error("Forsøk på å avslutte en turnering med flere grupper aktive.");
43 }
44
45 # Grab all the remaining groups; we order by the simple criteria:
46 # 1. If player A has gone to group X and player B hasn't, player A is higher.
47 # 2. If player A has a higher ranking in his/her group than player B, player A is higher.
48 # 3. If player A has higher max score than player B, player A is higher.
49
50 # Basically, #2 makes this impossible to achieve in pure SQL. We just have
51 # to fetch one and one group and make the best out of it. Fetch out all the
52 # parallels (in sorted order) and grab all players in turn.
53
54 my $qscores = $dbh->prepare('SELECT parallel,player,SUM(score) AS sum_score,MAX(score) AS max_score FROM scores WHERE tournament=? AND round=? GROUP BY parallel,player ORDER BY SUM(score) DESC');
55 for my $r (reverse (1..($last_sround-1))) {
56         my @parallels = ();
57         my $num_players = 0;
58         
59         $qscores->execute($tournament, $r);
60
61         while (my $ref = $qscores->fetchrow_hashref()) {
62                 my $p = $ref->{'parallel'};
63                 if (!defined($parallels[$p])) {
64                         $parallels[$p] = [];
65                 }
66
67                 push @{$parallels[$p]}, {%$ref};
68                 $num_players++;
69         }
70
71         my $place = 0;
72
73         # Grab players from the top until nobody's left
74         while ($num_players > 0) {
75                 my @players_this_place = ();
76                 for my $p (@parallels) {
77                         next if (!defined($p->[$place]));
78                         $num_players--;
79                         next if ($already_ordered{$p->[$place]->{'player'}});
80
81                         push @players_this_place, $p->[$place];
82                 }
83
84                 @players_this_place = sort { $b->{'max_score'} <=> $a->{'max_score'} } @players_this_place;
85
86                 for my $s (@players_this_place) {
87                         $dbh->do('INSERT INTO tournamentrankings (tournament, ranking, player, points) VALUES (?,?,?,?)',
88                                 undef, $tournament, $ranking, $s->{'player'}, points_for_place($ranking));
89                         $ranking++;
90                         $already_ordered{$s->{'player'}} = 1;
91                 }
92
93                 $place++;
94         }
95 }
96
97 $dbh->commit;
98 $dbh->disconnect;
99
100 ccbs::print_see_other('show-tournament.pl?id=' . $tournament);
101
102 # gives the usual 100, 91, 83, 76. 65, 61, ... series
103 sub points_for_place {
104         my $n = shift;
105         if ($n <= 10) {
106                 return 110 - (21/2) * $n + (1/2) * $n * $n;
107         } elsif ($n <= 65) {
108                 return 65 - $n;
109         } else {
110                 return 0;
111         }
112 }