You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
wiki-map/coord_tripler.pl

129 lines
4.3 KiB

use v5.36;
use rlib '.';
use Carp;
use Data::Dumper;
use feature "signatures";
no warnings "experimental::signatures";
my $coords_regex = qr/^\s*(-?\d+)\s*,\s*(-?\d+)\s*$/;
my %regions;
my %tile_to_regions;
my %bounds =
(
nw_min => "Inf",
nw_max => "-Inf",
sw_min => "Inf",
sw_max => "-Inf"
);
my $input_file = shift;
open (my $input_fh, $input_file);
my $output_file = shift // "$input_file.out";
open (my $output_fh, ">$output_file");
$regions{holes}{bg} = '#000000';
while (my $line = <$input_fh>)
{
my @fields = split '; ', $line;
my $region = (shift @fields); #region name
$regions{$region}{bg} = (shift @fields); #background colour
expand_coords(\%regions, \%tile_to_regions, $region, \%bounds, @fields);
}
fill_holes(\%regions, \%tile_to_regions, \%bounds);
foreach my $region (keys %regions)
{
say $output_fh ("$region; $regions{$region}{bg}; " . make_output_region_line(\%regions, $region));
}
sub expand_coords($regions_hashref, $tile_to_region_hashref, $region, $bounds, @coord_list)
{
foreach my $coords (@coord_list)
{
do { carp "Skipping bad spec: $coords"; next; } unless $coords =~ $coords_regex;
my $nw_base = $1 * 3;
my $sw_base = $2 * 3;
push @{$regions_hashref->{$region}{tiles}{$nw_base}}, $sw_base;
push @{$regions_hashref->{$region}{tiles}{$nw_base+1}}, $sw_base;
push @{$regions_hashref->{$region}{tiles}{$nw_base-1}}, $sw_base;
push @{$regions_hashref->{$region}{tiles}{$nw_base}}, $sw_base+1;
push @{$regions_hashref->{$region}{tiles}{$nw_base}}, $sw_base-1;
push @{$regions_hashref->{$region}{tiles}{$nw_base+1}}, $sw_base-1;
push @{$regions_hashref->{$region}{tiles}{$nw_base-1}}, $sw_base+1;
$tile_to_region_hashref->{$nw_base}{$sw_base} = $region;
$tile_to_region_hashref->{$nw_base+1}{$sw_base} = $region;
$tile_to_region_hashref->{$nw_base-1}{$sw_base} = $region;
$tile_to_region_hashref->{$nw_base}{$sw_base+1} = $region;
$tile_to_region_hashref->{$nw_base}{$sw_base-1} = $region;
$tile_to_region_hashref->{$nw_base+1}{$sw_base-1} = $region;
$tile_to_region_hashref->{$nw_base-1}{$sw_base+1} = $region;
$bounds{nw_min} = $nw_base - 1 if $bounds{nw_min} > $nw_base - 1;
$bounds{nw_max} = $nw_base + 1 if $bounds{nw_max} < $nw_base + 1;
$bounds{sw_min} = $sw_base - 1 if $bounds{sw_min} > $sw_base - 1;
$bounds{sw_max} = $sw_base + 1 if $bounds{sw_max} < $sw_base + 1;
}
}
sub fill_holes($regions_hashref, $tile_to_region_hashref, $bounds)
{
for(my $nw = $bounds->{nw_min}; $nw <= $bounds->{nw_max}; $nw++)
{
for(my $sw = $bounds->{sw_min}; $sw <= $bounds->{sw_max}; $sw++)
{
if($nw % 3 != 0 && $nw % 3 == $sw % 3)
{
my %neighbouring_regions;
$neighbouring_regions{$tile_to_region_hashref->{$nw+1}{$sw}}++ if exists $tile_to_region_hashref->{$nw+1}{$sw};
$neighbouring_regions{$tile_to_region_hashref->{$nw-1}{$sw}}++ if exists $tile_to_region_hashref->{$nw-1}{$sw};
$neighbouring_regions{$tile_to_region_hashref->{$nw}{$sw+1}}++ if exists $tile_to_region_hashref->{$nw}{$sw+1};
$neighbouring_regions{$tile_to_region_hashref->{$nw}{$sw-1}}++ if exists $tile_to_region_hashref->{$nw}{$sw-1};
$neighbouring_regions{$tile_to_region_hashref->{$nw+1}{$sw-1}}++ if exists $tile_to_region_hashref->{$nw+1}{$sw-1};
$neighbouring_regions{$tile_to_region_hashref->{$nw-1}{$sw+1}}++ if exists $tile_to_region_hashref->{$nw-1}{$sw+1};
my $total_neighbours = 0;
map {$total_neighbours += $_} (values %neighbouring_regions);
next if $total_neighbours < 6; # Must be surrounded to be filled
# Each neighbouring region will always provide 2,4 or 6 neighbouring tiles
my $found_region;
foreach my $region (keys %neighbouring_regions)
{
if($neighbouring_regions{$region} > 3) # == 4 or 6
{
$found_region = $region;
}
}
if(!$found_region) # Neighboured by 3 regions each providing 2 tiles
{
$found_region = (keys %neighbouring_regions)[int(rand(3))];
}
push @{$regions_hashref->{$found_region}{tiles}{$nw}}, $sw;
$tile_to_region_hashref->{$nw}{$sw} = $found_region;
}
}
}
}
sub make_output_region_line($regions_hashref, $region)
{
my $line = "";
foreach my $nw (keys %{$regions_hashref->{$region}{tiles}})
{
foreach my $sw (@{$regions_hashref->{$region}{tiles}{$nw}})
{
$line .= "$nw,$sw; ";
}
}
chop($line);
chop($line);
return $line;
}
close $input_fh;
close $output_fh;