]> mj.ucw.cz Git - eval.git/blob - bin/mo-score
New table layout by Bim.
[eval.git] / bin / mo-score
1 #!/usr/bin/perl
2
3 $debug = 0;
4 $detail = 0;
5 $html = 0;
6 $tex = 0;
7 $extras = 0;
8 $alt = 0;
9 $usage = "Usage: mo-score [--detail] [--alt] [--extras] [--html] [--tex] <task1> <task2> ...";
10 while (($arg = $ARGV[0]) =~ /^--([a-z]+)$/) {
11         shift @ARGV;
12         $var = "\$$1";
13         if (!eval "defined $var") { die $usage; }
14         eval "$var = 1;";
15 }
16 @ARGV || die $usage;
17
18 @tasks = @ARGV;
19
20 print STDERR "Scanning contestants... ";
21 open (CT, "bin/mo-get-users --full |") || die "Cannot get list of contestants";
22 while (<CT>) {
23         chomp;
24         ($u,$f) = split /\t/;
25         ($u eq "somebody") && next;
26         $users{$u}=$f;
27 }
28 close CT;
29 print STDERR 0+keys %users, "\n";
30
31 print STDERR "Scanning exceptions... ";
32 if ($extras && open (EX, "exceptions")) {
33         while (<EX>) {
34                 chomp;
35                 (/^$/ || /^#/) && next;
36                 @a = split /\s+/;
37                 $u = shift @a;
38                 defined $users{$u} || die "Unknown user $u";
39                 while (@a) { $extra{$u} += shift @a; }
40         }
41         close EX;
42         print STDERR "OK\n";
43 } else { print STDERR "none\n"; }
44
45 print STDERR "Scanning task results... ";
46 $need_tasks = join("|", @ARGV);
47 %messages = ();
48 %error_codes = ();
49 foreach $u (keys %users) {
50         opendir (D, "testing/$u") or next;
51         foreach $t (readdir(D)) {
52                 $t =~ /^\./ && next;
53                 $t =~ /$need_tasks/ || next;
54                 $known_tasks{$t} = 1;
55                 $tt = "testing/$u/$t/points" . ($alt ? ".alt" : "");
56                 -f $tt || next;
57                 print STDERR "$u/$t ";
58                 open (X, $tt) || die "Unable to open $tt";
59                 while (<X>) {
60                         chomp;
61                         /^(\S+) (-?\d+)\s*(.*)/ || die "Parse error: $_";
62                         $ttest = $1;
63                         $tpts = $2;
64                         $trem = $3;
65                         $ttest =~ s/[^0-9]//g;
66                         $known_tests{$t}{$ttest} = 1;
67                         $results{$u}{$t}{$ttest} = $tpts;
68                         $remarks{$u}{$t}{$ttest} = $trem;
69                         $cmt = $tpts;
70                         if ($tpts == 0) {
71                                 if ($trem =~ /^Compile /) { $cmt = "CE"; }
72                                 elsif ($trem =~ /^Time limit exceeded/) { $cmt = "TO"; }
73                                 elsif ($trem =~ /^Exited with error /) { $cmt = "RE"; }
74                                 elsif ($trem =~ /^Caught fatal signal /) { $cmt = "SG"; }
75                                 elsif ($trem =~ /^([A-Za-z])\S*\s+([A-Za-z])/) {
76                                         ($cmt = "$1$2") =~ tr/a-z/A-Z/;
77                                 }
78                                 elsif ($trem =~ /^Wrong answer/) { $cmt = "WA"; }
79                                 if (!defined $messages{$trem}) {
80                                         $messages{$trem} = $cmt;
81                                         if (!defined $error_codes{$cmt}) {
82                                                 $error_codes{$cmt} = $trem;
83                                         } else {
84                                                 $error_codes{$cmt} .= ", $trem";
85                                         }
86                                 }
87                         }
88                         $comment{$u}{$t}{$ttest} = $cmt;
89                         $total{$u}{$t} += $tpts;
90                 }
91                 close X;
92         }
93         closedir D;
94 }
95 print STDERR "OK\n";
96
97 print STDERR "Creating table template... ";
98 @header = ("Rank","User","Name");
99 @body = ('','$u','$users{$u}');
100 @bodysums = ();
101 @footer = ('"Total"','','');
102 if (keys %extra) {
103         push @header, "Extra";
104         push @body, '$extra{$u}';
105         $col = 0+@footer;
106         push @bodysums, $col;
107         push @footer, "sum($col)";
108 }
109 foreach $t (@ARGV) {
110         defined $known_tasks{$t} || die "Unknown task $t";
111         push @header, substr($t, 0, 4);
112         push @body, "(\$xx = \$total{\$u}{'$t'}) > 0 ? \$xx : 0";
113         $col = 0+@footer;
114         push @footer, "sum($col)";
115         push @bodysums, $col;
116         if ($detail) {
117                 foreach $s (sort { $a <=> $b } keys %{$known_tests{$t}}) {
118                         push @header, "$s";
119                         push @body, "\$comment{\$u}{'$t'}{'$s'}";
120                         $col = 0+@footer;
121                         push @footer, "sum($col)";
122                 }
123         }
124 }
125 push @header, "Total";
126 push @body, join('+', map { $_ = "\$$_" } @bodysums);
127 $col = 0+@footer;
128 push @footer, "sum($col)";
129 print STDERR "OK\n";
130
131 print STDERR "h: ", join(':',@header), "\n" if $debug;
132 print STDERR "b: ", join(':',@body), "\n" if $debug;
133 print STDERR "f: ", join(':',@footer), "\n" if $debug;
134
135 print STDERR "Filling in results... ";
136 @table = ();
137 foreach $u (keys %users) {
138         $row = [];
139         foreach my $c (@body) {
140                 $c =~ s/\$(\d+)/\$\$row[$1]/g;
141                 $x = eval $c;
142                 push @$row, (defined $x ? $x : '-');
143         }
144         print STDERR "row: ", join(':',@$row), "\n" if $debug;
145         push @table, $row;
146 }
147 print STDERR "OK\n";
148
149 print STDERR "Sorting... ";
150 $sortcol = @{$table[0]} - 1;
151 $namecol = 2;
152 @table = sort {
153         my $p, $an, $bn;
154         $p = $$b[$sortcol] <=> $$a[$sortcol];
155         ($an = $$a[$namecol]) =~ s/(\S+)\s+(\S+)/$2 $1/;
156         ($bn = $$b[$namecol]) =~ s/(\S+)\s+(\S+)/$2 $1/;
157         $p ? $p : ($an cmp $bn);
158 } @table;
159 $i=0;
160 while ($i < @table) {
161         $j = $i;
162         while ($i < @table && ${$table[$i]}[$sortcol] == ${$table[$j]}[$sortcol]) {
163                 $i++;
164         }
165         if ($i == $j+1) {
166                 ${table[$j]}[0] = "$i.";
167         } else {
168                 ${table[$j]}[0] = $j+1 . ".-" . $i . ".";
169                 $j++;
170                 while ($j < $i) { ${table[$j++]}[0] = ""; };
171         }
172 }
173 print STDERR "OK\n";
174
175 print STDERR "Attaching headers and footers... ";
176 sub sum { my $col=shift @_; my $t=0; foreach my $z (0..@table-1) { $t += ${$table[$z]}[$col]; } $t; }
177 map { $_ = eval $_; } @footer;
178 push @table, \@footer;
179 unshift @table, \@header;
180 print STDERR "OK\n";
181
182 if ($debug) {
183         foreach $r (@table) { print join(':',@$r), "\n"; }
184 } elsif ($html) {
185         print '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html40/strict.dtd">', "\n";
186         print "<HTML><HEAD><TITLE>Rank list</TITLE></HEAD><BODY>\n";
187         print "<H1>Rank list</H1>\n";
188
189         my @perm;
190         &printHtmlHeader(\@perm);
191         print "<tbody>";
192         
193         foreach $r (@table[1..($#table - 1)]) {
194                 &printHtmlRow(@{$r}[@perm]);
195         }
196
197         print "<tbody>";
198         &printHtmlRow(@{$table[$#table]}[@perm]);
199
200         print "</TABLE>\n";
201         if ($detail) {
202                 print "<H2>Error codes</H2><UL>\n";
203                 foreach $r (sort keys %error_codes) { print "<LI>$r: $error_codes{$r}\n"; }
204                 print "</UL>\n";
205         }
206         print "</BODY></HTML>\n";
207 } elsif ($tex) {
208         print "\\error{TeX output not supported yet!}\n";
209 } else {
210         foreach $r (@table) { print join("\t",@$r), "\n"; }
211         print "\n";
212         foreach $r (sort keys %error_codes) { print "$r: $error_codes{$r}\n"; }
213 }
214
215
216 sub printHtmlRow {
217         print "<TR>", join('',map {
218                 if ($hdr) { $_ = "<TH>$_"; }
219                 else { $_ = "<TD align=" . (/^[0-9A-Z-]+$/ ? "right" : "left") . (length($_) > 14 ? " width=150" : "") . ">$_"; }
220         } @_), "\n";
221 }
222
223
224 sub printHtmlHeader {
225
226   my ($perm) = @_;
227
228    my $colspec = "<colgroup span=3>";
229    my $hdr1;
230    my $hdr2;
231
232    @$perm = (0, 1, 2);
233    my $p = 3;
234
235    if ($detail) {
236      $hdr1 = "<th rowspan=2>Rank<th rowspan=2>User<th rowspan=2>Name";
237      for my $task (@tasks) {
238
239         my $nSub = scalar(keys %{$known_tests{$task}});
240
241         $p++;
242         map { push @$perm, $p++ } (1..$nSub);
243         push @$perm, $p - $nSub - 1;
244         
245         $colspec .= "<colgroup span='" . $nSub . "'>\n";
246         $colspec .= "<colgroup span='1'>\n";
247         $hdr1 .= "<th colspan='" . ($nSub + 1) . "' style='border-bottom:1px solid black;'>$task";
248         $hdr2 .= join("", map { "<th>$_" } sort {$a <=> $b} keys %{$known_tests{$task}});
249         $hdr2 .= "<th>Total";
250      }
251    
252      $hdr1 .= "<th rowspan='2'>Total";
253      
254    } else {  ## no detail
255    
256      $hdr1 = "<th>Rank<th>User<th>Name";
257
258      for my $task (@tasks) {
259         push @$perm, $p++;
260         $hdr1 .= "<th>$task";
261      }
262      $hdr1 .= "<th>Total";
263      $colspec .= "<colgroup span='" . scalar (@tasks) . "'>";
264    }
265
266    push @$perm, $p++;
267    
268    print "<TABLE rules=groups frame=all border='1' cellpadding='2'>\n";
269    print "$colspec<colgroup span='1'>\n";
270    print "<tr>$hdr1</tr>\n";
271    print "<tr>$hdr2</tr>\n" if $detail;
272   
273 }