#!/usr/bin/env perl use strict; use warnings; use Getopt::Long 2.33 qw(HelpMessage :config bundling); use Template; use List::Util; use Data::Dumper; our $VERSION = '1.00'; GetOptions( "verbose|v!" => \our $DEBUG, ) or HelpMessage(-exitval => 2); my %area = ( fieldxmin => 45, fieldxmax => 1590, fieldymin => 10, fieldymax => 575, xmax => 1600, ymax => 600, ); $area{fieldxsize} = $area{fieldxmax} - $area{fieldxmin}; $area{fieldysize} = $area{fieldymax} - $area{fieldymin}; my @lines; my @max = (0) x 4; my $maxtime = 0; my $player = 0; for my $input (@ARGV) { open my $datafile, '<', $input or next; my @data; my $lasttime; while (defined ($_ = readline $datafile)) { my ($frame, $time, @vars) = split /\t/, $_; $frame =~ /^\d+:$/ or next; if ($time !~ /^\d+$/) { defined $lasttime or next; $time = $lasttime + 1; $lasttime = undef; } else { $lasttime = $time; } /^\d+$/ or $_ = undef for @vars; push @{$data[$time]} => \@vars; defined $vars[$_] and $vars[$_] > $max[$_] and $max[$_] = $vars[$_] for 0 .. $#vars; } $maxtime = $#data if $#data > $maxtime; close $datafile; for my $time (0 .. $#data) { my $vals = $data[$time]; for my $subtime (0 .. $#$vals) { defined $vals->[$subtime]->[$_] and push @{$lines[$_][$player]} => [ ($time + $subtime/@$vals), # x $vals->[$subtime]->[$_] # y ] for 0 .. 3; } } for (0 .. 3) { my $line = $lines[$_][$player]; my $start; my $lasty; for (my $i = 1; $i <= $#$line; $i++) { defined $line->[$i] or next; if ($line->[$i][1] == $line->[$i - 1][1]) { $start = $i unless defined $start; } elsif (defined $start) { delete @$line[$start .. $i-2]; undef $start; } } delete @$line[$start .. $#$line-2] if defined $start; # or -1 } $player++; } $max[2] = $max[3]; my @norm = ((map {$area{fieldysize} / $_} @max), $area{fieldxsize} / $maxtime); my $xsteps = 25; my $xstep = $maxtime / $xsteps; my @xaxis = map [$area{fieldxmin} + $_ * $norm[4], sprintf '%d:%02d', $_/3600, $_/60%60], map $_*$xstep, 0 .. $xsteps-1; my $ysteps = 10; my @yaxis; for my $i (0 .. 3) { my $ystep = $max[$i] / $ysteps; $ystep = 10 ** int (log($ystep * 4) / log(10)); $ystep /= 2 while $ystep * $ysteps > $max[$i]; $yaxis[$i] = [ map [$area{fieldymax} - $_ * $norm[$i], $_], map $_*$ystep, 0 .. int $max[$i] / $ystep ]; } undef $/; my $svg = Template->new({POST_CHOMP => 1, BLOCKS => {timeline => readline DATA}}); for ([0 => "min", "Minerals"], [1 => "gas", "Gas"], [2 => "unit", "Units"]) { my ($line, $filename, $title) = @$_; open my $output, '>', "$filename.svg"; $svg->process('timeline', { title => "$title timeline for /replay/20080201md4x4", fill => $line == 2 && [ map { "\n\tM " . join "\tL ", map sprintf("%s %s\n", $area{fieldxmin} + $_->[0] * $norm[4], $area{fieldymax} - $_->[1] * $norm[$line+1] ), grep defined, @{$lines[$line][$_]}, reverse @{$lines[$line+1][$_]} } 0 .. $#{$lines[$line]} ], paths => [ map { "\n\tM " . join "\tL ", map sprintf("%s %s\n", $area{fieldxmin} + $_->[0] * $norm[4], $area{fieldymax} - $_->[1] * $norm[$line] ), grep defined, @$_ } @{$lines[$line]} ], xaxis => \@xaxis, yaxis => $yaxis[$line], area => \%area, }, $output) or die $svg->error; } __DATA__ [% title %] [% FOREACH entry = xaxis %] [% entry.1 %] [% END %] [% FOREACH entry = yaxis %] [% entry.1 %] [% END %] [% count = 0 %] [% FOREACH path = paths %][% count = count + 1 %] [% END %] [% IF fill %] [% count = 0 %] [% FOREACH path = fill %][% count = count + 1 %] [% END %] [% END %]