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 @candidates; my $length = $self->length->($word,$HORIZONTAL); $self->log->debug("looking for $length of horizontal space"); push @candidates, $self->_find_places_horiz($length); $length = $self->length->($word,$VERTICAL); $self->log->debug("looking for $length of vertical space"); 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} (?X*) | O{$length} (?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;