使用 Python 和 Rich 创建 Wordle 克隆

2025年3月17日 | 阅读18分钟

在本教程中,我们将为终端创建一个 Wordle 克隆版。自 Josh Wardle 于 2021 年 10 月首次发布 Wordle 以来,已有数百万人使用过它。虽然原版游戏可以在线玩,但我们将为我们的版本创建一个命令行应用程序,并利用 Rich 库赋予它一个漂亮的外观。

在完成这个循序渐进的项目时,您将获得设置基本原型游戏并将其迭代开发为可靠应用程序的经验。

什么是 Wordle?

Wordle 给你六次机会来找到一个隐藏的五个字母的单词。每次猜测后,你都会被告知哪些字母插入正确、位置错误和完全错误。

步骤 1:猜词

游戏看起来不会很好,而且很难解释玩家的反馈。但是,你的 Wordle 克隆版的基础已经就位。在这一步中,你将构建一个非常简单的猜词游戏。

你的用户可以对单词进行有根据的猜测,并了解他们正确放置了哪些字母,错误放置了哪些字母,以及哪些字母甚至不在单词中。

在这一阶段,你将使用 input() 来读取玩家提供的单词,使用 for 循环给他们多次猜测的机会,并使用集合来跟踪他们正确识别的字母。

通过 input() 获取用户数据

通过用户输入,你可以从他们那里获取信息。这个内置功能是在命令行上提供简单交互性的绝佳方式。

启动你的 REPL 并尝试一下。你应该写入

你可以使用可选的提示来请求输入。在输入任何数据之前,用户会看到这个提示。上面示例中高亮显示的行显示了用户输入和提示。提示用户猜测一个单词。用户输入 "python" 并点击 "Enter"。

调用 input 返回用户的文本输入。前面提到的情况,其中 "python" 被选为猜测词,说明了这一点。开始开发你的游戏永远不是一个坏主意。用你的编辑器创建文件 wyrdl.py 并填入以下详细信息

在读取用户的猜测后,你判断它是否与隐藏的单词 "python" 匹配。你评估他们的直觉,并告知他们准确与否。

你可能不认为这里有太多的游戏性。如果你认为它是一个游戏,它无疑是最沉闷和最令人沮丧的游戏之一。秘密单词每次都相同。因此没有太多的重玩价值。此外,用户无法根据反馈采取行动,因为他们无法从被纠正中学到任何东西。

你很快就会改变你的游戏,使其更有趣。本小节将通过解决一个小的可用性问题来完成。考虑以下游戏

在这种情况下,你正确地推断出秘密单词是 python。然而,游戏告诉你这是错误的,因为它将你的猜测与大写字符串 "PYTHON" 进行对比。这个游戏的目标是猜单词,而不是识别大写或小写字符。如何比较两个单词,无论大小写如何?

可能最简单的解决方案是明确地将猜测词更改为大写。之后,用户如何输入单词就无关紧要了

你添加的 .upper() 使所有用户的猜测都变成大写。这个修改立即提高了游戏的可用性。即使你用小写字母拼写 Python,现在也会被报告为正确。然而,你只允许用户进行一次正确的猜测。在下一节中,你将为你的游戏添加更多的猜测机会。

使用循环避免重复代码。

玩 Wordle 时,你最多有六次机会来选择正确的单词。为了达到同样的效果,你可以复制你已经创建的代码,并在你的游戏中包含六次。这样做是不明智的,原因有很多。最重要的是,它将难以维护且效率低下。

相反,你将使用循环来实现重复行为。Python 提供了 for 和 while 循环结构。在执行确定性迭代时,你通常使用 for,因为你预先知道要循环多少次。而 while,另一方面,非常适合无限迭代,当你不确定需要重复多少次任务时。

在这种情况下,你将使用 for 循环要求用户猜测单词六次。

你还通过迭代一个范围来计算猜测次数,并向用户显示该数字

一旦用户找到了答案,让他们继续猜测就没有意义了。如果用户选择了正确的单词,会使用 break 语句来提前退出循环。break 还有一个额外的好处,就是消除了对显式 else 的需求。只有当猜测正确时,你的代码才会继续运行。

为了使游戏可玩,是时候加入一些相关的用户反馈了。在下面的小节中,你将看到如何计算用户准确猜出的字母。

使用集合检查字母

到目前为止,用户只被告知他们是否正确猜出了这个词。你将对他们正确预测的具体字母进行评论,为他们提供一些线索,他们可以利用这些线索来找出隐藏的单词。每个字母将被你归入以下三组之一

  • 一个正确的字母可以在隐藏词和猜测词的相同位置找到。
  • 秘密单词包含一个位置错误的字母,但在不同的位置。
  • 隐藏的单词不包含不正确的字母。

你如何确定哪些字母属于不同的标题?首先,确定哪些字母的顺序是正确的。Python 的 zip() 方法在逐个元素比较两个序列时表现出色。在这种情况下,你正在比较两个字符串的字母

通过逐个字母比较 PYTHON 和 PROGRAM,你可以在此代码示例中识别出 PROGRAM 中两个位置错误的字符。尽管 O 在两个词中都存在,但由于其位置不同,所以没有被报告。

你现在必须收集字母而不是打印它们。Python 的推导式是强大的构建块,可以用来将一个或多个序列转换成另一个。在这种情况下,你将应用一个预先确定的理解来获得正确的字母

虽然它产生一个集合而不是一个列表,但集合推导式类似于列表推导式。因为它不关心正确字母的顺序,所以在这种情况下效果很好。

Python 对集合有强大的操作,这是它的优点之一。为了轻松找到存在于至少一个集合、两个集合或仅一个集合中的元素,可以使用两个集合之间的并集、交集和差集。

例如,如果你有两个字符串,你可以使用集合交集(&)来找到两个字符串中都出现的所有字母

你可以从交集中推断出 P 和 O 同时存在于 PYTHON 和 PROGRAM 中。集合差集也可以用来识别出现在一个集合中但不在另一个集合中的字母

PROGRAM 中的字母 N、Y、H 和 T 在 PYTHON 中不存在。

集合可以帮助你提高游戏水平。但是,在开始实现之前,你还要做一个调整。你目前在 if 测试中硬编码了秘密单词。在对字母进行分类时,你会用到那个词。使用以下常量来引用它

引入 WORD 后,更改秘密单词变得更容易。如果你在下一部分中提供一个单词列表,从中可以选择单词,游戏将更具吸引力。

现在你已经了解了集合,你可以计算并显示正确、错误和位置错误的字符。你应该更新你的代码以包含以下内容

你目前只列出了类别和字母。例如

虽然信息存在,但理解它并不总是那么简单。然而,下一步是使用单词列表添加一些变化。之后,你将改进游戏的用户界面,以提高视觉吸引力和玩家体验。

Utilize Python and Rich to Create a Wordle Clone

步骤 2:使用单词列表

即使游戏的外观没有改变,每次玩游戏时你都必须尝试识别一个不同的单词。在此阶段,你不会改变游戏的功能。但是,如果你提供一个单词列表,它会更有趣和可重玩。到目前为止,秘密单词一直是固定的。这种情况很快就会改变。

在此阶段,您将手动组建一个小词汇表并将其包含在您的游戏中。然后将介绍如何从任何文本创建词汇表。

手动创建一个单词列表

一个包含你的单词列表的纯文本文件每行会有一个短语。这延续了 Unix 系统上的一个悠久传统,即拼写检查器等应用程序使用一个名为 words 的文件。

创建一个名为 wordlist.txt 的新文件,并填入以下信息以开始

你已经包含了在前面阶段作为可能猜测所研究的单词。请随时添加到列表中。请不要在这上面花太多精力;单词列表很快会自动生成。

在制作一个更好的列表之前,你首先要考虑如何将这个单词列表读入你的软件中。Python 的 pathlib 模块非常适合处理各种文件并将其读入内存。可以测试一下吗?

使用 .read_text() 方法将整个文件读取为单个字符串。符号 \n 分隔单词。这些代表文件中的换行符。移除最后一个换行符并分割其余行以创建单词列表

你使用函数 .strip() 和 .split() 将文件转换为单词列表,并分别删除文件末尾的任何额外行。为了避免担心小写和大写字母,你将所有单词都转换为大写。

从单词列表中随机选择一个单词

Python 在标准库中包含了一个强大的 random 模块。你可以为你的项目产生各种随机性。在这种情况下,应用 random.choice() 从一个序列中随机选择一个项目

运行相同的代码,你可能会得到不同的结果。

是时候为你的 Wordle 克隆版添加单词列表功能了。对你的游戏进行以下更改

在你的脚本顶部,你已经包含了读取单词列表并从中选择一个随机单词的代码。你已经将 WORD 改为 word,因为秘密单词不再是常量了。

一个小小的缺点是,如果你猜错了单词,你的 Wordle 克隆版永远不会揭示它随机选择的秘密单词。通过在你的代码末尾包含下一步,你可以修复它。

尽管不常见,但在某些情况下,将 for 与 else 子句一起使用非常有用。如果 for 循环没有自行终止,即如果 break 结束了循环,则将执行 else 块中包含的代码。在现实生活中,这意味着如果每个猜测都不同,则打印秘密单词。

多次玩你的游戏。当你不能马上知道实际的术语时,它已经变得更难也更有趣了。不过,由于单词列表很短,游戏变得重复。接下来你将看到如何制作更长的单词列表。

从文本创建单词列表

你的电脑上通常已经安装了一个单词列表,你也可以在线获取单词列表。但是,你可能希望为了灵活性和控制权而创建自己的列表。这使你能够创建主题化的专业单词列表,例如,包含与编程、地名或其他语言相关的术语。

你编写的脚本会将任何文本文件转换为格式正确的单词列表,你可以在你的 Wordle 克隆版中使用。请创建一个名为 create_wordlist.py 的新文件并包含以下文本。

说明: 你的脚本使用 sys.argv 从命令行读取数据。前两个命令行选项被转换为路径,并在第 7 行和第 8 行中被命名为 in_path 和 out_path。你必须指定新词汇表文件的位置和现有文本文件的路径。

以下是如何使用该脚本将您当前的 wyrdl.py 副本转换为单词列表的示例

在读取 wyrdl.py 时会找到这些单词,然后保存在当前目录的 wordlist.txt 中。请记住,这将替换手动创建的 wordlist.txt 文件。查看你更新的单词列表

解释: 你会从你的代码中认出几个词。但是,请注意,并非所有术语都包含在单词列表中。回到 create_wordlist.py,特别注意第 14 行。这一行将通过阻止读取包含非 ASCII 字符的单词来过滤你的集合推导式。实际上,它仅限于字母 A 到 Z。

你应该知道,多于或少于五个字母的术语没有被过滤掉。也许你应该开发一个 Wordle 的变体,测试用户对七个字母单词的知识。在构建单词列表时,你可以这样做。但是,通过将该任务转移到你的 wyrdl.py 代码中,你可以获得一些灵活性。它允许更改游戏的单词长度,以及使用常规单词列表。

单词列表也进行了排序。没有这个,仍然可以手动浏览列表,但这不一定是必需的。为了改变排序顺序,你在第 16 行指定了 key。

通过 `key=lambda word: (len(word), word)`,你首先根据单词的长度对单词进行排序,然后再根据它们的实际长度进行排序。因此,你的单词列表从只有一个字母的单词开始,然后是两个字母的单词,以此类推。每个长度相同的单词组都按字母顺序排列。

现在你可以创建你自己的单词列表了。在你找到的任何纯文本文件上运行你的 create_wordlist.py 脚本。例如,你可以下载莎士比亚全集来制作一个老式的单词列表,或者下载一个简化版的《爱丽丝梦游仙境》来制作一个更简单的单词列表。

解释: 由于它们已经被 if 测试过滤掉了,所以你也省略了空单词 `.strip()`。

为了让你的代码在长期内更容易使用,你必须首先重新组织它。秘密单词现在是从单词列表中随机选择的,这使得你的游戏更具吸引力。稍后你将致力于通过更合乎逻辑的反馈来改善用户体验。

输出

Utilize Python and Rich to Create a Wordle Clone

步骤 3:使用函数组织代码

到目前为止,你已经为你的游戏创建了一个脚本。它由一个接一个执行的命令列表组成。这类程序扩展性不佳,即使它们非常适合快速入门和测试游戏的基本原型。随着你的程序变得更加复杂,你应该将你的代码组织成可重用的函数。

完成此步骤后,游戏对您的用户来说仍然看起来一样。但是,底层的代码以后会更容易开发。

在下面的组织中,代码如下所示。

所有这些更改后,你的游戏现在应该可以玩了。执行你的程序,检查游戏是否按预期运行。

步骤 4:使用 Rich 设计游戏风格

如果你在线玩过 Wordle,你会认出那个猜测表格和用颜色表示字母是否正确、位置错误或完全错误的彩色字母。

熟悉 Rich 控制台打印机

您必须安装 Rich,一个第三方库,才能使用它。在安装 Rich 之前,创建一个虚拟环境来安装您的项目需求。从下面的列表中选择您的平台,然后键入以下命令

在你的虚拟环境设置并启动后,可以使用 pip 安装 Rich。

安装后你可以测试 Rich。一个简单的方法是重写 print() 函数来开始使用 Rich

Rich 使用一种独特的标记语法,该语法模仿了公告板代码。Rich 将以粗体红字渲染“Rich”这个词,即使在这段代码块中看不到。样式指令被添加在方括号中,如上面所示的 [bold red]。该样式一直有效,直到你用 [/] 结束它。

你可以利用 Rich 通过在每次猜测之间清除屏幕来提高游戏的美观性。为此,你使用一个控制台。clear()。在你的代码中添加以下函数

使用 rule(),你可以添加一条装饰性的水平线,以更突出你打印的文本。控制台将使用 console.clear() 清除屏幕。然后,它将使用 console.rule() 在屏幕顶部打印一个标题。

记录之前的预测并给它们上色

你将使用一个列表来跟踪你所有的有根据的猜测。该列表可以以 "_____" 开始,即五个下划线,作为未来可能猜测的占位符。然后,当用户做出有根据的猜测时,占位符将被替换。

更新 main() 如下以开始

说明: 演示将反映用户的新预测。所有预测将使用新函数打印到屏幕上,该函数使用 Rich 来实现漂亮的颜色和布局。在为每个字母选择正确的颜色时,你将遍历每个猜测中的字母。

为了使这更容易,你从旧的基于集合的推理切换到一个新的每个字母的分类系统。在下面的代码中,display_guesses() 已经取代了 show_guess()

如果字母准确,你用绿色背景来装饰它。如果字母放错了位置——也就是说,如果字母不正确但出现在秘密单词中,你添加一个黄色背景。如果一个字母不正确,它会显示在灰色背景上,用十六进制值 #666666 表示。最后,你将占位符符号显示为暗淡色。

最后的猜测没有在 game_over() 的当前实现中更新到猜测数据库中。你通过在 input() 之前放置 show_guesses() 来做到这一点。

输出

Utilize Python and Rich to Create a Wordle Clone

步骤 5:包含验证和用户评论

在这个阶段,如果用户采取了激烈的行动,你将添加工具来帮助他们在游戏中导航。

基本的游戏玩法保持不变,但你的程序现在更加可靠,并且会在用户犯错时帮助他们。

输出

Utilize Python and Rich to Create a Wordle Clone

恭喜!你已经创建了一个功能丰富的 Wordle 克隆版,你可以使用并与你所有的朋友分享——至少是那些熟悉使用终端执行 Python 程序的朋友。