既然讨论的是文件,为什么要在这一章建立一个游戏呢?嗯,Hangman 游戏之所以有趣,原因在于它有一个庞大的词汇表,可以从这个词汇表中选择题目。要做到这一点,最容易的办法就是从文件中读取。我们仍然使用 PythonCard 来完成这个游戏,也想由此说明并非只能使用 Pygame 建立图形化游戏。
我不打算像介绍其他程序那样详细地解释这个程序。现在你应该已经会看代码了,相信你能自己搞清楚其中大部分代码的作用。我只会稍稍给你一点指导,帮助你顺利读懂代码。
Hangman GUI
我们的 Hangman 程序的主 GUI 是像右图这样的:
这里显示了上吊小人的各个部分,不过程序运行时,我们首先会隐藏小人的所有部分。玩家猜错一个字母时,就会显示这个小人的下一部分。如果整个小人都显示出来,玩家可以再猜一次,然后游戏结束!
玩家猜一个字母时,程序会查看这个字母是否在秘密词中。如果确实是秘密词中的字母,就把这个字母显示出来。在窗口下方,玩家可以看见到目前为止他猜过的所有字母。玩家什么时候都可以尝试猜词。
Hangman 是 Carter 创建的,他希望这个游戏尽可能简单,所以词汇表里的词只能包含字母,不能有任何标点符号。
程序运行时的效果是像右图这样的:
下面概括一下这个程序的工作原理。
开始时,程序完成以下工作:
从文件加载词汇表;
从每行的末尾去除换行符;
让小人的所有部分都不可见;
从词汇表随机选择一个词;
根据秘密词中的字母个数显示相同数目的横线。
玩家点击 Guess a letter 按钮时,程序做以下工作。
打开一个带有文本输入域的对话框,玩家可以在这个域中键入一个字母。
检查秘密词,查看是否包含这个字母。
如果玩家猜对了,用这个字母取代横线,显示这个字母出现在什么位置。
如果玩家猜错了,显示小人的另一部分。
把猜出的字母增加到 Your Guesses 显示区。
查看玩家是否已经猜出单词(猜出所有字母)。
查看玩家是不是已经没有机会了,如果是,显示一个对话框,指出 You Lost (你失败了),并显示这个秘密词到底是什么。
玩家点击 Guess the word 按钮时,程序做以下工作。
打开一个对话框让玩家输入单词。
查看玩家是否猜对了。
如果是,显示一个对话框,指出“You Got It!”(你赢了!),并开始一个新游戏。
我们还建立了菜单项来开始新游戏,所以如果游戏只玩到一半,玩家不必重启整个程序也可以开始新游戏。
从词汇表得到单词
这一章讨论的是文件,所以下面来看程序中得到词汇表的部分。相应代码如下:
words.txt 文件只是一个文本文件,所以可以使用 readlines 读这个文件。为了从词汇表中选择一个词,我们使用了 random.choice 函数,如下:
self.currentword = random.choice(self.lines)
显示小人
要跟踪已经显示了小人的哪些部分,另外下一步要显示哪一部分,这有很多方法。Carter 决定使用嵌套 if 语句,这种做法还不错,代码如下:
def wrong_guess(self): dialog.alertDialog(self, /"WRONG!!!/", /'Hangman/') if self.components.head.visible == True: if self.components.body.visible == True: if self.components.arm1.visible == True: if self.components.arm2.visible == True: if self.components.foot1.visible == True: if self.components.foot2.visible == True: dialog.alertDialog(self, /"You lost! Word was /"+self.currentword, /'Hangman/') self.new_game else: self.components.foot2.visible = True else: self.components.foot1.visible = True else: self.components.arm2.visible = True else: self.components.arm1.visible = True else: self.components.body.visible = True else: self.components.head.visible = True
上吊小人有 6 个部分,所以我们需要 6 个嵌套的 if 块。注意,如果所有部分都可见,而且再一次猜错,就会得到一条消息,指出你失败了。
如果小人还有更多部分,嵌套 if 块会很难维护,我们可能需要另想办法。没准你就能想到哦!
检查猜到的字母
这个程序最难的一部分就是检查玩家猜到的字母,看它是否出现在秘密词中。这个工作之所以困难,是因为字母可能在一个单词中出现多次。例如,如果秘密词是 lever,玩家猜到了 e,就必须把第 2 个和第 4 个字母都显示出来,因为它们都是 e。
Carter 完成这部分时需要一点帮助,所以我写了几个函数来完成这项工作。find_letters 函数会查找某个字母在单词中出现的所有位置,并返回一个包含这些位置的列表。例如,对于字母 e 和单词 lever,这个函数会返回 [1, 3],因为字母 e 出现在这个字符串的索引 1 和索引 3 的位置上。(记住,索引从 0 开始。)代码如下:
def find_letters(letter, a_string): locations = start = 0 while a_string.find(letter, start, len(a_string)) != -1: location = a_string.find(letter, start, len(a_string)) locations.append(location) start = location + 1 return locations
replace_letters 函数从 find_letters 得到列表,用正确的字母替换这些位置上的横线。在我们的例子中(lever 中的字母 e),它会用 -e-e- 替换 -----。这就向玩家显示出猜对的字母出现在单词的什么位置,其余仍然为横线。代码如下:
def replace_letters(string, locations, letter): new_string = /'/' for i in range (0, len(string)): if i in locations: new_string = new_string + letter else: new_string = new_string + string[i] return new_string
玩家猜一个字母时,我们使用刚才定义的两个函数 find_letters 和 replace_letters:
整个程序大约 95 行代码,另外我还加入了一些空行,让代码看起来更美观。代码清单 22-8 给出了整个程序,这里加了对各个不同部分做的一些解释。如果使用本书的安装程序,你的计算机上的 exampleshangman 文件夹中应该已经有这个代码了,另外也可以在网站上找到这个代码,包括 hangman.py、hangman.rsrc.py 和 words.txt。
代码清单 22-8 完整的 hangman.py 程序
建议你自己创建这个程序。可以在 PythonCard 中使用资源编辑器构建 GUI,即使看上去与这里的版本不完全一样也没有关系。不过一定要仔细查看代码,看看组件分别使用什么名字。代码中的名字必须与资源文件中的名字一致。
尽可能自己键入代码。运行程序,看看结果怎么样。如果你想做些不同的尝试,那就放手去做!充分尝试,大胆试验,并享受其中的快乐。这正是编程最有意思也最有收获的地方,大多数知识都是通过这个途径获得的。
你学到了什么
在这一章,你学到了以下内容。
什么是文件。
如何打开和关闭文件。
打开文件的不同方式:读、写和追加。
写文件的不同方法:write 或 print >>。
如何使用 pickle 在文件中保存列表和对象(以及其他 Python 数据结构)。
很多与文件夹(也称为目录)、文件位置和路径相关的内容。
我们还建立了一个 Hangman 游戏,这个游戏使用来自文件的数据得到一个词汇表。
测试题
Python 中用来处理文件的对象称为 _______。
如何创建一个文件对象?
文件对象和文件名之间有什么区别?
完成文件读写时应该对文件做什么操作?
如果用追加模式打开一个文件然后在文件中写入内容会怎样?
如果用写模式打开一个文件然后在文件中写入内容会怎样?
读过文件的一部分之后如何从文件起始位置开始读?
将一个 Python 对象保存到文件中要使用哪个 pickle 函数?
要“还原”一个对象 ( 从 pickle 文件得到对象 , 并放回到 Python 变量中 ),应当使用哪个 pickle 方法?
动手试一试
建立程序造一些滑稽句子。每个句子应该至少有 4 部分,类似于:
The __________ ___________ ____________ _____________
(形容词) ( 名词 ) ( 动词短语 ) ( 副词短语 )
例如:
这个程序会随机选择一个形容词、一个名词、一个动词短语和一个副词短语来创建句子。这些单词都存储在文件中,可以使用“记事本”创建这些单词。
要完成这个程序,最简单的方法是为这 4 组单词分别创建一个文件,不过也可以采用你希望的任何方式创建文件。下面给出一些点子来启发一下你,不过,我相信你也能提出自己的想法:
形容词:crazed, silly, shy, goofy, angry, lazy, obstinate, purple
名词:monkey, elephant, cyclist, teacher, author, hockey player
动词短语:played a ukulele, danced a jig, combed his hair, flapped her ears
副词短语:on the table, at the grocery store, in the shower, after breakfast,with a broom
再给出一个示例输出:“The lazy author combed his hair with a broom”。
编写一个程序,让用户输入名字、年龄、最喜欢的颜色和最喜欢的食物。程序要把所有这 4 项保存在一个文本文件中,每一项分别放在单独的一行上。
完成第 2 题的任务,不过使用 pickle 将数据保存到一个文件。(提示:如果先把数据放在一个列表中就会很容易做到。)