最近我一直在iPhone上玩一款名为《Scramble》的游戏。有些人可能知道这个游戏叫拼字游戏。从本质上讲,当游戏开始时,你会得到一个字母矩阵:
F X I E
A M L O
E W B X
A S T U
The goal of the game is to find as many words as you can that can be formed by chaining letters together. You can start with any letter, and all the letters that surround it are fair game, and then once you move on to the next letter, all the letters that surround that letter are fair game, except for any previously used letters. So in the grid above, for example, I could come up with the words LOB, TUX, SEA, FAME, etc. Words must be at least 3 characters, and no more than NxN characters, which would be 16 in this game but can vary in some implementations. While this game is fun and addictive, I am apparently not very good at it and I wanted to cheat a little bit by making a program that would give me the best possible words (the longer the word the more points you get).
(来源:boggled.org)
不幸的是,我不太擅长算法或它们的效率等等。我的第一次尝试使用一个像这样的字典(约2.3MB),并进行线性搜索,试图匹配字典条目的组合。这需要花费很长时间来找到可能的单词,因为你每轮只有2分钟的时间,这是不够的。
我很有兴趣看看是否有任何Stackoverflowers可以提出更有效的解决方案。我主要是在寻找使用三大p的解决方案:Python、PHP和Perl,尽管任何使用Java或c++的东西也很酷,因为速度是至关重要的。
目前的解决方案:
Adam Rosenfield, Python, ~20岁
John Fouhy, Python, ~3秒
Kent Fredric, Perl, ~1s
Darius Bacon, Python, ~1s
rvarcher, VB。净,~ 1 s
Paolo Bergantino, PHP(实时链接),~5s(本地~2s)
我花了3个月的时间致力于解决10个最佳点密集的5x5 Boggle板问题。
这个问题现在已经解决了,并在5个网页上进行了全面披露。有问题请联系我。
该棋盘分析算法使用显式堆栈,通过具有直接子信息的有向无环词图伪递归遍历棋盘方格,并使用时间戳跟踪机制。这很可能是世界上最先进的词汇数据结构。
该方案在四核上每秒评估大约10,000块非常好的电路板。(9500 +分)
父网页:
DeepSearch.c - http://www.pathcom.com/~vadco/deep.html
组件网页:
最佳记分牌- http://www.pathcom.com/~vadco/binary.html
高级词汇结构- http://www.pathcom.com/~vadco/adtdawg.html
板分析算法- http://www.pathcom.com/~vadco/guns.html
并行批处理- http://www.pathcom.com/~vadco/parallel.html
-
只有追求最好的人才会对这本全面的著作感兴趣。
这是我想出的解决填字游戏的办法。我想这是最“python”的做事方式:
from itertools import combinations
from itertools import izip
from math import fabs
def isAllowedStep(current,step,length,doubleLength):
# for step == length -1 not to be 0 => trivial solutions are not allowed
return length > 1 and \
current + step < doubleLength and current - step > 0 and \
( step == 1 or step == -1 or step <= length+1 or step >= length - 1)
def getPairwiseList(someList):
iterableList = iter(someList)
return izip(iterableList, iterableList)
def isCombinationAllowed(combination,length,doubleLength):
for (first,second) in getPairwiseList(combination):
_, firstCoordinate = first
_, secondCoordinate = second
if not isAllowedStep(firstCoordinate, fabs(secondCoordinate-firstCoordinate),length,doubleLength):
return False
return True
def extractSolution(combinations):
return ["".join([x[0] for x in combinationTuple]) for combinationTuple in combinations]
length = 4
text = tuple("".join("fxie amlo ewbx astu".split()))
textIndices = tuple(range(len(text)))
coordinates = zip(text,textIndices)
validCombinations = [combination for combination in combinations(coordinates,length) if isCombinationAllowed(combination,length,length*length)]
solution = extractSolution(validCombinations)
我善意地建议你不要将这部分用于所有可能的匹配,但它实际上提供了一种检查你生成的单词是否真的构成有效单词的可能性:
import mechanize
def checkWord(word):
url = "https://en.oxforddictionaries.com/search?filter=dictionary&query="+word
br = mechanize.Browser()
br.set_handle_robots(False)
response = br.open(url)
text = response.read()
return "no exact matches" not in text.lower()
print [valid for valid in solution[:10] if checkWord(valid)]
令人惊讶的是,没有人尝试使用PHP版本。
这是John Fouhy的Python解决方案的PHP版本。
虽然我从其他人的答案中得到了一些建议,但这主要是抄袭约翰的。
$boggle = "fxie
amlo
ewbx
astu";
$alphabet = str_split(str_replace(array("\n", " ", "\r"), "", strtolower($boggle)));
$rows = array_map('trim', explode("\n", $boggle));
$dictionary = file("C:/dict.txt");
$prefixes = array(''=>'');
$words = array();
$regex = '/[' . implode('', $alphabet) . ']{3,}$/S';
foreach($dictionary as $k=>$value) {
$value = trim(strtolower($value));
$length = strlen($value);
if(preg_match($regex, $value)) {
for($x = 0; $x < $length; $x++) {
$letter = substr($value, 0, $x+1);
if($letter == $value) {
$words[$value] = 1;
} else {
$prefixes[$letter] = 1;
}
}
}
}
$graph = array();
$chardict = array();
$positions = array();
$c = count($rows);
for($i = 0; $i < $c; $i++) {
$l = strlen($rows[$i]);
for($j = 0; $j < $l; $j++) {
$chardict[$i.','.$j] = $rows[$i][$j];
$children = array();
$pos = array(-1,0,1);
foreach($pos as $z) {
$xCoord = $z + $i;
if($xCoord < 0 || $xCoord >= count($rows)) {
continue;
}
$len = strlen($rows[0]);
foreach($pos as $w) {
$yCoord = $j + $w;
if(($yCoord < 0 || $yCoord >= $len) || ($z == 0 && $w == 0)) {
continue;
}
$children[] = array($xCoord, $yCoord);
}
}
$graph['None'][] = array($i, $j);
$graph[$i.','.$j] = $children;
}
}
function to_word($chardict, $prefix) {
$word = array();
foreach($prefix as $v) {
$word[] = $chardict[$v[0].','.$v[1]];
}
return implode("", $word);
}
function find_words($graph, $chardict, $position, $prefix, $prefixes, &$results, $words) {
$word = to_word($chardict, $prefix);
if(!isset($prefixes[$word])) return false;
if(isset($words[$word])) {
$results[] = $word;
}
foreach($graph[$position] as $child) {
if(!in_array($child, $prefix)) {
$newprefix = $prefix;
$newprefix[] = $child;
find_words($graph, $chardict, $child[0].','.$child[1], $newprefix, $prefixes, $results, $words);
}
}
}
$solution = array();
find_words($graph, $chardict, 'None', array(), $prefixes, $solution);
print_r($solution);
如果你想尝试的话,这里有一个实时链接。虽然在我的本地机器上需要大约2秒,但在我的web服务器上需要大约5秒。无论哪种情况,它都不是很快。尽管如此,它还是很可怕,所以我可以想象时间可以大大缩短。任何关于如何实现这一目标的建议都将不胜感激。PHP缺少元组,这使得坐标处理起来很奇怪,而且我无法理解到底发生了什么,这对我一点帮助都没有。
编辑:一些修复使它在本地少于1秒。
下面是使用NLTK工具包中的预定义单词的解决方案
NLTK有NLTK。语料库包,我们有一个叫做单词的包,它包含超过20万个英语单词,你可以简单地把它们都用到你的程序中。
一旦创建你的矩阵转换成一个字符数组,并执行这段代码
import nltk
from nltk.corpus import words
from collections import Counter
def possibleWords(input, charSet):
for word in input:
dict = Counter(word)
flag = 1
for key in dict.keys():
if key not in charSet:
flag = 0
if flag == 1 and len(word)>5: #its depends if you want only length more than 5 use this otherwise remove that one.
print(word)
nltk.download('words')
word_list = words.words()
# prints 236736
print(len(word_list))
charSet = ['h', 'e', 'l', 'o', 'n', 'v', 't']
possibleWords(word_list, charSet)
输出:
eleven
eleventh
elevon
entente
entone
ethene
ethenol
evolve
evolvent
hellhole
helvell
hooven
letten
looten
nettle
nonene
nonent
nonlevel
notelet
novelet
novelette
novene
teenet
teethe
teevee
telethon
tellee
tenent
tentlet
theelol
toetoe
tonlet
toothlet
tootle
tottle
vellon
velvet
velveteen
venene
vennel
venthole
voeten
volent
volvelle
volvent
voteen
我希望你能得到它。