I'm trying to solve word search puzzles which contain hidden messages. The idea is to match the given words in the grid and any remaining letters will be the message. I found this script golfed version [1] to be a good starting point, but it doesn't handle many corner cases, so I tried improving on it by keeping a separate grid for each direction. I ultimately want to duplicate the results from this online tool [2], which produces perfect results, but I can't find a description of the algorithm anywhere. The following is my version, which produces good results, but not perfect.
[1] http://codegolf.stackexchange.com/a/3390/36220
[2] http://www.dcode.fr/word-search-solver

Edit: So I finally got this particular test to work by iterating through the different directions in the reverse order plus only allowing one match per word. That feels a bit arbitrary, so still open to alternative algorithm suggestions.

#!/usr/bin/env perl use 5.012; use warnings; use List::AllUtils qw(nsort_by reduce); my $grid = join "\n", qw( ONEFISHTWOJELLYFISHS LYNTAOBDOPAEPNBUETYE PMIRHSAESTNESRRARTEU CALIFORNIAPLEASANTLL HHSREDPOPPIESXVHUWLB AAAZECROFEFILERDLOAE PMLMPHSIFDEPIRTSYOVM PDLEQMIEWBLACKCATDSI YEADENRESURGENCEPYNT FNCIDOLBABYOCTOPUSOR AHTCYLMAERDSRELLEFTE MODEERFOTTHGILFWDPLM IUBRNEDRAGEMOHELHKAM LSSCOUNTRYWALKDTVQWU YEDNOPNEZORFPUSFRUSS ); my @words = qw( BABYOCTOPUS BLACKCAT CALIFORNIAPLEASANT CALLAS COUNTRYWALK EEL FELLERSDREAM FLIGHTTOFREEDOM FROZENPOND HAMDENHOUSE HAPPYFAMILY HOMEGARDEN LIFEFORCE ONEFISHTWOJELLYFISH PEAPODBOAT REDPOPPIES REEFDWELLERS RESURGENCE SEASHRIMP STRIPEDFISH SUMMERTIMEBLUES SURFSUP VASE WALTONSVALLEY WOODY ); # Look for the largest words first. @words = nsort_by { -length } @words; my $width = index $grid, "\n"; my @dir = map { [$_, 0, $grid], [$_, 1, $grid] } (0, $width-1 .. $widt +h+1); for my $word (@words) { for my $dir (@dir) { my @char = split '', $dir->[1] ? reverse $word : $word; my $re = join ".{$dir->[0]}", map "($_)", @char; if (my $i = $dir->[2] =~ /$re/s ) { substr $dir->[2], $-[$i++], 1, ' ' for @char; } } } my $message = reduce { $a & $b } map { $_->[2] } @dir; $message =~ tr/A-Z//cd; say $message;
The hidden message is supposed to be LYNNBUETTNERART, but my version produces LYNNBUETTNRART... (note the missing second E), whereas the the online tool gets this right. Can somebody help find the error in the algorithm or the implementation, or suggest a better algorithm?

In reply to Improving this word search solver by phizel

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.