iT邦幫忙

2025 iThome 鐵人賽

DAY 23
0
Software Development

軟體開發養成計畫:以小程式實作深化開發能力系列 第 23

[Day23]邊玩邊練打字!用 Python 做一個 Typing Game

  • 分享至 

  • xImage
  •  

開場

在程式學習的過程中,我常常需要快速輸入程式碼、指令或文字,而這時候「打字速度」就顯得格外重要。隨著自己逐漸往科技領域邁進,才意識到現有的打字速度不足以支撐想要完成的輸入量,因此如何提升打字效率成了我面臨的一大難題。在身邊許多人的建議下,我發現**「打字遊戲」**是一個不錯的解決方式,與其枯燥地反覆練習,不如將它設計成小遊戲來增加趣味性。
那接下來讓我們一起來看看,如何把「打字練習」變成一個有趣的小遊戲吧!

1.遊戲規劃

遊戲流程如下:
1.程式隨機產生一個單字或句子
2.玩家輸入答案
3.判斷是否正確、是否超時
4.記錄分數,進入下一回合

2.程式設計重點

1.單字庫管理

使用 nltk 單字庫,篩選字母、去重,確保題目多樣。

2.遊戲模式設計

限時模式 / 無限模式 / 可擴充模式,增加可玩性。

3.GUI 介面

Tkinter 建立視窗、標籤、按鈕、輸入框,操作直覺、像 App。

4.遊戲邏輯

顯示單字 → 玩家輸入 → 判斷正確/錯誤 → 更新分數 → 換下一題。

5.倒數計時與遊戲結束

限時模式用計時器,每秒更新;時間到或手動結束,遊戲停止。

6.排行榜功能

存玩家分數到檔案、讀取並排序,顯示前 10 名,增加競爭感。

3.打字遊戲程式碼

(1)準備單字庫

import nltk

try:
    from nltk.corpus import words as nltk_words
except LookupError:
    nltk.download('words')
    from nltk.corpus import words as nltk_words

word_list = [w.lower() for w in nltk_words.words() if w.isalpha() and 3 <= len(w) <= 8]
word_list = list(dict.fromkeys(word_list))

這段確保遊戲有大量單字可以隨機抽取,我選擇:

  • 下載了 nltk 內建的英文單字庫做使用。
  • 篩選單字條件為:只保留英文字母的單字,長度 3~8。
  • dict.fromkeys 去重,確保不會有重複單字。

(2)排行榜功能

SCORE_FILE = "scores.txt"

def save_score(name, score, mode):
    with open(SCORE_FILE, "a", encoding="utf-8") as f:
        f.write(f"{name},{score},{mode}\n")

def load_scores():
    if not os.path.exists(SCORE_FILE):
        return []
    with open(SCORE_FILE, "r", encoding="utf-8") as f:
        lines = f.read().splitlines()
    scores = []
    for line in lines:
        parts = line.split(",")
        if len(parts) == 3:
            scores.append((parts[0], int(parts[1]), parts[2]))
    scores.sort(key=lambda x: x[1], reverse=True)
    return scores[:10]

讓遊戲有「排行榜」功能,增加可玩性

  • save_score:遊戲結束時,把玩家名字、分數和模式存入 scores.txt。
  • load_scores:讀取檔案,排序並只顯示前 10 名。

(3)GUI 主選單 & 遊戲模式選擇

def show_menu(self):
    self.clear_screen()
    tk.Label(self.root, text="打字遊戲", font=("Arial", 28, "bold")).pack(pady=30)

    tk.Button(self.root, text="限時模式", font=("Arial", 16),
              command=lambda: self.start_game("timed")).pack(pady=10)
    tk.Button(self.root, text="無限模式", font=("Arial", 16),
              command=lambda: self.start_game("endless")).pack(pady=10)
    tk.Button(self.root, text="查看排行榜", font=("Arial", 16),
              command=self.show_leaderboard).pack(pady=10)
    tk.Button(self.root, text="退出", font=("Arial", 16),
              command=self.root.quit).pack(pady=10)
  • show_menu 清空畫面,顯示大標題和按鈕選單。
  • 可選限時模式 / 無限模式 / 排行榜 / 退出
  • 每個按鈕用 command 連結對應功能。

(4)遊戲畫面與打字邏輯

def start_game(self, mode):
    self.clear_screen()
    self.mode = mode
    self.score = 0
    self.game_running = True
    self.time_left = self.time_limit

    self.label_word = tk.Label(self.root, text="", font=("Arial", 22))
    self.label_word.pack(pady=20)

    self.entry = tk.Entry(self.root, font=("Arial", 18))
    self.entry.pack()
    self.entry.bind("<Return>", self.check_word)
    self.entry.focus()

    self.label_feedback = tk.Label(self.root, text="", font=("Arial", 14))
    self.label_feedback.pack(pady=10)

    self.label_timer = tk.Label(self.root, text=f"時間: {self.time_left}", font=("Arial", 14))
    self.label_timer.pack()

    self.label_score = tk.Label(self.root, text=f"分數: {self.score}", font=("Arial", 14))
    self.label_score.pack()

    tk.Button(self.root, text="結束遊戲", font=("Arial", 14), command=self.end_game).pack(pady=20)

    self.update_word()
    if mode == "timed":
        self.update_timer()
  • 初始化遊戲畫面(單字顯示、輸入框、分數、倒數計時)。
  • entry.bind("Return", self.check_word):按 Enter 就會檢查玩家輸入。
  • 根據模式決定是否啟動倒數計時 (update_timer)。

(5)檢查輸入、更新單字與分數

def check_word(self, event=None):
    if not self.game_running:
        return
    typed = self.entry.get().strip().lower()
    if typed == self.current_word:
        self.score += 1
        self.label_feedback.config(text="正確!", fg="green")
    else:
        self.label_feedback.config(text=f"錯誤!(答案: {self.current_word})", fg="red")
    self.label_score.config(text=f"分數: {self.score}")
    self.update_word()

def update_word(self):
    if self.game_running:
        self.current_word = random.choice(word_list)
        self.label_word.config(text=self.current_word)
        self.entry.delete(0, tk.END)
  • check_word:判斷使用者輸入是否正確,更新分數和提示文字。
  • update_word:抽新單字並清空輸入框,讓玩家可以繼續打下一題。

(6)倒數計時與遊戲結束

def update_timer(self):
    if self.game_running and self.mode == "timed":
        if self.time_left > 0:
            self.label_timer.config(text=f"時間: {self.time_left}")
            self.time_left -= 1
            self.root.after(1000, self.update_timer)
        else:
            self.end_game()

def end_game(self):
    self.game_running = False
    self.clear_screen()
    tk.Label(self.root, text="遊戲結束!", font=("Arial", 24, "bold")).pack(pady=20)
    tk.Label(self.root, text=f"你的分數: {self.score}", font=("Arial", 18)).pack(pady=10)

    tk.Label(self.root, text="輸入名字:", font=("Arial", 14)).pack()
    name_entry = tk.Entry(self.root, font=("Arial", 14))
    name_entry.pack()

    def save_and_back():
        name = name_entry.get().strip() or "玩家"
        save_score(name, self.score, self.mode)
        self.show_menu()

    tk.Button(self.root, text="存檔並返回主選單", font=("Arial", 14), command=save_and_back).pack(pady=20)
  • update_timer 每秒減少時間,時間到呼叫 end_game。
  • end_game 清空畫面,顯示分數,讓玩家輸入名字存排行榜。
  • 之後可回到主選單重新遊玩。

(7)主程式入口

if __name__ == "__main__":
    root = tk.Tk()
    app = TypingGameApp(root)
    root.mainloop()
  • 建立 Tkinter 視窗 (root)。
  • 建立遊戲物件TypingGameApp(root),初始化選單。
  • root.mainloop() 開始 GUI 事件迴圈,等待使用者操作。

4.打字遊戲成果展示

(1)遊戲主介面

35

(2)遊戲畫面

36
37

(3)排行榜

38

5.心得

一開始,我設計這個打字遊戲時,只能自己手動輸入單字到單字庫中,每次要增加題目都覺得很麻煩,也限制了遊戲的挑戰性。後來經過 ChatGPT 的建議,我找到使用 nltk 單字庫的最佳方法,瞬間就能載入成千上萬個單字,遊戲變得更豐富、更有趣。

除了單字庫的改進,我也加入了多種遊戲模式:限時模式、無限模式、等,讓練習可以依自己的需求調整難度和時間,練習更有效率。再加上 排行榜功能,每次打完都能記錄分數並和自己比賽,激勵我不斷挑戰自己的打字速度與準確度。

這個小專案讓我深刻體會到,程式不只是完成功能,還能透過設計細節提升使用者體驗與學習效果。每一次修改與新增功能的過程,都像是在和程式對話,也讓我對 Python 與 GUI 設計更加有信心,期待下一次再繼續製作更多有趣又實用的小程式。


上一篇
[Day22]讓時間動起來:Python 的 datetime 與 schedule 入門
下一篇
[Day24]程式開發必備技能:Git & GitHub 的基礎應用
系列文
軟體開發養成計畫:以小程式實作深化開發能力25
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言