#!/usr/local/bin/perl -w

use strict;
our (@empty_square, @full_square);

#############################################################################

package Grid;

sub new {
    my $class = shift;
    my $self = [@_];
    length $_ == length $self->[0] || die for @$self;
    bless $self, $class;
}

sub c { # c for "cell"
    my ($self, $row, $col, $val) = @_;
    defined $val ?
        substr($self->[$row], $col, length $val, $val) :
        substr($self->[$row], $col, 1);
}

sub rows { scalar @{$_[0]}; }

sub cols { length $_[0]->[0]; }

sub grid { $_[0]; }

#############################################################################

package main;

sub layout_crossword {
    my $t = Grid->new(@_);  # t for "template"
    my $e = Grid->new(@empty_square);
    my $f = Grid->new(@full_square);

    # regularize tmpl: just dots and Xs
    s/[^.]/X/g for @{$t->grid};

    # replace . with n where numbers go

    # horiz words are easy
    s/(^|X)\.([^X])/$1n$2/g for @{$t->grid};

    # vert words are harder
    for my $r (0..$t->rows-1) {
        for my $c (0..$t->cols-1) {
            if ($t->c($r, $c) ne 'X'
                && ($r == 0 || $t->c($r-1, $c) eq 'X')
                && $r < $t->rows-1
                && $t->c($r+1, $c) ne 'X') {
                $t->c($r, $c, 'n');
            }
        }
    }

    # p is our eventual output
    my $prows = ($e->rows-1) * $t->rows + 1;
    my $pcols = ($e->cols-1) * $t->cols + 1;
    my $p = Grid->new((' ' x $pcols) x $prows);

    # add phantom squares to minipuz, for right and bottom edges
    $t->grid->[$t->rows] = 'X' x $t->cols;
    $_ .= 'X' for @{$t->grid};

    # do the layout
    for my $r (0..$p->rows-1) {
        for my $c (0..$p->cols-1) {
            my $isfull = $t->c($r/($e->rows-1), $c/($e->cols-1)) eq
'X';
            my $filler = ($isfull?$f:$e)->c($r%($e->rows-1),
$c%($e->cols-1));
            $p->c($r, $c, $filler);
        }
    }

    # remove the phantom squares
    pop @{$t->grid};
    substr($_, -1, 1, '') for @{$t->grid};

    # determine numeral position within @empty_square
    my $nrow;
    my $ncol;
  NUMPOS:
    for my $r (0..$e->rows-1) {
        for my $c (0..$e->cols-1) {
            if ($e->c($r, $c) eq '.') {
                # found where to put the numeral
                ($nrow, $ncol) = ($r, $c);
                last NUMPOS;
            }
        }
    }

    # figure out how much room we have for digits
    die unless $e->c($nrow, $ncol) eq '.';
    my $nspace = length((substr($e->grid->[$nrow], $ncol) =~
/^(\.+)/)[0]);

    # stick in the numbers
    my $num = 1;
    for my $r (0..$t->rows-1) {
        for my $c (0..$t->cols-1) {
            if ($t->c($r, $c) eq 'n') {
                die if length $num > $nspace;
                $p->c($r*($e->rows-1)+$nrow, $c*($e->cols-1)+$ncol,
$num);
                $num++;
            }
        }
    }

    s/\./ /g for @{$p->grid};

    return @{$p->grid};
}


