Dtablegen

#!/usr/bin/perl -w
use strict;
my $invert_y = 1; # For dofus's map, which is a bit goofy this way.
my $scrunch_blank = 1; # Do we skip over blank rows/cols in the grid
main();
############################
# dtablegen, a tool for making nice wiki tables for coordinate data.
# 	Originally written for maps in the dofus wiki.
#
# By Pat Gunn, hereby placed in the Public Domain.
############################
sub main
{
my %cfg = handle_args(@ARGV); # Keys: image
my %zone; # Not using a true array because coords may be negative, and also
	# because it's more efficient to do it with a sparse matrix.
my $max_x;
my $min_x;
my $max_y;
my $min_y;
while(<STDIN>) # Let's read the table and fill in the grid
	{
	my ($cx, $cy, $num) = /\(([-0-9]+)\s*,\s*([-0-9]+)\)\s*x\s*([0-9]+)/;
				# Typical line: (-76,-49) x 2
	if(defined($cx) && defined($cy) && defined($num))
		{
		if( defined($zone{$cx}{$cy}) )
			{
			die "Duplicate entry in map at ($cx,$cy), PLEASE FIX\n";
			}
		learn_from($cx, $cy, \$max_x, \$min_x, \$max_y, \$min_y);
		$zone{$cx}{$cy} = $num;
		}
	else
		{
		chomp $_;
		die "Failed to parse line in table: [$_]\n";
		}
	}
# At this point we know the min and max of both axes, and we're ready to generate the grid.
# Pay attention to the following two header variables: $invert_y and $scrunch_blank
my @cols;
my @rows;
if($scrunch_blank)
	{
	@cols = sort {$a <=> $b} keys %zone;
	my %tmpr;
	foreach my $tmpkey (@cols)
		{
		map
			{
			$tmpr{$_} = 1;
			} keys %{$zone{$tmpkey}};
		}
	@rows = keys %tmpr;
	}
else
	{
	@cols = $min_x .. $max_x;
	@rows = $min_y .. $max_y;
	}
# And now we sort the rows according to $invert_y
if($invert_y)
	{@rows = sort {$a <=> $b} @rows;}
else
	{@rows = sort {$b <=> $a} @rows;}
print generate_table(\%cfg, \@cols, \@rows, \%zone);
}
sub usage
{
die "Usage: dwikitable IMAGENAME RESNAME\n(feed to STDIN the table)\n";
}
sub handle_args
{
my @args = @_;
my %ret;
if(@args != 2)
	{usage()};
if(($args[0] =~ /-h/)
|| ($args[0] =~ /--help/))
	{usage();}
$ret{image} = $args[0];
$ret{name} = $args[1];
return %ret;
}
sub learn_from
{
my ($cordx, $cordy, $ref_max_x, $ref_min_x, $ref_max_y, $ref_min_y) = @_;
if( 	(! defined($$ref_min_x))
||	($cordx < $$ref_min_x))
	{
	$$ref_min_x = $cordx;
	}
if( 	(! defined($$ref_max_x))
||	($cordx > $$ref_max_x))
	{
	$$ref_max_x = $cordx;
	}
if( 	(! defined($$ref_min_y))
||	($cordy < $$ref_min_y))
	{
	$$ref_min_y = $cordy;
	}
if( 	(! defined($$ref_max_y))
||	($cordy > $$ref_max_y))
	{
	$$ref_max_y = $cordy;
	}
}
sub generate_table
{ # Ok, this is a good start, but how do we handle blank spots on the grid? Ideally we leave them blank.
my ($cfg, $cols, $rows, $zone) = @_;
my $ret = ;
$ret .= qq/{| {{prettytable}}\n/;
$ret .= qq/! !!/ . join('!!', @$cols) . "\n";
foreach my $row (@$rows)
	{
	$ret .= "|-\n";
	$ret .= "!$row\n";
	$ret .= "| ";
	$ret .= join(' || ', map{ build_grid_square($$zone{$_}{$row}, $$cfg{image}, $$cfg{name}) } @$cols) . "\n";
	}
$ret .= qq/\n|}\n\n/;
return $ret;
}
sub build_grid_square
{
my ($val, $img, $name) = @_;
if(defined $val)
	{
	return $val . '[[Image:' . $img . '|' . $name . '|15px]]';
	}
else
	{
	return ; # Alternatively, could make it grey with value bgcolor="grey" (do we need an extra | after that?)
	}
}
The above is used to make tables based on data pages, such as Frosteez (plant)/data or Aspen (tree)/data.
*