拼字游戏字谜生成器
Posted
技术标签:
【中文标题】拼字游戏字谜生成器【英文标题】:Scrabble Anagram Generator 【发布时间】:2010-12-23 18:43:14 【问题描述】:我正在尝试编写一个。
到目前为止,我的代码可以正常工作,但是速度非常慢,并且存在错误。一个是它会不止一次地使用字母。例如:输入的字母:“ABCDEFG”。而且会生成AB,还会生成AA,这是不对的。
请帮忙。
public class Scrabble1
private String[] dictionary2 = new String[97];
private String[] dictionary3 = new String[978];
private String[] dictionary4 = new String[3904];
private String[] dictionary5 = new String[8635];
private String[] dictionary6 = new String[15225];
private String[] dictionary7 = new String[23097];
public void sampleMethod(String s) throws FileNotFoundException
File in2 = new File( "dictionary2.txt" );
File in3 = new File( "dictionary3.txt" );
File in4 = new File( "dictionary4.txt" );
File in5 = new File( "dictionary5.txt" );
File in6 = new File( "dictionary6.txt" );
File in7 = new File( "dictionary7.txt" );
Scanner dict2 = null,dict3 = null,dict4 = null,dict5 = null,dict6 = null,dict7 = null;
try
dict2 = new Scanner(in2);
dict3 = new Scanner(in3);
dict4 = new Scanner(in4);
dict5 = new Scanner(in5);
dict6 = new Scanner(in6);
dict7 = new Scanner(in7);
int c = 0;
while(dict2.hasNext()&&dict3.hasNext()&&dict4.hasNext()&&dict5.hasNext()&&dict6.hasNext()&&dict7.hasNext())
dictionary2[c] = dict2.next();
dictionary3[c] = dict3.next();
dictionary4[c] = dict4.next();
dictionary5[c] = dict5.next();
dictionary6[c] = dict6.next();
dictionary7[c] = dict7.next();
c++;
catch( FileNotFoundException e )
System.err.println( e.getMessage () );
System.exit(1);
finally
dict2.close();
dict3.close();
dict4.close();
dict5.close();
dict6.close();
dict7.close();
// for(int i= 0; i<80612; i++)
//System.out.println(dicArray[i]);
String temp = "";
//All 2 letter anagrams
for(int k=0; k<=6; k++)
for(int i=0; i<=6; i++)
for(int d= 0; d<97; d++)
temp = "" + s.charAt(k) + s.charAt(i);
if(temp.equals(dictionary2[d]))
System.out.println(temp );
//All 3 letter anagrams
for(int j = 0; j<=6; j++)
for(int k=0; k<=6; k++)
for(int i=0; i<=6; i++)
for(int d= 0; d<978; d++)
temp = "" + s.charAt(j) + s.charAt(k)+ s.charAt(i);
if(temp.equals(dictionary3[d]))
System.out.println(temp );
//All 4 letter anagrams
for(int j = 0; j<=6; j++)
for(int k = 0; k<=6; k++)
for(int i=0; i<=6; i++)
for(int l=0; l<=6; l++)
for(int d= 0; d<-3904; d++)
temp = "" + s.charAt(j) + s.charAt(k)+ s.charAt(i)+ s.charAt(l);
if(temp.equals(dictionary4[d]))
System.out.println(temp );
//All 5 letter anagrams
for(int j = 0; j<=6; j++)
for(int k = 0; k<=6; k++)
for(int i=0; i<=6; i++)
for(int l=0; l<=6; l++)
for(int f=0; f<=6; f++)
for(int d= 0; d<8635; d++)
temp = "" + s.charAt(j) + s.charAt(k)+ s.charAt(i)+ s.charAt(l)+s.charAt(f);
if(temp.equals(dictionary5[d]))
System.out.println(temp );
//All 6 letter anagrams
for(int j = 0; j<=6; j++)
for(int k = 0; k<=6; k++)
for(int i=0; i<=6; i++)
for(int l=0; l<=6; l++)
for(int f=0; f<=6; f++)
for(int g=0; g<=6; g++)
for(int d= 0; d<15225; d++)
temp = "" + s.charAt(j) + s.charAt(k)+ s.charAt(i)+ s.charAt(l)+ s.charAt(f)+ s.charAt(g);
if(temp.equals(dictionary6[d]))
System.out.println(temp );
//All 7 letter anagrams.
for(int j = 0; j<=6; j++)
for(int k = 0; k<=6; k++)
for(int i=0; i<=6; i++)
for(int l=0; l<=6; l++)
for(int f=0; f<=6; f++)
for(int g=0; g<=6; g++)
for(int p=0; p<=6; p++)
for(int d= 0; d<23097; d++)
temp = "" + s.charAt(j) + s.charAt(k)+ s.charAt(i)+ s.charAt(l)+ s.charAt(f)+ s.charAt(g)+ s.charAt(p);
if(temp.equals(dictionary7[d]))
System.out.println(temp );
字典文件只是按字长排序。
【问题讨论】:
您是否只想找到使用所有字母的字谜,或者也想找到使用字母子集的字谜?也就是说,您是否希望它也为“one”找到“no”? 是的。我上面的凌乱算法就是这样做的,但效率很低。这是我想要实现的最好的例子:homepage.ntlworld.com/adam.bozon/scrabble.htm 您确定您的字典文件都包含相同数量的单词吗? (一旦到达第一个文件的末尾,您就停止读取文件......) 我使用了一个已经按字长排序的字典,然后我写了一个快速的程序来分离它。我也检查了它们,所以我很确定。 我问的不是单词的长度,而是每个文件有多少... 【参考方案1】:您可以从字典中构建一个trie 并遍历它。对于输入字符串中的每个字符,到trie中对应的节点,从输入中删除该字符,递归重复。
伪代码:
function check(trie_node)
if trie_node is terminal
output trie_node
else
for each child of trie_node
let c be the character of the child
if input contains at least one c
remove one c from input
check(child)
put c back into input
end
end
end
end
check(trie_root)
您可以使用查找表快速检查输入中还剩下多少特定字符(恒定时间检查)。
【讨论】:
这是一个 Java Trie 实现:trie.googlecode.com/svn/trunk/trie/src/net/bcharris/trie(根据 Apache 许可证 2.0 许可的代码:apache.org/licenses/LICENSE-2.0。)【参考方案2】:我会通过首先将您的所有词典统一到一个巨型词典中来解决此问题,然后对您构建的词典中的字母和您正在搜索的名为 searchWord 的子集的单词进行排序。
我会做这样的事情
String findAllScrabbleWords (String searchWord)
searchWord = searchWord.sortLetters();
Dictionary<String,List<String>> wordlist = new Dictionary <String, List<String>>()
foreach file in fileList
foreach word in file
sortedword = word.sortLetters();
// Add a new key if it isn't there then add the new word
if (!wordlist.containsKey(sortedword))
wordlist[sortedword] = new List<String>();
wordlist[sortedword].add(word);
end
// Now search for the words.
return findScrabbleWords ("", sortedword, wordList);
end
// We do this recursively so we don't have to worry about how long the search
// string is.
String function findScrabbleWords (String headString, String tailString, Dictionary<String,List<String>> wordList)
if (tailString == "")
return "";
end
String returnValue = "";
for (pos = 0; pos < tailString.length; pos++)
// Add an element of the tail to the current string and remove
// that letter from the tail.
String currString = headString + tailString[pos];
String remainderString = tailString.removeAt(pos,1);
if (wordList.containsKey(currString))
foreach word in wordList[currString]
returnValue += word + " ";
end
end
// Now check the strings that contain the new currString
returnValue += findScrabbleWords(currString,remainderString,wordList);
end
return returnValue;
end
【讨论】:
【参考方案3】:您的问题归结为以下基本算法:
生成给定集合的所有可能子集 使用bitfield counter 最容易完成 生成集合的所有排列 Pseudocode description and diagram A more specific implementation for .NET strings我还应该注意,您当前代码的一个问题是您所有的内部循环都从 0 开始,这是不正确的。这就是生成“AA”的原因(因为您最终会返回索引 0 的字符两次)。
Java 中的位域计数器
package com.***.samples;
import java.lang.String;
public class Main
public static void main(String[] args)
String input = "ABCDE";
printAllSubsets(input);
private static void printAllSubsets(String input)
int n = input.length();
int last = 2 << n;
char[] subset = new char[n];
for (int bits = 0; bits < last; ++bits)
int j = 0;
for (int i = 0; i < n; ++i)
if (bitIsSet(bits, i))
subset[j] = input.charAt(i);
++j;
printSubset(subset, j);
private static void printSubset(char[] subset, int n)
System.out.print('');
for (int i = 0; i < n; ++i)
System.out.print(subset[i]);
System.out.println('');
private static boolean bitIsSet(int bits, int position)
return ((bits >> position) & 1) == 1;
【讨论】:
对不起。我不完全确定你的意思。目前,我的 Java 知识相当……有限。 我回答的哪一部分你有问题? 位域计数器,不确定它是如何工作的或做什么的。 好的,假设你有一个输入字符串 ABC。可能的子字符串(包括空字符串和字符串本身)是 、A、B、C、AB、AC、BC、ABC。请注意,在 3 个元素集中有 2^3 = 8 个子集。如果你仔细想想,你会发现你可以通过从 0 到 7 的二进制数来生成这些子集:000, 001, 010, 011, 100, 101, 110, 111。1 代表一个字母,0 表示没有字母,所以 110 是“AB”,101 是“AC”。 您能举例说明如何在 Java 中实现这一点吗?我很确定我理解它背后的逻辑。【参考方案4】:在 Python 中:
import itertools
mystring = "ABCDEFG"
for perm in itertools.permutations(mystring):
print "".join(perm)
如果你想看算法,看看source/docs:
def permutations(iterable, r=None):
# permutations('ABCD', 2) --> AB AC AD BA BC BD CA CB CD DA DB DC
# permutations(range(3)) --> 012 021 102 120 201 210
pool = tuple(iterable)
n = len(pool)
r = n if r is None else r
if r > n:
return
indices = range(n)
cycles = range(n, n-r, -1)
yield tuple(pool[i] for i in indices[:r])
while n:
for i in reversed(range(r)):
cycles[i] -= 1
if cycles[i] == 0:
indices[i:] = indices[i+1:] + indices[i:i+1]
cycles[i] = n - i
else:
j = cycles[i]
indices[i], indices[-j] = indices[-j], indices[i]
yield tuple(pool[i] for i in indices[:r])
break
else:
return
【讨论】:
【参考方案5】:Jon Bentley 的书Programming Pearls 有一个很好的例子来说明字谜,我相信你可以适应它。请参阅code for column 2(或者更好地抓住这本书!)。
我将在这里勾勒出一个实现:
1) 浏览字典,为每个单词按顺序排列字母(例如 fish 会变成“fihs”,“donkey”会变成“dekony”。这个键可以让您查找所有可以查找的单词由这一系列字母组成。将此信息存储在数据结构 Map
3) 现在,当您要查找单词时,如上所述对机架中的字母序列进行排序并查询地图(例如,在您制作的地图中查找键)。这将为您提供由该系列字母组成的所有可能单词的列表。
您需要稍微调整一下 Scrabble,因为原始算法是针对字谜的,但它应该像多次查询地图一样简单(例如,如果您有字母 dayvgea,那么您不需要查询仅适用于 aadgeyv,但也适用于 6 个字母及以下的每个组合。不同的 combinations of 7 items 的数量只有 128 个,因此要找到最佳单词,您只需要在数据结构中查找固定次数。
【讨论】:
请注意,这与约翰在另一个答案中使用的想法相同!【参考方案6】:感谢您提供的所有帮助。我采用了一种更简单的方法,如下所示:它似乎非常有效,但我仍计划研究您提出的所有替代方案。
public class Unscramble
public final static String letters = JOptionPane.showInputDialog("Please input your tiles").toLowerCase();
public static LinkedList<String> words = new LinkedList();
public static void main(String[] args) throws FileNotFoundException, IOException
checkWords(new FileReader("ospd3.txt"));
for(int i = 0; i < words.size(); i++)
System.out.println(words.get(i));
private static void checkWords(FileReader dict) throws IOException
BufferedReader bf = new BufferedReader(dict);
String line = "";
while((line = bf.readLine()) != null)
if(hasWord(line))
words.add(line);
bf.close();
dict.close();
public static boolean hasWord(String word)
String copy = letters;
for(int u = 0; u < word.length(); u++)
if(copy.contains(String.valueOf(word.charAt(u))))
copy = copy.replaceFirst(String.valueOf(word.charAt(u)), "");
else
return false;
return true;
【讨论】:
以上是关于拼字游戏字谜生成器的主要内容,如果未能解决你的问题,请参考以下文章