使用 Linux 命令行解决Wordle 问题
使用 Linux 的 grep 命令和 fgrep 命令解开你喜欢的单词猜谜游戏。
我最近有点迷上了一个在线文字游戏,在这个游戏中,你有六次机会来猜一个随机的五个字母的单词。这个词每天都在变化,而且你每天只能玩一次。每次猜测后,你猜测中的每个字母都会被高亮显示:灰色表示该字母没有出现在神秘的单词中,黄色表示该字母出现在单词中,但不在那个位置,绿色表示该字母出现在该单词的正确位置。
以下是教你如何使用 Linux 命令行来帮助你玩猜谜游戏,如 Wordle。我用这个方法帮助我解决了1月6日的谜题:
第一次尝试
Linux 系统在 /usr/share/dict/words 文件中保存了一个单词词典。这是一个很长的纯文本文件。我系统的 words 文件有超过479800个条目。该文件既包含纯文字,也包含专有名词(名字、地点等等)。
为了开始我的第一个猜测,我只想要一个正好是五个字母长度的纯文字列表。要做到这点,我使用了 grep 命令:
$ grep '^[a-z][a-z][a-z][a-z][a-z]$' /usr/share/dict/words > myguess
grep 命令使用正则表达式进行搜索。你可以用正则表达式做很多事情,但为了帮助我解决 Wordle 问题,我只需要一些基础的知识点: ^ 表示行的开始, $ 表示行的结束。在这两者之间,我指定了5个 [a-z] 的实例,表示从 a 到 z 的任何小写字母。
我还可以使用 wc 命令看到可能的单词列表中“只有”15000个单词:
$ wc -l myguess
15034 myguess
从该列表中,我随机挑选了一个五个字母的单词: acres。 a 被设置为黄色,意味着该字母存在于神秘单词的某个位置,但不在第一位置。其他字母是灰色的,所以我知道它们不存在于今天的单词中。
第二次尝试
对于我的下一个猜测,我想得到一个包含 a,但不是在第一位置的所有单词的列表。我的列表也不应该包括字母 c, r, e 或 s。让我们把它分解为几个步骤:
为了得到所有带 a 的单词的列表,我使用 fgrep(fixed strings grep) 命令。 fgrep 命令也像 grep 一样搜索文本,但不使用正则表达式:
$ fgrep a myguess > myguess2
这使我下一个可能的猜测列表从15000字降为6600字:
$ wc -l myguess myguess2
15034 myguess
6634 myguess2
21668 total
但这个单词列表也包括了第一个位置的字母a,这是我不想要的。游戏已经表明字母 a 存在于其他位置。我可以用 grep 修改我的命令,寻找在第一个位置含有其他字母的词。这样我就把可能的猜测缩小到5500个单词:
$ fgrep a myguess | grep '^[b-z]' > myguess2
$ wc -l myguess myguess2
15034 myguess
5566 myguess2
20600 total
但我知道这个神秘的词也不包括字母 c、 r、 e 和 s,所以我可以用另一个 grep 命令从搜索中省略这些字母:
$ fgrep a myguess | grep '^[b-z]' | grep -v '[cres]' > myguess2
$ wc -l myguess myguess2
15034 myguess
1257 myguess2
16291 total
-v 选项表示反转搜索,因此 grep 将只返回不符合正则表达式 [cres] 或单列字母 c、 r、 e 或 s 的行。通过这个额外的 grep 命令,我已经将下一个猜测的范围大大缩小到只有1200个可能的单词,这些单词在某处有 a,但不在第一位置,并且不包含 c、 r、 e 或 s。
查看列表后,我决定尝试 balmy 这个词。
第三次尝试
这一次,字母 b 和 a 被高亮为绿色,这意味着我把这些字母放在了正确的位置。字母 l 是黄色的,所以这个字母存在于单词的其他地方,但不是在那个位置。字母 m 和 y 是灰色的,所以我可以在我的下一次猜测中排除这些。
为了确定我下一个可能的单词列表,我可以使用另一组 grep 命令。我知道这个词以 ba 开头,所以我可以从这里开始搜索:
$ grep '^ba' myguess2 > myguess3
$ wc -l myguess3
77 myguess3
这只有77个字!我可以通过寻找除第三位外还含有字母 l 的词来进一步缩小范围:
$ grep '^ba[^l]' myguess2 > myguess3
$ wc -l myguess3
61 myguess3
方括号[^l] 内的 ^ 意味着不是这个字母列表,所以不是字母 l。这使我的可能单词列降到61个,但并非所有单词都包含字母 l,我可以使用另一个 grep 搜索来消除字母 l:
$ grep '^ba[^l]' myguess2 | fgrep l > myguess3
$ wc -l myguess3
10 myguess3
其中一些单词可能含有字母 m 和 y,而这些字母并不在今天的神秘词中。我可以再进行一次倒置的 grep 搜索,把它们从我的猜测列表中删除:
$ grep '^ba[^l]' myguess2 | fgrep l | grep -v '[my]' > myguess3
$ wc -l myguess3
7 myguess3
我的可能词汇清单现在很短,只有7个词!
$ cat myguess3
babul
bailo
bakal
bakli
banal
bauld
baulk
我将选择 banal 作为我下一个猜测的单词,而这恰好是正确的。
正则表达式的力量
Linux 命令行提供了强大的工具来帮助您完成实际工作。 grep 和 fgrep 命令在扫描单词列表时提供了极大的灵活性。对于一个基于单词的猜谜游戏, grep 帮助确定了一个当天包含15000个可能的单词的列表。在猜测并知道哪些字母在神秘的单词中出现和没有出现之后, grep 和 fgrep 帮助将选项缩小到1200个单词,然后只剩下7个单词。这就是命令行的威力。
翻译:starstary
参考资料:Solve Wordle using the Linux command line