#!/usr/bin/perl -w
use strict;
our (@empty_square, @full_square);

my @sample_puzzle = (
 '....X.....X....',
 '....X.....X....',
 '....X.....X....',
 '.......X.......',
 'XXX......X.....',
 '.....X......XXX',
 '......X...X....',
 '...X.......X...',
 '....X...X......',
 'XXX......X.....',
 '.....X......XXX',
 '.......X.......',
 '....X.....X....',
 '....X.....X....',
 '....X.....X....',
);

my @output = layout_crossword(@sample_puzzle);
print join("\n",@output),"\n";


# The pre-requisites to this function are that:
# 1) in the @sample_puzzle array, blanks are notated as '.'
# 2) the @empty_square array contains a 1 character border around the blank area

sub layout_crossword {
 my $count = 1;        # start the numbering
 my $width = length($_[0]) -1;    # width of crossword
 my $height = scalar(@_) -1;     # height of crossword
 my @lines = ();        # our output block
 my $fill = substr($full_square[0],0,1);  # whats the border character?

 foreach my $h (0..$height) {    #
  pop @lines if($h > 0);     # remove the overlap row
            # add the new block rows
  push @lines, map {$fill} 0..(scalar(@full_square)-1);

  foreach my $w (0..$width) {
   # we got a full square
   if(substr($_[$h],$w,1) ne '.') {
    add_square(\@lines,\@full_square);
    next;
   }

   # determine the state of the neighbouring 4 squares
   my ($above,$below,$left,$right) = (0,0,0,0);
   $above = 1 if($h == 0       || substr($_[$h-1],$w,1) ne '.');
   $below = 1 if($h == $height || substr($_[$h+1],$w,1) ne '.');
   $left  = 1 if($w == 0       || substr($_[$h],$w-1,1) ne '.');
   $right = 1 if($w == $width  || substr($_[$h],$w+1,1) ne '.');

   # if start of row or column, we have a blank with number
   if(($above && !$below) || ($left && !$right)) {
    add_square(\@lines,\@empty_square,$count);
    $count++;

   # otherwise we have just a blank
   } else {
    add_square(\@lines,\@empty_square);
   }
  }
 }

 return @lines;
}

sub add_square {
 my ($lines,$square,$count) = @_;

 # calculate the current depths
 my $max = scalar(@$lines) - 1;
 my $squ = scalar(@$square) - 1;

 # foreach square row
 foreach my $inx (0..$squ) {
  my $this = $max-$squ+$inx;    # which block row?
  chop @{$lines}[$this];     # remove the overlap column
  @{$lines}[$this] .= @{$square}[$inx]; # add square row to block row
  @{$lines}[$this] =~ s/\./ /g;   # replace dots with space
 }

 if(defined $count) {      # do we need to add a number?
  # check the number will fit
  my $wid = length("$count");    # how many characters?
  die "Sorry, number too big for square\n" if($wid > $squ);

  my $this = $max-$squ+1;     # 2nd row of the blank square
  my $inx = length(@{$lines}[$this])  # 2nd col of the blank square
     - length(@{$square}[0])
     + 1;
            # replace with the number
  substr(@{$lines}[$this],$inx,$wid,"$count");
 }
}

