#!/usr/bin/perl
use 5.016;
use warnings;
use List::Util qw(reduce);

my $table = [ map{ [ split // ] } split(/\n/, <<'EOF') ];
WVERTICALL
ROOAFFLSAB
ACRILIATOA
NDODKONWDC
DRKESOODDK
OEEPZEGLIW
MSIIHOAERA
ALRKRRIRER
KODIDEDRCD
HELWSLEUTH
EOF

my @words = split /\n/, <<'EOF';
WEEK
FIND
RANDOM
SLEUTH
BACKWARD
VERTICAL
DIAGONAL
WIKIPEDIA
HORIZONTAL
WORDSEARCH
EOF

sub rest { [ @{$_[0]}[1 .. $#{$_[0]}] ] }
sub equal { defined $_[0] and $_[0] eq $_[1] }

sub f {
	my ($x, $y, $dx, $dy, $words, $str) = @_;

	return ((@{$str} < 1) ?
		1 :
		((($x >= 0) and ($y >= 0) and equal($words->[$y]->[$x], $str->[0])) ?
			f($x + $dx, $y + $dy, $dx, $dy, $words, rest($str)) :
			0
		)
	);
}

sub g {
	my ($words) = @_;

	my @dir = (
		[-1, -1], [0, -1], [1, -1], [-1, 0], [1, 0], [-1, 1], [0, 1], [1, 1]
	);

	my %initial;
	foreach my $y (0 .. $#{$words}){
		foreach my $x (0 .. $#{$words->[$y]}){
			push(@{$initial{$words->[$y]->[$x]}}, [$x, $y]);
		}
	}

	return sub {
		my $str = [ split //, shift ];
		return reduce {
			(grep{ f(@{$b}, @{$_}, $words, $str) } @dir) ? [ @{$a}, $b ] : $a
		} [], @{$initial{$str->[0]}}
	};
}

use Data::Dumper;
local $Data::Dumper::Terse = 1;
local $Data::Dumper::Indent = 0;

my $g = g($table);
say Dumper([ map{ [ $_, $g->($_) ] } @words ]);
