使用 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 次浏览

开启你的 职业生涯

通过完成课程获得认证

立即开始
广告