• 个人简介

    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