3 # no warranty for this script
9 use FindBin; use lib $FindBin::Bin;
10 use WeaponEncounterProfile;
12 my ($statsfile) = @ARGV;
17 $stats = WeaponEncounterProfile->new($statsfile);
27 my @bigmatrix = map { [ @{$m->[$_]}, $v->[$_] ] } 0..$n-1;
32 # first: bring the highest value to the top
37 my $v = $bigmatrix[$j]->[$i];
38 if($v*$v > $bestval*$bestval)
44 die "lindep" if $best == -1;
47 ($bigmatrix[$i], $bigmatrix[$best]) = ($bigmatrix[$best], $bigmatrix[$i]);
52 my $r = $bigmatrix[$j]->[$i];
55 $bigmatrix[$j]->[$k] -= $bigmatrix[$i]->[$k] * $r / $bestval;
61 for my $i(reverse 0..$n-1)
63 my $bestval = $bigmatrix[$i]->[$i];
66 my $r = $bigmatrix[$j]->[$i];
69 $bigmatrix[$j]->[$k] -= $bigmatrix[$i]->[$k] * $r / $bestval;
74 # 3. Read off solutions
75 return map { $bigmatrix[$_]->[$n] / $bigmatrix[$_]->[$_] } 0..($n-1);
78 sub SolveBestSquares($$)
93 my $weight = $w->[$i]->[$j];
94 $num += $weight * $d->[$i]->[$j];
97 push @result, $num / $denom;
102 # build linear equation system
104 my @matrix = map { [ map { 0 } 1..$n ] } 1..$n;
105 my @vector = map { 0 } 1..$n;
116 $matrix[$z][$i] += $w->[$i]->[$z];
117 $matrix[$z][$z] -= $w->[$i]->[$z];
118 $vector[$z] += $w->[$i]->[$z] * $d->[$i]->[$z];
122 return LinSolve(\@matrix, \@vector);
129 while(my ($k, $v) = each %$matrix)
131 while(my ($k2, $v2) = each %$v)
139 delete $allweps{0}; # ignore the tuba
140 my @allweps = keys %allweps;
143 my @dmatrix = map { [ map { 0 } @allweps ] } @allweps;
144 my @wmatrix = map { [ map { 0 } @allweps ] } @allweps;
146 for my $i(0..@allweps - 1)
148 my $attackweapon = $allweps[$i];
151 for my $j(0..@allweps - 1)
153 my $defendweapon = $allweps[$j];
154 next if $attackweapon eq $defendweapon;
155 my $win = ($matrix->{$attackweapon}{$defendweapon} || 0);
156 my $lose = ($matrix->{$defendweapon}{$attackweapon} || 0);
157 my $c = ($win + $lose);
160 my $w = 1 - 1/($c * 0.1 + 1);
162 $dmatrix[$i][$j] = $p - (1 - $p); # antisymmetric
163 $wmatrix[$i][$j] = $w; # symmetric
170 @val = SolveBestSquares(\@dmatrix, \@wmatrix);
175 @val = map { undef } @allweps;
178 for my $i(0..@allweps - 1)
180 my $attackweapon = $allweps[$i];
181 $values{$attackweapon} = $val[$i];
188 my ($event, @data) = @_;
189 if($event eq 'start')
192 elsif($event eq 'startmatrix')
194 my ($addr, $type, $map, @columns) = @data;
198 print "For server $addr type $type map $map:\n";
200 elsif($event eq 'startrow')
202 my ($row, $val) = @data;
203 printf " %-30s %8s |", $stats->weaponid_to_name($row), defined $val ? sprintf("%8.5f", $val) : "N/A";
205 elsif($event eq 'cell')
207 my ($win, $lose, $p) = @data;
218 printf " %+6.3f", $p;
221 elsif($event eq 'endrow')
225 elsif($event eq 'endmatrix')
229 print " Relevance: $min\n";
232 elsif($event eq 'end')
240 $s =~ s/[^-_A-Za-z0-9 ]/&#@{[ord $&]};/g;
253 my ($event, @data) = @_;
254 if($event eq 'start')
256 print "<html><body><h1>Weapon Profiling</h1>\n";
258 elsif($event eq 'startmatrix')
260 my ($addr, $type, $map, @columns) = @data;
264 print "<h2>For server $addr type $type map $map</h2>\n";
265 print "<table><tr><th>Weapon</th><th>Rating</th>\n";
266 printf '<th><img width=64 height=87 src="weaponimg/%s_3rd_small.png" title="%s" alt="%s"></th>', $stats->weaponid_to_model($_), html $stats->weaponid_to_name($_), html nospace $stats->weaponid_to_name($_) for @columns;
269 elsif($event eq 'startrow')
271 my ($row, $val) = @data;
272 printf '<tr><th><img width=96 height=64 src="weaponimg/%s_1st_small.png" title="%s" alt="%s"></th><th align=right>%s</th>', $stats->weaponid_to_model($row), html $stats->weaponid_to_name($row), html nospace $stats->weaponid_to_name($row), defined $val ? sprintf("%8.5f", $val) : "N/A";
274 elsif($event eq 'cell')
276 my ($win, $lose, $p) = @data;
280 printf '<td align=center bgcolor="#808080">%d</td>', $win;
284 printf '<td align=center bgcolor="#%02x%02x%02x">%d</td>', $v - $v * $p, 255, 0, $win;
288 #printf '<td align=center bgcolor="#%02x%02x%02x">%d</td>', (255 - $v) - $v * $p, $v + $v * $p, 0, $win;
289 printf '<td align=center bgcolor="#%02x%02x%02x">%d</td>', 255, $v + $v * $p, 0, $win;
293 printf '<td align=center bgcolor="#ffff00">%d</td>', $win;
296 elsif($event eq 'endrow')
300 elsif($event eq 'endmatrix')
304 print "</table>Relevance: $min\n";
306 elsif($event eq 'end')
311 my $out_html_cache_fh;
312 sub out_html_cache($@)
314 my ($event, @data) = @_;
315 if($event eq 'startmatrix')
318 my ($addr, $type, $map, @columns) = @data;
324 open $out_html_cache_fh, ">", "$type/$map"
325 or warn "open $type/$map: $!";
326 select $out_html_cache_fh;
329 out_html($event, @data)
330 if defined $out_html_cache_fh;
331 if($event eq 'endmatrix')
335 close $out_html_cache_fh
336 if defined $out_html_cache_fh;
337 undef $out_html_cache_fh;
342 $ENV{html_cache} ? \&out_html_cache :
343 $ENV{html} ? \&out_html :
350 my ($addr, $type, $map, $data) = @_;
351 my $values = Evaluate $data;
352 my $valid = defined [values %$values]->[0];
353 my @weapons_sorted = sort { $valid ? $values->{$b} <=> $values->{$a} : $a <=> $b } keys %$values;
355 $out->(startmatrix => ($addr, $type, $map, @weapons_sorted));
356 for my $row(@weapons_sorted)
358 $out->(startrow => $row, ($valid ? $values->{$row} : undef));
359 for my $col(@weapons_sorted)
361 my $win = ($data->{$row}{$col} || 0);
362 my $lose = ($data->{$col}{$row} || 0);
364 if $row ne $col and (not defined $min or $min > $win + $lose);
365 $out->(cell => ($win, $lose, (($row ne $col) && ($win + $lose)) ? (2 * $win / ($win + $lose) - 1) : undef));
367 $out->(endrow => ());
369 $out->(endmatrix => ($min));