sairate 3d1a9e092c feat(第7讲 字母卡牌): 实现记忆游戏并添加开始界面
- 新增 jiyi.py 文件,实现字母翻牌记忆游戏功能
- 添加 youxijiemian.py 文件,创建游戏开始界面
- 使用 turtle 和 tkinter 模块分别实现游戏和界面
- 支持选择不同难度的游戏模式
2025-07-09 15:54:21 +08:00

155 lines
5.9 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import tkinter as tk
from tkinter import messagebox
import random
# 扫雷游戏类
class MineSweeper:
def __init__(self, master, rows, cols, mines):
self.master = master # 主窗口
self.rows = rows # 行数
self.cols = cols # 列数
self.mines = mines # 雷的数量
self.buttons = {} # 存放每个按钮控件的字典 {(r, c): Button}
self.board = [[0 for _ in range(cols)] for _ in range(rows)] # 雷区,-1 表示地雷,其他为周围雷的数量
self.revealed = [[False for _ in range(cols)] for _ in range(rows)] # 是否已翻开
self.flags = [[False for _ in range(cols)] for _ in range(rows)] # 是否标记为旗帜
self.game_over = False # 游戏是否结束
self.generate_mines() # 随机布雷并更新数字
self.create_widgets() # 创建按钮控件界面
# 布雷并更新周围格子的数字
def generate_mines(self):
count = 0
while count < self.mines:
r = random.randint(0, self.rows - 1)
c = random.randint(0, self.cols - 1)
if self.board[r][c] == -1:
continue # 避免重复布雷
self.board[r][c] = -1
count += 1
# 更新周围8格的数字
for i in range(r - 1, r + 2):
for j in range(c - 1, c + 2):
if 0 <= i < self.rows and 0 <= j < self.cols and self.board[i][j] != -1:
self.board[i][j] += 1
# 创建游戏按钮界面
def create_widgets(self):
for r in range(self.rows):
for c in range(self.cols):
# 每个格子是一个 Button绑定左键点击翻格子、右键标旗
b = tk.Button(self.master, width=2, height=1, font=('Arial', 14),
command=lambda r=r, c=c: self.reveal_cell(r, c))
b.bind("<Button-3>", lambda e, r=r, c=c: self.toggle_flag(r, c))
b.grid(row=r, column=c)
self.buttons[(r, c)] = b
# 翻开一个格子
def reveal_cell(self, r, c):
if self.game_over or self.revealed[r][c] or self.flags[r][c]:
return # 游戏结束、已翻开或已标旗不响应
if self.board[r][c] == -1:
# 踩到地雷
self.buttons[(r, c)].config(text="💣", bg="red")
self.game_over = True
self.show_all_mines()
messagebox.showerror("游戏结束", "你踩到雷啦!")
return
# 否则开始翻格子(递归展开空格)
self.flood_fill(r, c)
self.check_win()
# 类似于 BFS 的空白格子展开
def flood_fill(self, r, c):
if not (0 <= r < self.rows and 0 <= c < self.cols):
return # 越界
if self.revealed[r][c] or self.flags[r][c]:
return # 已翻开或被标记不处理
self.revealed[r][c] = True
val = self.board[r][c]
btn = self.buttons[(r, c)]
# 设置按钮为灰色、不可点击、显示数字(或空)
btn.config(relief=tk.SUNKEN, text=str(val) if val > 0 else "", state=tk.DISABLED, bg="lightgray")
if val == 0:
# 如果是 0继续向四周递归展开
for dr in (-1, 0, 1):
for dc in (-1, 0, 1):
if dr != 0 or dc != 0:
self.flood_fill(r + dr, c + dc)
# 标记旗帜(右键)
def toggle_flag(self, r, c):
if self.revealed[r][c] or self.game_over:
return
if self.flags[r][c]:
self.flags[r][c] = False
self.buttons[(r, c)].config(text="") # 取消旗帜
else:
self.flags[r][c] = True
self.buttons[(r, c)].config(text="🚩") # 添加旗帜
# 显示所有地雷
def show_all_mines(self):
for r in range(self.rows):
for c in range(self.cols):
if self.board[r][c] == -1:
self.buttons[(r, c)].config(text="💣")
# 检查是否胜利
def check_win(self):
for r in range(self.rows):
for c in range(self.cols):
if self.board[r][c] != -1 and not self.revealed[r][c]:
return # 还有未翻开的非雷格子
self.game_over = True
messagebox.showinfo("胜利!", "恭喜你,排雷成功!")
# 游戏入口,获取参数并启动游戏
def start_game():
try:
# 从输入框获取参数并转为整数
rows = int(entry_rows.get())
cols = int(entry_cols.get())
mines = int(entry_mines.get())
# 检查输入合理性:不能为负、雷不能太多、不能太大
if rows <= 0 or cols <= 0 or mines <= 0 or mines*4 >= rows * cols or rows >= 20 or cols >= 20:
raise ValueError
except:
messagebox.showerror("输入错误", "请输入合理的行列和雷数")
return
# 关闭设置窗口,打开主游戏窗口
settings_window.destroy()
root = tk.Tk()
root.title("扫雷")
MineSweeper(root, rows, cols, mines)
root.mainloop()
# 设置窗口(输入行、列、雷数)
settings_window = tk.Tk()
settings_window.title("扫雷设置")
tk.Label(settings_window, text="行数:").grid(row=0, column=0)
entry_rows = tk.Entry(settings_window)
entry_rows.insert(0, "20") # 默认行数
entry_rows.grid(row=0, column=1)
tk.Label(settings_window, text="列数:").grid(row=1, column=0)
entry_cols = tk.Entry(settings_window)
entry_cols.insert(0, "10") # 默认列数
entry_cols.grid(row=1, column=1)
tk.Label(settings_window, text="雷数:").grid(row=2, column=0)
entry_mines = tk.Entry(settings_window)
entry_mines.insert(0, "10") # 默认雷数
entry_mines.grid(row=2, column=1)
# 开始游戏按钮
tk.Button(settings_window, text="开始游戏", command=start_game).grid(row=3, column=0, columnspan=2)
# 启动设置窗口主循环
settings_window.mainloop()