使用 Python3 實現翻牌遊戲(記憶遊戲)


歡迎閱讀這篇博文,我們將討論一個名為 Flip! 的趣味遊戲的實現,該遊戲使用 Python 開發。Flip! 是一款在 4x4 網格上翻轉瓦片以顯示其顏色的遊戲。遊戲的目標是在儘可能少的步數內翻轉所有瓦片。在這篇文章中,我們將逐步介紹使用 Python 實現該遊戲的過程,並解釋程式碼的不同組成部分。

語法

以下軟體包用於此程式碼:

  • itertools - 該軟體包提供函式,以更簡單的方式迭代集合。

  • tkinter - 該軟體包為遊戲提供圖形使用者介面 (GUI)。

  • random - 該軟體包提供函式來生成隨機數。

  • ctypes - 該軟體包提供對低階 Windows 函式的訪問。

由於這些軟體包都是 Python 預設庫的一部分,因此無需額外安裝。

演算法

  • 按下按鈕時,按鈕的顏色會顯示出來,並將其與之前按下的按鈕的顏色進行比較。

  • 如果兩種顏色匹配,則按鈕保持翻轉狀態,並更新玩家的分數。如果兩種顏色不匹配,則按鈕翻轉回來,並且玩家的分數不會改變。

  • 遊戲持續進行,直到所有按鈕都被翻轉過來,程式將玩家的最高分儲存在名為 maxscore.txt 的文字檔案中。

  • 在遊戲結束時,將玩家的分數與其最高分進行比較,如果玩家的分數更高,則更改檔案中的最高分。

  • 按下按鈕會導致按鈕的白色背景發生變化,以顯示下面的顏色。

  • 當連續按下相同顏色的兩個按鈕時,它們會保持翻轉狀態。連續按下兩個不同顏色的按鈕,它們會翻轉回來。

  • 所有按鈕都翻轉後,遊戲結束並顯示玩家的分數。

  • 玩家翻轉按鈕的次數決定了他們的分數。

import itertools
import tkinter as tk
import random
import ctypes

ctypes.windll.shcore.SetProcessDpiAwareness(1)
pressed = -1
tile_flipped = 16
count_move = 0
maxscore = 0

def is_winner():
   global maxscore, count_move
   if tile_flipped == 0:
      if count_move <= maxscore or maxscore == -1:
         maxscore = count_move
         with open('maxscore.txt', 'w') as f:
            f.write(str(maxscore))
      win_lbl['text'] = f'CLICKS: {str(count_move)}, BEST: {str(maxscore)}'

def print_count_move():
   win_lbl['text'] = f'CLICKS: {str(count_move)}'

def new_game():
   global pressed, tile_flipped, btns, colours, count_move, win_lbl, maxscore
   pressed = -1
   tile_flipped = 16
   count_move = 0
   btns = {}
   win_lbl['text'] = ''

   # make the file if it doesn't exist
   try:
      with open('maxscore.txt', 'r') as f:
         pass
   except FileNotFoundError:
      with open('maxscore.txt', 'w') as f:
         f.write('-1')
             
   with open('maxscore.txt', 'r') as f:
      maxscore = int(f.readline().strip())
   random.shuffle(colours)

   k=0
   for _, _ in itertools.product(range(4), range(4)):
      btn = Button(k)
      btns[k] = btn
      if k!= len(colours)-1: k+=1

   k=0
   for i, j in itertools.product(range(4), range(4)):
      btns[k].bttn.grid(row=i, column=j, sticky='nsew')
      if k!= len(colours)-1: k+=1

class Button:
   def __init__(self, k):
      self.index = k
      self.bttn = tk.Button(frm,width=6, height=2,borderwidth=6, bg='white', activebackground = colours[self.index],command=self.btn_press)
        
   def btn_press(self):
      global pressed, count_move
      self.bttn.configure(bg=colours[self.index])
      count_move += 1
      print_count_move()
      if pressed == -1:
         pressed = self.index
      else:
         self.compare_pressed_btns()
    
   def compare_pressed_btns(self):
      global pressed
      global tile_flipped

      if colours[self.index] != colours[pressed]:
         self.bttn.configure(bg='white')
         btns[pressed].bttn.configure(bg='white')
      elif self.index != pressed:
         self.bttn['state'] = tk.DISABLED
         btns[pressed].bttn['state']= tk.DISABLED
         tile_flipped -= 2
         is_winner()

      else:
         self.bttn.configure(bg='white')
      pressed = -1
       
window = tk.Tk()
window.title('Flip!')
window.config(bg = 'black')

window.rowconfigure([0,1],weight=1,pad=2)
window.columnconfigure(0,weight =1, pad=2)

frm = tk.Frame(window, bg='Gray')
frm.grid(row = 0, column=0, sticky='nsew')

frm.rowconfigure(list(range(4)), minsize=50, pad=2)
frm.columnconfigure(list(range(4)), minsize=50, pad=2)

btns = {}
colours=['YellowGreen', 'Violet', 'Tomato', 'SlateBlue', 'DarkCyan', 'Orange','DodgerBlue', 'ForestGreen']*2
random.shuffle(colours)
frm2 = tk.Frame(window, bg='Khaki')
win_lbl = tk.Label(frm2,width=19, height=1,bg='PowderBlue',relief=tk.GROOVE,borderwidth=2)
win_lbl.grid(row=0, column=0, padx=5, pady=5, sticky='nsew')

new_game_btn = tk.Button(text='NEW GAME', master=frm2, width=10, height=1, borderwidth=3, bg='Plum', command=new_game)
new_game_btn.grid(row=0, column=1, padx=5, pady=5, sticky = 'nsew')
frm2.grid(row=1, column=0, sticky='nsew')
new_game()

window.mainloop()

輸出

解釋

  • 在這個流行的記憶遊戲 Flip 的簡化版本中,玩家會看到一個按鈕網格,每個按鈕最初顯示為白色,並且 4x4 網格中的每個按鈕都隱藏了一個顏色。使用者需要在翻轉按鈕時匹配兩個按鈕的顏色,直到沒有兩個按鈕剩餘為止,遊戲結束。

  • 首先匯入必要的庫,包括用於圖形使用者介面的 random、itertools、tkinter 和用於 Windows 特定功能的 ctypes。Random 模組用於重新排列按鈕的顏色。設定不同的全域性變數來跟蹤遊戲的進度。"pressed" 用於跟蹤最近一次按鈕按下事件的索引,"tile flipped" 顯示匹配了多少個按鈕,"count move" 顯示進行了多少次移動,而 "maxscore" 顯示遊戲中的最高分。

  • is_winner 函式負責檢查遊戲是否獲勝。它檢查所有瓦片是否都已翻轉,即 tile_flipped 是否等於零,如果是,則檢查當前移動次數 count_move 是否小於或等於之前的最高分 maxscore。如果是,則將 maxscore 更新為新的 count_move 並將其寫入名為 maxscore.txt 的檔案中。最後,它更新 win_lbl 標籤的文字以顯示當前分數和最高分。

  • print_count_move 函式更新 win_lbl 標籤以顯示當前移動次數。

  • new_game 函式負責重置遊戲。它將變數初始化為預設值,清除 win_lbl 標籤,並從 maxscore.txt 檔案中讀取之前的最高分。然後,它對顏色列表進行洗牌,並使用 Button 類建立按鈕網格。它還在螢幕上設定按鈕的網格佈局。

  • Button 類定義了遊戲中每個瓦片的屬性和行為。每個按鈕都有一個索引值,對應於它在顏色洗牌列表中的位置。它建立一個 tk.Button 物件,其背景顏色為白色,活動背景顏色與其分配的顏色匹配。當按鈕被點選時,其背景顏色會更改為其分配的顏色,並且 count_move 會遞增。如果按鈕是第一個被點選的按鈕,則它會將索引值儲存在 pressed 變數中。如果是第二個被點選的按鈕,則透過呼叫 compare_pressed_btns 方法將其顏色與第一個按鈕的顏色進行比較。如果顏色匹配,則停用按鈕,並且 tile_flipped 計數遞減。如果顏色不匹配,則將按鈕的背景顏色改回白色。

  • 最後,程式碼的主體初始化 GUI 視窗,設定其標題和背景顏色,並建立 frmfrm2 框架,分別用於容納遊戲板和分數標籤以及新遊戲按鈕。它還建立了 win_lbl 標籤new_game_btn 按鈕並設定其屬性。然後,它呼叫 new_game 函式以開始遊戲。最後,它使用 window.mainloop() 進入主事件迴圈。

應用

這個專案可以展示圖形使用者介面 (GUI)、按鈕和函式的概念;同樣,它也作為評估和提高記憶能力的絕佳方式,使用清晰的圖形連線點。可以進一步修改遊戲以包含各種形狀、顏色和影像,使其成為初學者學習如何使用 Python 程式設計圖形使用者介面的絕佳專案。

結論

使用 Tkinter 工具包和 Python 3 開發的翻牌遊戲既有趣又引人入勝,它是學習 Python GUI 開發的絕佳專案。按鈕和函式的使用演示瞭如何使用程式語言和 GUI 框架建立互動式圖形介面,因此可以根據自己的喜好調整此益智遊戲,並且是初學者開始學習 Python 程式語言的圖形使用者介面的好起點。

更新於: 2023-08-22

264 次瀏覽

開啟你的 職業生涯

透過完成課程獲得認證

立即開始
廣告