#wordle-solver #wordle #puzzle-solver #solver #guess #game #puzzle

rs-wordle-solver

一个用于解决 Wordle 风格谜题的库。它提供了多种猜测算法,以及实现您自己的 Wordle 解决算法的构建块。

8 个版本 (3 个稳定版)

1.2.0 2024年5月1日
1.1.0 2024年3月17日
0.3.0 2023年11月22日
0.2.0 2023年5月20日
0.1.1 2022年4月3日

170算法 中排名

Download history 99/week @ 2024-04-26 27/week @ 2024-05-03 2/week @ 2024-05-17 3/week @ 2024-05-24 1/week @ 2024-06-28 3/week @ 2024-07-05

每月下载量 578 次

MIT/Apache

135KB
2K SLoC

rs-wordle-solver

用于解决流行游戏《Wordle》的自动解决库。

如何使用它?

请参阅 文档

版本

1.2.0

本版本的主要目标是支持在中途更改 GuessFrom 值,而无需创建全新的 Guesser。构造函数中提供的 GuessFrom 值现在作为默认值使用,除非显式指定。

  • 添加 Guesser::select_next_guess_from 以从特定的 GuessFrom 列表中选择猜测。
  • 添加 MaxScoreGuesser::select_top_n_guesses_from 以从特定的列表中选择顶级猜测。
  • 添加 MaxScoreGuesser::compute_scores_if_needed_from 以缓存特定列表的分数。

1.1.0

  • 添加 MaxScoreGuesser::get_or_compute_scores 以提取预先计算的单词分数。
  • 添加 MaxScoreGuesser::with_scores 以使用提取的/否则预先计算的单词分数。
  • MaxScoreGuesser::with_parallelisation_limit 更改为接受和返回 Self 的构建函数,而不是作为替代构造函数。

1.0.0

  • 将分数预计算从 MaxEliminationsScorerMaxComboEliminationsScorer 构造移动到 MaxScoreGuesser
  • 除非调用 MaxScoreGuesser::compute_scores_if_unknown,否则分数预计算现在是懒加载的。
  • 并行化限制现在可以由用户修改,并且应用得更加一致。默认限制已降低。
  • 一些构造函数接受一个拥有对象而不是引用,即使它们需要克隆该对象。
  • MaxScoreGuesser 在解决平局时试图优先考虑可能的单词。
  • 许多其他重大变更。

0.3.0

  • 添加 MaxEliminationsScorer::from_first_guess_eliminations::first_guess_eliminations。这对于有效地序列化和反序列化此结构的重要部分特别有用。
  • 调整 WordBank::from_reader::from_iterator 的实现。

0.2.0

  • 使用 Rayon 启用并行化

    • 并行化 MaxEliminationsScorer::new 的关键部分
    • 并行化 MaxComboEliminationsScorer::new 的关键部分
    • 并行化 MaxScoreGuesser::select_next_guess::select_top_n_guesses
  • WordScorer::score_word 的参数从 &self 改为 &mut self

  • 修复 MaxComboEliminationsScorer 中的错误以改进其结果

解决效率基准测试

不同的猜测算法已经与几个单词列表进行了基准测试

大多数算法都针对整个 改进 单词列表进行了基准测试。一些算法以两种配置运行

  1. PossibleWords 进行猜测,即只猜测仍然可能的单词。这相当于Wordle的“困难”模式。
  2. AllUnguessedWords 进行猜测,包括不能作为答案的单词。这通常更好,因为算法能够更快地排除更多单词。

RandomGuesser

这从仍然可能的单词中随机选择。这是一个基线最坏情况选择。任何其他算法都应该比这更好。

一个示例基准测试

猜测次数 游戏次数
1 1
2 106
3 816
4 1628
5 1248
6 518
7 180
8 67
9 28
10 7
11 2
12 1

平均猜测次数 4.49 +/- 1.26

MaxUniqueLetterFrequencyScorer

这是一个相当简单的选择器。它选择最大化尚未猜测的独特字母频率总和的单词。

GuessFrom::PossibleWords

猜测次数 游戏次数
1 1
2 137
3 1248
4 1831
5 830
6 321
7 135
8 63
9 26
10 7
11 1
12 1
13 1

平均猜测次数:4.17 +/- 1.24 平均每场比赛持续时间:0.224ms +/- 0.058ms

GuessFrom::AllUnguessedWords

猜测次数 游戏次数
1 1
2 32
3 1045
4 2268
5 1037
6 194
7 23
8 2

平均猜测次数:4.08 +/- 0.83 平均每场比赛持续时间:0.491ms +/- 0.114ms

LocatedLettersScorer

此方法根据字母在可能单词中的存在和位置选择得分最高的单词。每个字母的得分计算后再相加。每个字母的评分如下。

对于每个字母,评分

  • 如果字母必须位于这个位置,则加1分。

  • 如果字母的位置尚不明确,并且这是字母的新位置,则每个包含此字母的单词加1分。

  • 如果这个字母是全新的

    • 如果这个字母在此单词中尚未评分

      • 如果字母在此位置,则每个可能的单词加1分。
      • 如果字母在其他位置,则每个可能的单词加1分。
    • 否则

      • 如果字母在此位置,则每个可能的单词加1分。

GuessFrom::PossibleWords

猜测次数 游戏次数
1 1
2 180
3 1448
4 1836
5 720
6 255
7 100
8 44
9 12
10 4
11 1
12 1

平均猜测次数:4.00 +/- 1.15 每次游戏的平均持续时间:0.211ms +/- 0.040ms

GuessFrom::AllUnguessedWords

猜测次数 游戏次数
1 1
2 128
3 1599
4 1924
5 638
6 199
7 75
8 25
9 9
10 2
11 1
12 1

平均猜测次数:3.91 +/- 1.04 每次游戏的平均持续时间:0.491ms +/- 0.117ms

MaxApproximateEliminationsScorer

此方法选择预期将消除最多其他单词的单词。对于每个字母,计算每个可能状态下的预期消除数量

  • 在状态下的预期消除单词数量 * 匹配此状态的可能单词的分数

例如,对于单词 ["could", "match", "coast"],以下是对单词 could 中的字母 c 的计算:

  • 如果正确:match 被移除,所以:1 * (2/3)
  • 如果字母不存在于此处:couldcoast 被移除,所以:2 * (1/3)
  • 如果字母不存在:所有单词都被移除,所以:3 * (0/3)(注意:如果此字母* 已在另一个位置检查过),则此期望被跳过)。

然后将每个字母的期望值相加,以得到单词的期望值。以这种方式近似期望消除是一种计算成本低的方法,但稍微不太准确,因此效果略差,不如使用 MaxEliminationsScorer 计算的确切计数。

GuessFrom::PossibleWords

猜测次数 游戏次数
1 1
2 180
3 1430
4 1846
5 721
6 258
7 105
8 41
9 13
10 5
11 1
12 1

平均猜测次数:4.01 +/- 1.15 每次游戏的平均持续时间:0.210ms +/- 0.041ms

GuessFrom::AllUnguessedWords

猜测次数 游戏次数
1 1
2 73
3 1331
4 2486
5 655
6 53
7 3

平均猜测次数:3.85 +/- 0.72 每次游戏的平均持续时间:0.503ms +/- 0.106ms

MaxEliminationsScorer

此方法概率计算每个猜测将消除多少单词的期望值,并选择消除最多其他猜测的单词。这相对较难计算,因此它会在评分器首次创建时尽可能预计算。在我的机器上,使用改进的单词列表构建评分器大约需要120ms,但这使得每次后续游戏可以在大约4ms内完成。

GuessFrom::PossibleWords

猜测次数 游戏次数
1 1
2 180
3 1476
4 1928
5 653
6 223
7 93
8 33
9 10
10 4
11 1

平均猜测次数:3.95 +/- 1.10 每次游戏的平均持续时间:0.342ms +/- 0.190ms

GuessFrom::AllUnguessedWords

猜测次数 游戏次数
1 1
2 73
3 1616
4 2474
5 419
6 19

平均猜测次数:3.72 +/- 0.67 每次游戏的平均持续时间:3.578ms +/- 2.608ms

MaxComboEliminationsScorer

此方法扩展了 MaxEliminationsScorer,以便选择在下一个两个猜测中应最大化消除单词数量的单词,前提是有超过特定限制的可能单词数量。我们将此称为 combo limit。一旦剩余的可能单词数量少于 combo limit,则此方法将回退到 MaxEliminationsScorer 的行为。

此评分器的理论基础是,由于大多数单词至少需要3次猜测,评分器应尝试在第一次和第二次猜测中集体消除尽可能多的单词。这与在MaxEliminationsScorer中每轮选择最佳单个单词的方法可能不同。

这计算起来非常昂贵,因为它大约以O(n3)的比例扩展,其中n是单词库中的单词数量。使用PossibleWords计算包含4600个单词的第一个猜测的分数需要大约2.5分钟,使用AllPossibleWords则需要14分钟。

组合限制:256GuessFrom::PossibleWords

猜测次数 游戏次数
1 1
2 148
3 1508
4 2034
5 617
6 179
7 75
8 27
9 9
10 2
11 2

平均猜测次数:3.91 +/- 1.03 平均每局游戏持续时间:40.549ms +/- 84.745ms

组合限制:256GuessFrom::AllUnguessedWords

猜测次数 游戏次数
1 1
2 83
3 1587
4 2556
5 353
6 22

平均猜测次数:3.70 +/- 0.65 平均每局游戏持续时间:6111.912ms +/- 23946.495ms

速度基准

RandomGuesser

test bench_guess_random_improved_words                             ... bench:     134,544 ns/iter (+/- 13,317)
test bench_guess_random_wordle_words                               ... bench:     360,913 ns/iter (+/- 48,680)

MaxUniqueLetterFrequencyScorer

test bench_unique_letters_improved_words                           ... bench:   1,572,994 ns/iter (+/- 516,087)

LocatedLettersScorer

test bench_located_letters_improved_words                          ... bench:   1,575,697 ns/iter (+/- 512,853)

MaxApproximateEliminationsScorer

test bench_max_approximate_eliminations_improved_words             ... bench:   1,595,036 ns/iter (+/- 839,135)

MaxEliminationsScorer

test bench_max_eliminations_scorer_precompute_improved_words       ... bench: 404,998,819 ns/iter (+/- 7,069,306)
test bench_max_eliminations_scorer_with_precomputed_improved_words ... bench:  10,699,991 ns/iter (+/- 10,244,686)

MaxComboEliminationsScorer

在改进的单词上预计算大约需要:41分钟(从所有单词猜测)或3.5分钟(从可能单词猜测)。解决单个单词大约需要:10秒(从所有单词猜测)或0.16秒(从可能单词猜测)

依赖关系

~2MB
~34K SLoC