summaryrefslogtreecommitdiff
path: root/lib/GridFiller/Chooser/Smarter.pm
diff options
context:
space:
mode:
Diffstat (limited to 'lib/GridFiller/Chooser/Smarter.pm')
-rw-r--r--lib/GridFiller/Chooser/Smarter.pm118
1 files changed, 118 insertions, 0 deletions
diff --git a/lib/GridFiller/Chooser/Smarter.pm b/lib/GridFiller/Chooser/Smarter.pm
new file mode 100644
index 0000000..814e930
--- /dev/null
+++ b/lib/GridFiller/Chooser/Smarter.pm
@@ -0,0 +1,118 @@
+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 = length $word;
+
+ my @candidates;
+
+ push @candidates, $self->_find_places_horiz($length);
+ push @candidates, $self->_find_places_vert($length);
+
+ return unless @candidates;
+
+ my $ret = maxfirst @candidates;
+
+ shift @$ret;
+
+ 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;