Python RegEx- hangman算法

时间:2011-06-14 05:31:52

标签: python regex algorithm dictionary

我正在尝试编写一个hangman算法。我的想法是这样的:

  • 预处理包含单词的相对字母频率的字典,具体取决于其长度。一步完成。

示例:

#Each key corresponds to length of the word.   

frequencyDict = {2: ['a', 'o', 'e', 'i', 'm', 'h', 'n', 'u', 's', 't', 'y', 'b', 'd', 'l', 'p', 'x', 'f', 'r', 'w', 'g', 'k', 'j'], 
  3: ['a', 'e', 'o', 'i', 't', 's', 'u', 'p', 'r', 'n', 'd', 'b', 'm', 'g', 'y', 'l', 'h', 'w', 'f', 'c', 'k', 'x', 'v', 'j', 'z', 'q'], 
  4: ['e', 'a', 's', 'o', 'i', 'l', 'r', 't', 'n', 'u', 'd', 'p', 'm', 'h', 'b', 'c', 'g', 'k', 'y', 'f', 'w', 'v', 'j', 'z', 'x', 'q'],
  5: ['s', 'e', 'a', 'o', 'r', 'i', 'l', 't', 'n', 'd', 'u', 'c', 'p', 'y', 'm', 'h', 'g', 'b', 'k', 'f', 'w', 'v', 'z', 'x', 'j', 'q'],
  6: ['e', 's', 'a', 'r', 'i', 'o', 'l', 'n', 't', 'd', 'u', 'c', 'p', 'm', 'g', 'h', 'b', 'y', 'f', 'k', 'w', 'v', 'z', 'x', 'j', 'q'],
  7: ['e', 's', 'a', 'i', 'r', 'n', 'o', 't', 'l', 'd', 'u', 'c', 'g', 'p', 'm', 'h', 'b', 'y', 'f', 'k', 'w', 'v', 'z', 'x', 'j', 'q'],
  8: ['e', 's', 'i', 'a', 'r', 'n', 'o', 't', 'l', 'd', 'c', 'u', 'g', 'p', 'm', 'h', 'b', 'y', 'f', 'k', 'w', 'v', 'z', 'x', 'q', 'j']}

我在字典中也有一个单词生成器:

dictionary = word_reader('C:\\Python27\\dictionary.txt', len(letters))

基于此功能

#Strips dictionary of words that are too big or too small from the list
def word_reader(filename, L):
  L2 = L+2
  return (word.strip() for word in open(filename) \
          if len(word) < L2 and len(word) > 2)
  • 这个特殊的游戏将免费提供最后一个元音。例如,如果这个词是土制的, 用户将被给予以下板:e ---- e-猜测。所以,我想找到一种方法来创建一个新的生成器或列表 所有被剥离的单词都不符合e ---- e-模板。

p = re.compile('^e\D\D\D\De\D$', re.IGNORECASE)会这样做,但它可能会找到单词 在第一个字母和倒数第二个字母之外的其他地方包含'e'。

所以我的第一个问题是:

  1. 我如何确保'e' 仅位于第一和第二 倒数第二的位置
  2. 如何创建一个具有新正则表达式的智能功能,因为拼图会更新并且计算机会不断猜测?
  3. 例如,如果单词是monkey,那么计算机就会被给出---- e- 第一步是从字典中删除所有不是6个字母的单词,以及所有不完全符合'---- e-'模板并将其放在newList中的单词。 怎么做 我这样做了吗?

    然后根据其中的单词的相对频率计算一个新的frequencyDict newList。

    我目前的做法是这样的:

       cnt = Counter()
       for words in dictionary:
          for letters in words:
             cnt[letters]+=1
    

    这是最有效的方式吗?

    然后它将使用newfrequencyDict猜测最常见的字母,假设它有 还没有被猜到。它继续这样做,直到(希望)这个词被猜到。

    这是一种有效的算法吗?是否有更好的实施?

2 个答案:

答案 0 :(得分:3)

这是很多问题。我会尝试回答一些问题。

  1. 你的正则表达式应该更像这样:'^e[^e][^e][^e][^e]e[^e]$'。那些[^e]位说“匹配任何不是'e'的字符。请注意,与正则表达式不同,这个 mach非字母字符,但如果你不应该是一个问题确保你的字典只有字母。请注意,一旦你发现了多个字母,你就会将所有字母放入每个“不匹配”部分。例如,假设'a'被猜到了,所以它是“ea --- e-”,现在你将匹配正则表达式“^ea[^ae][^ae][^ae]e[^ae]$”。
  2. 你可以简单地编写一个带有字符串的函数,例如“ea --- e-”并从中构建一个正则表达式。它只需要a)找到字符串中的所有非连字符,作为一个集合(在这种情况下,{'a', 'e'}),b)将该集合展平为“匹配所有但是这个”正则表达式片段([^ae]) - 请注意,顺序并不重要,这就是为什么我使用了一个集合,c)用其中一个(ea[^ae][^ae][^ae]e[^ae])替换每个连字符,并且d)最后只是放了一个前面是“^”,最后是“$”。
  3. 最后用频率字典 - 这是一个非常独立的问题。通过整个字典进行线性搜索很难获得更高的效率。我要提出的一个建议是,你可能不应该多次计算字母数。例如,您是否希望“earthen”这个词为'e'的字母数贡献2分?我想在Hangman你只想要它算一次,因为单词“eeeeeeee”和单词“the”都有相同的结果来猜测字母'e'(成功)。但我可能错了。

答案 1 :(得分:2)

关于正则表达式并没有什么特别神奇之处,并且将它们与整个字典相匹配仍然需要花费O(n)时间。我建议你编写自己的函数,确定一个单词是否与模板匹配,并运行你的字典 - 远远不够。

这是一个示例函数:

def matches_template(word, template):
  found_chars = set(x for x in template if x != '-')
  for char, template_char in zip(word, template):
    if template_char == '-':
      if char in found_chars: return False
    else:
      if template_char != char: return False
  return True

至于确定要猜测的下一个字符,您可能不希望选择最常用的字符。相反,你想要选择最接近50%单词的字符,这意味着无论哪种方式都消除了最多的可能性。即使这不是最佳的 - 可能是某些字符更有可能在单词中出现两次,因此消除了更大比例的候选人 - 但它更接近。