PHP anagram拼图解算器

时间:2015-08-08 05:15:26

标签: php puzzle solver anagram

我正在尝试找到我正在研究的PHP拼图解算器的解决方案。

这是一个anagram解算器,需要在“给游泳者的消息”中用16个字母的4个字母的字谜填充4x4网格。

水平行和垂直列需要制作短语的完整4个字母的字谜。以下是期望的结果,但我的计划必须自己解决。

S M O G
W E R E
I T E M
M A S S

我创造这个的尝试正在超时。我正在尝试这样的事情:

foreach($word_array as $word){

    $board = array();   
    $available = $default_array;
    $row1 = $trie->run_word_check($word[0],$available);

    if($row1){
        echo "current row1 check: ". $row1."<br/>";
        remove_from_available($row1,$available);
        $board[] = $row1;
        $col1 = $trie->run_word_check($row1[0],$available);

        if($col1){
            echo "current col1 check: ". $col1."<br/>";
            remove_from_available($col1,$available);
            $board[] = $col1;
            $row2 = $trie->run_word_check($col1[0],$available);

            if($row2){
                echo "current row2 check: ". $row2."<br/>";
                remove_from_available($row2,$available);
                $board[] = $row2;
                $col2 = $trie->run_word_check($row1[1].$row2[1],$available);

                if($col2){
                    etc...
                }
            }
        }
    }
}

1 个答案:

答案 0 :(得分:1)

以下是如何做到这一点:

  • 预处理4个字母的单词列表,以便将它们作为键(值为1或其他值),以及它的每个前缀。所以当你有一个'SWIM'键时,你也会有一个'S','SW'和'SWI'。这对于快速检查选择几个字符后是否仍有可能完成一个4个字母的单词非常有用。

  • 预处理16个字母的输入字符串:将各个字母存储为键,其值等于该字符串中出现的次数。因此,对于“给游泳者的消息”,键“S”的值为3。

  • 保持4个水平字和4个垂直字。当然,这里有一些冗余(因为垂直的可以从水平的那里得到),但它将有助于快速访问它们。这两个4个单词的数组将以所有空字符串开头。

  • 然后从第二个数组中取一个字母(即带有计数的可用字母)用于网格中的位置0,0,然后将其存储为第一个水平字作为第一个垂直词。检查是否有4个字母的单词以此开头。

  • 如果有4个字母的单词可能性,则使用递归将下一个字母放在网格中的1,0处。将该字母添加到第一个水平单词(现在它有2个字符)并将其放在第二个垂直单词中(那里只有1个字符)。再次检查。

  • 重复递归,直到填充网格中的所有元素或者找不到任何字母,当将其添加到适当的水平和垂直单词时,会产生无法进一步完成以匹配4个字母单词的内容。在后一种情况下,回溯并尝试其他角色。

以上是粗略描述。这是代码:

$solution = anagram("Message to swimmer", get_words());
print_r ($solution);

function index_words($word_array) {
    $dict = [ '' => 1 ];
    foreach ($word_array as $word) {
        for ($len = 1; $len <= 4; $len++) {
            $dict[substr($word, 0, $len)] = 1;
        }
    }
    return $dict;
}

function letter_counts($available) {
    $letters = [];
    foreach(str_split(strtoupper($available)) as $letter) {
        if (ctype_alpha($letter)) {
            $letters[$letter] = isset($letters[$letter]) ? $letters[$letter]+1 : 1;
        }
    }
    return $letters;
}

function anagram($available, $word_array) { // Main algorithm
    $dict = index_words($word_array); //keys = all 4 letter words, and all their prefixes
    $letters = letter_counts($available); // key = letter, value = occurrence count
    $hori = ['','','','']; // store the words that are formed horizontally per row
    $vert = ['','','','']; // store the words that are formed horizontally per column

    $recurse = function ($row, $col) 
               use (&$recurse, &$letters, &$dict, &$hori, &$vert, &$limit) {
        if ($row == 4) return true; // all done. backtrack out of recursion
        $h = $hori[$row];
        $v = $vert[$col];
        foreach($letters as $letter => $count) { // for each available character
            if (!$count) continue; // not available any more
            $word1 = $h . $letter;
            $word2 = $v . $letter;
            if (isset($dict[$word1]) && isset($dict[$word2])) {
                // It is still possible to form 4-letter words after placing this letter
                $hori[$row] = $word1;
                $vert[$col] = $word2;
                $letters[$letter]--; 
                // use recursion to find characters for next slots in the grid
                if ($recurse($row + ($col == 3 ? 1 : 0), ($col + 1) % 4)) return true;
                // backtrack
                $letters[$letter]++;
            }
        }
        $hori[$row] = $h;
        $vert[$col] = $v;
    };
    $recurse(0, 0); // start the recursive placement of letters in the grid
    return $hori; // return the 4 words that were placed horizontally
}

function get_words() { // returns a comprehensive list of 4 letter words
    return [
'AAHS', 'AALS', 'ABAC', 'ABAS', 'ABBA', 'ABBE', 'ABBS', 'ABED', 'ABET', 'ABID', 'ABLE', 
/* etc... long list of 4-letter words ... */
'ZOOM', 'ZOON', 'ZOOS', 'ZOOT', 'ZORI', 'ZOUK', 'ZULU', 'ZUPA', 'ZURF', 'ZYGA', 'ZYME', 
'ZZZS'];
}   

您可以在eval.in上看到它。

发布4个字母的单词here,它会在不到0.2秒的时间内找到以下解决方案:

M E G S
O W R E
M E A T
I S M S

...结果取决于单词列表当然。我不得不查看OWRE的含义; - )