summaryrefslogtreecommitdiff
path: root/lib/GridFiller/Chooser/Smarter.pm
blob: 43ad5305be4229f9e425f61f0d919e62e820bf64 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
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;
 
    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,$HORIZONTALif 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,$VERTICALif 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;