Form a multiline string and play with the $gap.
#!/usr/bin/perl
# http://perlmonks.org/?node_id=1207332
use strict;
use warnings;
my @grid =
(
[ qw( a a b a c ) ],
[ qw( a a a c f ) ],
[ qw( a f c 1 b ) ],
[ qw( a w x c z ) ],
[ qw( a q q q c ) ],
);
$_ = join '', map join('', @$_) . "\n", @grid; # convert to string
print;
recognize( pattern => 'horizontal', min => 3 );
recognize( pattern => 'vertical', min => 5 );
recognize( pattern => 'diagonal', min => 2 );
sub recognize
{
my %args = @_;
my ( $direction, $min) = @args{ qw( pattern min ) };
$min // die "min not defined";
my $reps = $min - 1;
my $linesize = /\n/ && $+[0];
my $gapref = { horizontal => [0], vertical => [$linesize - 1],
diagonal => [$linesize - 2, $linesize]}->{$direction} //
die "invalid direction $direction";
for my $gap ( @$gapref )
{
print "\n";
print "$direction @{[ 1 + length($2) / ($gap + 1) ]} '$1' at ",
$-[1] % $linesize, ' ', int $-[1] / $linesize, "\n"
while /(\w)(?=((?:.{$gap}\1){$reps,}))/gs;
}
}
Outputs:
aabac
aaacf
afc1b
awxcz
aqqqc
horizontal 3 'a' at 0 1
horizontal 3 'q' at 1 4
vertical 5 'a' at 0 0
diagonal 2 'a' at 1 0
diagonal 2 'a' at 3 0
diagonal 3 'c' at 4 0
diagonal 2 'a' at 1 1
diagonal 2 'c' at 3 1
diagonal 2 'a' at 0 0
diagonal 2 'a' at 1 0
diagonal 3 'c' at 2 2
diagonal 2 'c' at 3 3