package GridFiller::Chooser::Smarter;
use Moose;
use namespace::autoclean -also => [qw(maxfirst)];
use GridFiller::Constants ':all';
use List::Util 'reduce';
use Carp;
extends 'GridFiller::Chooser';
sub maxfirst {
return reduce { $a->[0] > $b->[0] ? $a : $b } @_;
}
sub find_place_for {
my ($self,$word) = @_;
my $length = $self->length->($word);
$self->log->debug("looking for $length of space");
my @candidates;
push @candidates, $self->_find_places_horiz($length);
push @candidates, $self->_find_places_vert($length);
return unless @candidates;
my $ret = maxfirst @candidates;
return @$ret;
}
sub _find_places_horiz {
my ($self,$length) = @_;
my $rows = scalar @{$self->grid};
my ($col,$space);
my @ret;
for my $row (0..$rows-1) {
($space,$col) = $self->_find_in_row($row,$length);
push @ret, [$space,$col,$row,$HORIZONTAL] if defined $space;
}
return @ret;
}
sub _find_places_vert {
my ($self,$length) = @_;
my $cols = scalar @{$self->grid->[0]};
my ($row,$space);
my @ret;
for my $col (0..$cols-1) {
($space,$row) = $self->_find_in_col($col,$length);
push @ret,[$space,$col,$row,$VERTICAL] if defined $space;
}
return @ret;
}
{
my %symbols=(
$NOTHING => ' ',
$BLACK => 'X',
$WHITE => 'O',
);
sub _do_find {
my ($self,$str,$length) = @_;
my $rx = qr{\G .*?
(?:
X{$length} (?<tail>X*)
|
O{$length} (?<tail>O*)
) }x;
pos($str)=undef;
my @ret;
while ($str =~ m{$rx}gc) {
my $tail=length $+{tail};
my $skip=pos($str)-$length-$tail;
push @ret,[$tail,$skip];
$self->log->debug(" skip $skip tail $tail")
}
return unless @ret;
return @{maxfirst(@ret)};
}
sub _find_in_row {
my ($self,$row,$length) = @_;
my $str = join '',map { $symbols{$_} } @{$self->grid->[$row]};
$self->log->debug("row $row = $str");
return $self->_do_find($str,$length);
}
sub _find_in_col {
my ($self,$col,$length) = @_;
my $str = join '',map { $symbols{$_->[$col]} } @{$self->grid};
$self->log->debug("col $col = $str");
return $self->_do_find($str,$length);
}
}
1;