首页 » 与孩子一起学编程 » 与孩子一起学编程全文在线阅读

《与孩子一起学编程》22.9 又到了游戏时间Hangman

关灯直达底部

既然讨论的是文件,为什么要在这一章建立一个游戏呢?嗯,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_lettersreplace_letters

整个程序大约 95 行代码,另外我还加入了一些空行,让代码看起来更美观。代码清单 22-8 给出了整个程序,这里加了对各个不同部分做的一些解释。如果使用本书的安装程序,你的计算机上的 exampleshangman 文件夹中应该已经有这个代码了,另外也可以在网站上找到这个代码,包括 hangman.py、hangman.rsrc.py 和 words.txt。

代码清单 22-8 完整的 hangman.py 程序

建议你自己创建这个程序。可以在 PythonCard 中使用资源编辑器构建 GUI,即使看上去与这里的版本不完全一样也没有关系。不过一定要仔细查看代码,看看组件分别使用什么名字。代码中的名字必须与资源文件中的名字一致。

尽可能自己键入代码。运行程序,看看结果怎么样。如果你想做些不同的尝试,那就放手去做!充分尝试,大胆试验,并享受其中的快乐。这正是编程最有意思也最有收获的地方,大多数知识都是通过这个途径获得的。

你学到了什么

在这一章,你学到了以下内容。

 
  • 什么是文件。

  • 如何打开和关闭文件。

  • 打开文件的不同方式:读、写和追加。

  • 写文件的不同方法:writeprint >>

  • 如何使用 pickle 在文件中保存列表和对象(以及其他 Python 数据结构)。

  • 很多与文件夹(也称为目录)、文件位置和路径相关的内容。

我们还建立了一个 Hangman 游戏,这个游戏使用来自文件的数据得到一个词汇表。

测试题

 
  1. Python 中用来处理文件的对象称为 _______。

  2. 如何创建一个文件对象?

  3. 文件对象和文件名之间有什么区别?

  4. 完成文件读写时应该对文件做什么操作?

  5. 如果用追加模式打开一个文件然后在文件中写入内容会怎样?

  6. 如果用写模式打开一个文件然后在文件中写入内容会怎样?

  7. 读过文件的一部分之后如何从文件起始位置开始读?

  8. 将一个 Python 对象保存到文件中要使用哪个 pickle 函数?

  9. 要“还原”一个对象 ( 从 pickle 文件得到对象 , 并放回到 Python 变量中 ),应当使用哪个 pickle 方法?

动手试一试

 
  1. 建立程序造一些滑稽句子。每个句子应该至少有 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”。

  2. 编写一个程序,让用户输入名字、年龄、最喜欢的颜色和最喜欢的食物。程序要把所有这 4 项保存在一个文本文件中,每一项分别放在单独的一行上。

  3. 完成第 2 题的任务,不过使用 pickle 将数据保存到一个文件。(提示:如果先把数据放在一个列表中就会很容易做到。)