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 在 算法 中排名
每月下载量 578 次
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
- 将分数预计算从
MaxEliminationsScorer
和MaxComboEliminationsScorer
构造移动到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
中的错误以改进其结果
解决效率基准测试
不同的猜测算法已经与几个单词列表进行了基准测试
-
wordle-answers.txt
:这个列表包含了在被纽约时报收购之前所有来自 Wordle 的答案单词。 -
improved-words.txt
:这个列表结合了来自58,000多个英语单词的Corncob单词列表、MIT 10,000英语单词列表以及任何剩余的Wordle答案单词。这通常被用来代替完整的Wordle单词列表,因为许多允许的Wordle单词似乎有些不合逻辑。
大多数算法都针对整个 改进 单词列表进行了基准测试。一些算法以两种配置运行
- 从
PossibleWords
进行猜测,即只猜测仍然可能的单词。这相当于Wordle的“困难”模式。 - 从
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) - 如果字母不存在于此处:
could
和coast
被移除,所以: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分钟。
组合限制:256 和 GuessFrom::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
组合限制:256 和 GuessFrom::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