-
个人简介
import tkinter as tk import tkinter.messagebox as messagebox import random
游戏配置
ROWS = 10 COLS = 10 MINES = 10 BUTTON_SIZE = 30
8个方向偏移
DIRS = [(-1, -1), (-1, 0), (-1, 1), (0, -1), (0, 1), (1, -1), (1, 0), (1, 1)]
class MineSweeperGUI: def init(self, root): self.root = root self.root.title("扫雷 GUI") self.root.resizable(False, False) # 锁定窗口大小
# 游戏数据 self.map_data = [[0] * COLS for _ in range(ROWS)] # -1地雷,数字为周围雷数 self.btns = [[None for _ in range(COLS)] for _ in range(ROWS)] self.opened = set() # 已翻开坐标 self.flags = set() # 插旗坐标 self.game_over = False self.first_click = True # 标记是否第一次点击,防止开局踩雷 # ==========修复1:重置按钮行改为0,棋盘整体下移一行,解决row=-1报错========== reset_btn = tk.Button(self.root, text="重新开始", command=self.reset_game, font=("SimHei", 10)) reset_btn.grid(row=0, column=0, columnspan=COLS, pady=3) self.create_ui() # 重置游戏 def reset_game(self): self.map_data = [[0] * COLS for _ in range(ROWS)] self.opened.clear() self.flags.clear() self.game_over = False self.first_click = True # 重置所有按钮样式 for r in range(ROWS): for c in range(COLS): self.btns[r][c].config(text="", bg="#cccccc") # 生成地雷(避开首次点击位置) def create_mines(self, click_r, click_c): count = 0 while count < MINES: r = random.randint(0, ROWS - 1) c = random.randint(0, COLS - 1) # 首次点击格子及周边8格不放地雷 if abs(r - click_r) <= 1 and abs(c - click_c) <= 1: continue if self.map_data[r][c] != -1: self.map_data[r][c] = -1 count += 1 self.calc_mine_num() # 计算每个格子周围地雷数量 def calc_mine_num(self): for r in range(ROWS): for c in range(COLS): if self.map_data[r][c] == -1: continue mine_count = 0 for dx, dy in DIRS: nr, nc = r + dx, c + dy if 0 <= nr < ROWS and 0 <= nc < COLS and self.map_data[nr][nc] == -1: mine_count += 1 self.map_data[r][c] = mine_count # 创建棋盘按钮(行从1开始,给顶部重置按钮留出位置) def create_ui(self): # ==========修复2:棋盘按钮起始行改为1,避开重置按钮========== for r in range(ROWS): for c in range(COLS): btn = tk.Button( self.root, width=2, height=1, font=("SimHei", 12), bg="#cccccc", relief=tk.RIDGE ) # r+1 整体下移一行 btn.grid(row=r + 1, column=c) # 左键翻开 btn.bind("<Button-1>", lambda e, r=r, c=c: self.left_click(r, c)) # 右键插旗 btn.bind("<Button-3>", lambda e, r=r, c=c: self.right_click(r, c)) self.btns[r][c] = btn # 右键插旗/取消旗子 def right_click(self, r, c): if self.game_over or (r, c) in self.opened: return btn = self.btns[r][c] if (r, c) in self.flags: self.flags.remove((r, c)) btn.config(text="") else: self.flags.add((r, c)) btn.config(text="🚩", fg="red") # 左键点击格子 def left_click(self, r, c): # 游戏结束、已翻开、插旗的格子禁止点击 if self.game_over or (r, c) in self.opened or (r, c) in self.flags: return # 第一次点击时生成地雷,保证不会踩雷 if self.first_click: self.create_mines(r, c) self.first_click = False val = self.map_data[r][c] # 踩到地雷,游戏失败 if val == -1: self.game_over = True self.show_all_mines() messagebox.showinfo("游戏结束", "踩到地雷了!游戏失败") return # 翻开格子并扩散空白区域 self.open_cell(r, c) # 检测是否胜利 self.check_win() # 递归翻开空白区域 def open_cell(self, r, c): if (r, c) in self.opened: return self.opened.add((r, c)) val = self.map_data[r][c] btn = self.btns[r][c] btn.config(bg="white") # 数字格子,显示对应颜色数字 if val > 0: color_map = { 1: "blue", 2: "green", 3: "red", 4: "purple", 5: "orange", 6: "teal", 7: "black", 8: "gray" } btn.config(text=str(val), fg=color_map[val]) return # 空白0格,递归翻开四周 btn.config(text="") for dx, dy in DIRS: nr, nc = r + dx, c + dy if 0 <= nr < ROWS and 0 <= nc < COLS: self.open_cell(nr, nc) # 游戏失败:展示所有地雷 def show_all_mines(self): for r in range(ROWS): for c in range(COLS): if self.map_data[r][c] == -1: self.btns[r][c].config(text="💣", bg="#ffaaaa") # 判断胜利条件:所有无雷格子全部翻开 def check_win(self): safe_cell_total = ROWS * COLS - MINES if len(self.opened) == safe_cell_total: self.game_over = True messagebox.showinfo("恭喜通关", "全部地雷排查完毕,扫雷成功!")程序入口运行
if name == "main": root = tk.Tk() app = MineSweeperGUI(root) root.mainloop()
-
通过的题目
-
最近活动
This person is lazy and didn't join any contests or homework. -
最近编写的题解
This person is lazy and didn't write any solutions.
题目标签
- 一本通编程启蒙
- 1