use strict; use warnings; use re qw( eval ); use Data::Dump qw( pp ); sub finder_maker { my $pattern = shift; my @chars = split //, $pattern; die unless @chars > 1; my ($first_char, $second_char, @tail) = @chars; # Each character after the first two will be followed by (??{'.{'.length($1).'}'}) # This means that the code '.{'.length($1).'}' will be run while the regex is executed # and be replaced by .{N} with N the length of the first interval my $regex_tail = join "", map "(??{'.{'.length(\$1).'}'})$_", @tail; # Return a sub that will search for this pattern in a grid return sub { my $data = $_[0]; my $width = @{ $data->[0] }; say "Searching for $pattern in:\n", pp($data); # To avoid the string "ABCD" for # A B # C D # giving a false row on BC, we add dummy values to only keep the actual rows as valid # So we will have "AB__CD__" instead my $string = ""; $string .= join "", @$_, "_" x @$_, "\n" for @$data; my %directions = ( 0 => "Row", 2*$width => "Column", 2*$width+1 => "Diagonal" ); # Allow a distance that matches a row, column or diagonal for the first interval my $first_interval = join "|", map ".{$_}", keys %directions; # Find the first char, then the second, separated by an allowed interval $string =~ /$first_char ($first_interval) $second_char $regex_tail/xs or say "Not found\n\n" and return { }; my $out = { x => int($-[0]%(1+2*$width)), y => int($-[0]/(1+2*$width)), Direction => $directions{length $1} }; say "Found:\n", pp($out), "\n\n"; return $out; }; } 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 h q c ) ] ]; my $afx = finder_maker("afx"); $afx->($grid); finder_maker("fc1b")->($grid); my $smaller = [ ['w', 'a'], ['a', 'q'] ]; my $wq = finder_maker("wq"); $wq->($grid); $wq->($smaller); finder_maker("Nothing")->($smaller); #### Searching for afx in: [ ["a", "a", "b", "a", "c"], ["a", "a", "a", "c", "f"], ["a", "f", "c", 1, "b"], ["a", "w", "x", "c", "z"], ["a", "q", "h", "q", "c"], ] Found: { Direction => "Diagonal", x => 0, y => 1 } Searching for fc1b in: [ ["a", "a", "b", "a", "c"], ["a", "a", "a", "c", "f"], ["a", "f", "c", 1, "b"], ["a", "w", "x", "c", "z"], ["a", "q", "h", "q", "c"], ] Found: { Direction => "Row", x => 1, y => 2 } Searching for wq in: [ ["a", "a", "b", "a", "c"], ["a", "a", "a", "c", "f"], ["a", "f", "c", 1, "b"], ["a", "w", "x", "c", "z"], ["a", "q", "h", "q", "c"], ] Found: { Direction => "Column", x => 1, y => 3 } Searching for wq in: [["w", "a"], ["a", "q"]] Found: { Direction => "Diagonal", x => 0, y => 0 } Searching for Nothing in: [["w", "a"], ["a", "q"]] Not found