讀古今文學網 > 父與子的編程之旅:與小卡特一起學Python > 22.9 又到了遊戲時間Hangman >

22.9 又到了遊戲時間Hangman

既然討論的是文件,為什麼要在這一章建立一個遊戲呢?嗯,Hangman 遊戲之所以有趣,原因在於它有一個龐大的詞彙表,可以從這個詞彙表中選擇題目。要做到這一點,最容易的辦法就是從文件中讀取。我們仍然使用 PythonCard 來完成這個遊戲,也想由此說明並非只能使用 Pygame 建立圖形化遊戲。

我不打算像介紹其他程序那樣詳細地解釋這個程序。現在你應該已經會看代碼了,相信你能自己搞清楚其中大部分代碼的作用。我只會稍稍給你一點指導,幫助你順利讀懂代碼。

Hangman GUI

我們的 Hangman 程序的主 GUI 是像下圖這樣的:

這裡顯示了上吊小人的各個部分,不過程序運行時,我們首先會隱藏小人的所有部分。玩家猜錯一個字母時,就會顯示這個小人的下一部分。如果整個小人都顯示出來,玩家可以再猜一次,然後遊戲結束!

玩家猜一個字母時,程序會查看這個字母是否在秘密詞中。如果確實是秘密詞中的字母,就把這個字母顯示出來。在窗口下方,玩家可以看見到目前為止他猜過的所有字母。玩家什麼時候都可以嘗試猜詞。

下面概括一下這個程序的工作原理。

開始時,程序完成以下工作:

  • 從文件加載詞彙表;

  • 從每行的末尾去除換行符;

  • 讓小人的所有部分都不可見;

  • 從詞彙表隨機選擇一個詞;

  • 根據秘密詞中的字母個數顯示相同數目的橫線。

玩家點擊 Guess! 按鈕時,程序做以下工作。

  • 檢查猜的是一個字母還是一個詞。

  • 如果是一個字母:

    • 檢查秘密詞,查看是否包含這個字母。

    • 如果玩家猜對了,用這個字母取代橫線,顯示這個字母出現在什麼位置。

    • 如果玩家猜錯了,顯示小人的另一部分。

    • 把猜出的字母增加到 Previous guesses 顯示區。

    • 查看玩家是否已經猜出單詞(猜出所有字母)。

  • 如果是一個詞:

    • 檢查玩家猜得正確與否。

    • 如果正確,顯示一個對話框,指出 You Won!(你贏了!)並開始新遊戲。

  • 查看玩家是不是已經沒有機會了,如果是,顯示一個對話框,指出 You Lost(你失敗了),並顯示這個秘密詞到底是什麼。

從詞彙表得到單詞

這一章討論的是文件,所以下面來看程序中得到詞彙表的部分。相應代碼如下:

words.txt 文件只是一個文本文件,所以可以使用 readlines 讀這個文件。為了從詞彙表中選擇一個詞,我們使用了 random.choice 函數,如下:

self.currentword = random.choice(self.lines)  

顯示小人

要跟蹤已經顯示了小人的哪些部分,另外下一步要顯示哪一部分,這有很多方法。我們決定使用一個循環,代碼如下:

def wrong(self):       self.pieces_shown += 1       for i in range(self.pieces_shown):   self.pieces[i].setHidden(False)       if self.pieces_shown == len(self.pieces):   message = \"You lose.  The word was \" + self.currentword   QtGui.QMessageBox.warning(self,\"Hangman\",message)   self.new_game  

我們使用 self.pieces_shown 來跟蹤上吊小人顯示了多少部分。如果所有的部分都顯示出來了,我們就使用一個對話框來告知玩家他輸了。

檢查猜到的字母

這個程序最難的一部分就是檢查玩家猜到的字母,看它是否出現在秘密詞中。這個工作之所以困難,是因為字母可能在一個單詞中出現多次。例如,如果秘密詞是 lever,玩家猜到了 e,就必須把第 2 個和第 4 個字母都顯示出來,因為它們都是 e。

我們有幾個函數來完成這項工作。find_letters 函數會查找某個字母在單詞中出現的所有位置,並返回一個包含這些位置的列表。例如,對於字母 e 和單詞 lever,這個函數會返回 [1, 3],因為字母 e 出現在這個字符串的索引 1 和索引 3 的位置上。(記住,索引從 0 開始。)代碼如下:

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 + letterelse:    new_string = new_string + string[i]    return new_string 

玩家猜一個字母時,我們使用剛才定義的兩個函數 find_lettersreplace_letters

整個程序大約 95 行代碼,另外我還加入了一些空行,讓代碼看起來更美觀。代碼清單 22-8 給出了整個程序,這裡加了對各個不同部分做的一些解釋。如果使用本書的安裝程序,你的計算機上的 ExamplesHangman 文件夾中應該已經有這個代碼了,另外也可以在網站上找到這個代碼,包括 hangman.py、hangman.ui 和 words.txt。切記,正如我們在第 20 章提到的,如果你使用的是 Mac,則需要在 Qt Designer 中打開 hangman.ui,並勾選掉 menubar 對象的 nativeMenuBar 屬性。

代碼清單 22-8 完整的 hangman.py 程序

為了簡化起見,我們的 Hangman 程序只使用了小寫字母。我們提供的單詞表只有小寫字母,用戶也必須將其猜測的內容以小寫形式輸入。

新遊戲開始時,處的 dashes 函數使用橫槓替換了字母。但它並沒有替換標點符號,比如撇號。所以如果單詞是 doesn\'t,玩家將會看到 -----\'-

建議你自己創建這個程序。可以用 Qt Designer 構建 GUI,即使看上去與這裡的版本不完全一樣也沒有關係。不過一定要仔細查看代碼,看看組件分別使用什麼名字。代碼中的名字必須與 .ui 文件中的名字一致。

盡可能自己鍵入代碼。運行程序,看看結果怎麼樣。如果你想做些不同的嘗試,那就放手去做!充分嘗試,大膽試驗,並享受其中的快樂。這正是編程最有意思也最有收穫的地方,大多數知識都是通過這個途徑獲得的。

你學到了什麼

在這一章,你學到了以下內容。

  • 什麼是文件。

  • 如何打開和關閉文件。

  • 打開文件的不同方式:讀、寫和追加。

  • 寫文件的不同方法: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 將數據保存到一個文件。(提示:如果先把數據放在一個列表中就會很容易做到。)