【问题标题】:Algorithm to choose random letters for word search game that allows many words to be spelled为单词搜索游戏选择随机字母的算法,允许拼写许多单词
【发布时间】:2011-01-17 02:37:51
【问题描述】:

我正在制作类似boggle 的文字游戏。给用户一个像这样的字母网格:

O V Z W X
S T A C K
Y R F L Q

用户使用任何相邻的字母链来挑选一个单词,例如中间行的单词“STACK”。然后使用的字母被机器替换,例如(新的小写字母):

O V Z W X
z e x o p
Y R F L Q

请注意,您现在可以使用新字母拼写“OVeRFLoW”。我的问题是:我可以使用什么算法来挑选新字母,以最大限度地增加用户可以拼写的长单词的数量?我希望游戏有趣并涉及拼写,例如有时是 6 个字母的单词,但如果你选择了不好的字母,游戏会让用户只拼出 3 个字母的单词,而没有机会找到更大的单词。

例如:

  • 您可以从字母表中随机选择新字母。这效果不好。

  • 同样,我发现随机选择但使用 Scrabble 中的字母频率效果不佳。我认为这在拼字游戏中效果更好,因为您对使用字母的顺序没有那么严格。

  • 我尝试了一组列表,每个列表代表 Boggle 游戏中的一个骰子,每个字母将从随机骰子一侧挑选(我也想知道我是否可以在产品中合法使用这些数据)。我没有注意到这运作良好。我想 Boggle 骰子的面是以某种明智的方式选择的,但我不知道这是如何做到的。

我考虑过的一些想法:

  • 制作一个表格,说明字典中字母对出现的频率。为了争论起见,假设 E 在 30% 的时间出现在 A 旁边。在挑选新信时,我会根据网格上随机选择的相邻字母旁边发生此字母的频率随机选择一封信。例如,如果相邻字母是 E,则新字母将有 30% 的时间是“A”。这应该意味着有很多不错的对散布在地图上。我可以通过制作一个字母出现在其他两个字母之间的概率表来改进这一点。

  • 以某种方式搜索当前网格上可以拼写的单词,将新字母作为通配符。然后我会用允许拼写最大单词的字母替换通配符。但是,我不确定您将如何有效地做到这一点。

任何其他想法表示赞赏。我想知道是否有解决这个问题的通用方法以及其他文字游戏使用什么。

编辑:感谢到目前为止的精彩回答!我忘了提一下,如果可能的话,我的目标是低内存/cpu 要求,我可能会使用 SOWPODS 字典(大约 250,000),我的网格将能够达到 6 x 6。

【问题讨论】:

  • 我喜欢你使用字母并置概率的想法。您可以进一步扩展它:对于任何给定的字母位置,计算每个字母与其紧邻的字母相邻的概率,并将这些概率平均为一个,然后使用平均概率作为权重选择一个随机字母。

标签: java algorithm computer-science linguistics


【解决方案1】:

这里有一个简单的方法:

使用玩家将使用的相同单词列表为游戏编写一个快速求解器。随机生成 100 个不同的可能板(在这里使用字母频率可能是个好主意,但不是必需的)。对于每个棋盘,计算所有可以生成的词,并根据找到的词数或按词长加权的计数(即找到的所有词的词长总和)对棋盘进行评分。然后从 100 种可能性中选出最好的计分板,然后将其交给玩家。

此外,您可以设置不同的分数阈值,而不是总是选择得分最高的棋盘(即最简单的棋盘),以使游戏对专家来说更加困难。

【讨论】:

  • 谢谢。这可能是您可以使用的最防弹的想法,例如保证(大多数时候)总会有一定数量的大词可供选择。我的板子是 6x6,使用 trie 会占用太多内存,所以我不确定如何有效地使用它。
  • 如果您有记忆,使用单词前缀列表 (trie) 将提供最佳性能。如果您存储压缩的 trie,您可能可以在几 MB 内创建适合完整的 trie,我猜。如果没有,您可能仍然可以在内存中获得长度为 5 的单词前缀列表,然后切换到完整单词列表的二进制(或插值)搜索以检查长度超过 5 的匹配项。或者......将前缀计数长度为 5,并假设大量小的部分词很可能会在不明确检查长词的情况下产生长词。
  • 如果您有胆量,可以使用存储在数组中的 DAWG。在这里可以找到来自斯坦福的精彩视频讲座:youtube.com/watch?v=TJ8SkcUSdbU 简短的故事是她设法在 0.32 MB 中存储了 250,000 个单词
  • 如果您可以将此求解工作推送到单独的线程,则求解器可以在用户玩游戏时继续工作。这将使您的求解器有更多时间工作。
【解决方案2】:

字母对方法的一个小变化:在长词中使用字母对的频率——比如 6 个字母或更长——因为这是你的目标。您还可以开发一个包含所有相邻字母的权重,而不仅仅是一个随机字母。

【讨论】:

  • 很高兴使用 6 个字母的长词!我考虑过使用三元组(只考虑 3 个字母对的频率),但你的想法听起来更接近我真正想要的。
【解决方案3】:

This wordgame前阵子我打了一巴掌,和你描述的非常相似,使用英文频率表来选择字母,但首先决定是生成元音还是辅音,让我确保给定的元音率在板上。这似乎工作得相当好。

【讨论】:

  • 谢谢。你用什么来计算元音/辅音率?我的感觉是,在每个局部 2x2 网格中,您可能应该至少有一个元音。否则,您可能会在无法在单词中使用的角落中获得“被困”的辅音组。您是否仅使用常规字母频率表而不是例如成对的字母频率?
  • @Bobby:因为棋盘在每个单词之后都会发生变化,玩家可以随着时间的推移“切掉”难懂的字母——人们可能会认为这是游戏策略的一部分。元音/辅音比率硬连线为 0.559 - 我通过收集我身边的一些电子书的统计数据获得了该值和字母频率:)
  • 好的,谢谢。我实际上已经用下降行为测试了我的游戏,但我发现当底部的字母不是很好时,玩家往往会忽略底部的字母并且他们将所有时间都花在顶部。我在想不知何故从四面八方落下的信件。或者要求处理旧信件。此外,落下的字母使例如固定局部网格位置的元音数量。不过我可能想多了。 :) 如果例如,我会非常喜欢它。每个网格中至少有一个长词,以便专家们炫耀。
【解决方案4】:

您应该查看 n 语法和马尔可夫模型。

您的第一个想法与马尔可夫算法非常相关。 基本上,如果你有一个大的文本语料库,比如说 1000 个单词。您可以做的是分析每个字母并创建一个表格,以了解某个字母跟随当前字母的概率。

例如,我知道我的 1000 个单词(总共 4000 个字母)中的字母 Q 只使用了 40 次。然后我使用我的马尔可夫哈希表计算可能的字母。

例如, QU 发生 100% 的时间,所以我知道 Q 是否应该由您的应用程序随机选择,我需要确保字母 U 也包括在内。 然后,50% 的时间使用字母“I”,25% 的时间使用“A”,25% 的时间使用“O”。

实际上解释起来真的很复杂,我敢打赌还有其他解释比这个要好得多。

但想法是,给定一个合法的大型文本语料库,您可以创建一个 X 字母链,这些字母可能与英语一致,因此用户应该很容易从中造词。 您可以选择期待 n-gram 的值,数字越大,您的游戏就越容易。例如,一个 2 的 n-gram 可能很难创建超过 6 个单词,但一个 4 的 n-gram 会很容易。

维基百科对它的解释非常糟糕,所以我不会这样做。

看看这个马尔可夫发生器:

http://www.haykranen.nl/projects/markov/demo/

【讨论】:

  • 谢谢,听起来很有趣。你能详细说明一下 n-gram of 4 的想法吗?我会不会例如选择一个相邻的 4 个字母链,例如“C-H-A-N”,靠近我的随机字母位置,然后让一张桌子选择一个通常跟随 3 个字母“CHAN”的字母,例如“G”和“CHANGING”一样吗?
  • 我一直害怕马尔可夫链。主要的 wiki 文章令人困惑,但这篇相当不错:en.wikipedia.org/wiki/Examples_of_Markov_chains
  • n-gramming 就是您将某物分解为 N 克数的地方。例如,在 1-gram 上,单词 Boggle 是 1 gram BOGGLE 2-gram(通常称为二元组)它将是 B BO OG GG GL LE E 3-gram(通常称为三元组)它将是 B BO BOG OGG GGl GLE LE E 在 4-gram 上(仅称为 n-gram)它会是 B BO BOG BOGG OGGL GGLE GLE LE E 你可以看到如果你使用带有特定 n-gram 的马尔可夫链,你可以将特定的常见分组出现的字符序列。顺便说一句,随着你增加 n-gram,你会发现游戏变得更容易了。
【解决方案5】:

我不知道这方面的预设算法,但是...

在 UNIX 中有一个字典文件,我想在其他平台上也有类似的东西(甚至可能在 java 库中? - 谷歌它)。无论如何,请使用拼写检查器使用的文件。

在他们拼出一个单词后,它会丢失,你有现有的字母和空格。

1) 从每个现有的字母开始,向右、向左、向上、向下(您需要了解递归算法)。只要在字典文件中的单词开头或从单词结尾向后找到您到目前为止构建的字符串,就继续。当你遇到一个空格时,数一数你接下来需要的字母出现的频率。使用最常用的字母。

它不能保证一个单词,因为你没有检查相应的结尾或开头,但我认为它比穷举搜索更容易实现并得到很好的结果。

【讨论】:

  • 你能举一个简短的例子吗?我不确定这会如何工作。
【解决方案6】:

我认为这会让您离目的地更近一步:http://en.wikipedia.org/wiki/Levenshtein_distance

【讨论】:

    【解决方案7】:

    您可以查看Jumble algorithm 中的Java implementation 来查找可置换为多个字典单词的字母集:

    $ java -jar dist/jumble.jar |排序-nr |头 11 Orang Ronga angor argon goran grano groan nagor orang organ rogan 10 Elaps Lepas Pales 失效 salep saple sepal slape spale speal 9 酯 estre reest 重置 steer stere stree terse tsere 9 caret carte 满足 crate crate creat creta react recta trace 9 Easter Eastre asteer Easter reseat saeter seater staree teaser 9 Canari Carian Crania acinar 山金车 canari carina crania narica 8 jumpt palet patel pelta 花瓣盘 褶皱 tepal 8 laster lastre rastle relast resalt salter slater stelar 8 Trias arist astir Sitar 楼梯 stria tarsi tisar 8 Trema armet mater metra ramet tamer terma trame ...

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-06-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-03-18
      相关资源
      最近更新 更多