import tkinter as tk

from tkinter import messagebox

import random

class Minesweeper:

    def __init__(self):

        self.window = tk.Tk()

        self.window.title("扫雷")

        

        # 游戏参数

        self.board_size = 25  # 25x25的棋盘

        self.mine_count = 40  # 40个地雷

        self.cell_size = 25   # 每个方格25像素

        self.board_margin = 20

        

        # 创建画布

        canvas_size = self.board_size * self.cell_size + 2 * self.board_margin

        self.canvas = tk.Canvas(self.window, width=canvas_size, height=canvas_size)

        self.canvas.pack(padx=10, pady=10)

        

        # 初始化游戏数据

        self.board = [[0] * self.board_size for _ in range(self.board_size)]

        self.revealed = [[False] * self.board_size for _ in range(self.board_size)]

        self.flags = [[False] * self.board_size for _ in range(self.board_size)]

        

        # 添加重新开始按钮

        self.restart_button = tk.Button(self.window, text="重新开始", command=self.reset_game,

                                      font=('Arial', 12), relief='flat')

        self.restart_button.pack(side=tk.LEFT, padx=50, pady=(2, 15))  # 将按钮移到左边

        

        # 添加鼠标操作提示文字

        self.instructions_label = tk.Label(self.window, text="操作提示:左键揭开,右键标记地雷,左右键同时点击快速揭开周围区域。", font=('Arial', 12))

        self.instructions_label.pack(side=tk.LEFT, padx=10, pady=(0,10))  # 在按钮右边添加提示文字

        

        # 初始化状态变量

        self.left_pressed = False

        self.right_pressed = False

        self.game_over = False

        

        # 绑定鼠标事件

        self.canvas.bind('<Button-1>', self.on_left_press)

        self.canvas.bind('<ButtonRelease-1>', self.on_left_release)

        self.canvas.bind('<Button-2>', self.on_right_press)  

        self.canvas.bind('<ButtonRelease-2>', self.on_right_release)  

        

        # 初始化游戏

        self.reset_game()

    

    def reset_game(self):

        # 重置游戏数据

        self.board = [[0] * self.board_size for _ in range(self.board_size)]

        self.revealed = [[False] * self.board_size for _ in range(self.board_size)]

        self.flags = [[False] * self.board_size for _ in range(self.board_size)]

        self.game_over = False

        

        # 随机放置地雷

        mines = 0

        while mines < self.mine_count:

            x = random.randint(0, self.board_size-1)

            y = random.randint(0, self.board_size-1)

            if self.board[y][x] != -1:

                self.board[y][x] = -1

                mines += 1

        

        # 计算每个格子周围的地雷数

        for y in range(self.board_size):

            for x in range(self.board_size):

                if self.board[y][x] != -1:

                    self.board[y][x] = self.count_adjacent_mines(x, y)

        

        # 重绘棋盘

        self.draw_board()

    

    def count_adjacent_mines(self, x, y):

        count = 0

        for dy in [-1, 0, 1]:

            for dx in [-1, 0, 1]:

                if dx == 0 and dy == 0:

                    continue

                new_x, new_y = x + dx, y + dy

                if 0 <= new_x < self.board_size and 0 <= new_y < self.board_size:

                    if self.board[new_y][new_x] == -1:

                        count += 1

        return count

    

    def draw_board(self):

        self.canvas.delete("all")

        

        # 绘制背景

        canvas_size = self.board_size * self.cell_size + 2 * self.board_margin

        self.canvas.create_rectangle(0, 0, canvas_size, canvas_size,

                                   fill='#CDBA96', outline='#CDBA96')

        

        # 绘制网格和方块

        for y in range(self.board_size):

            for x in range(self.board_size):

                x1 = x * self.cell_size + self.board_margin

                y1 = y * self.cell_size + self.board_margin

                x2 = x1 + self.cell_size

                y2 = y1 + self.cell_size

               

                # 绘制方块

                if not self.revealed[y][x]:

                    self.canvas.create_rectangle(x1, y1, x2, y2,

                                              fill='#BDB088', outline='#7A6E4E')

                    if self.flags[y][x]:

                        # 绘制旗帜

                        self.canvas.create_text(x1 + self.cell_size//2,

                                             y1 + self.cell_size//2,

                                             text="🚩", font=('Arial', 12))

                else:

                    self.canvas.create_rectangle(x1, y1, x2, y2,

                                              fill='#E8D0AA', outline='#7A6E4E')

                    if self.board[y][x] > 0:

                        # 显示数字

                        self.canvas.create_text(x1 + self.cell_size//2,

                                             y1 + self.cell_size//2,

                                             text=str(self.board[y][x]),

                                             fill=self.get_number_color(self.board[y][x]))

                    elif self.board[y][x] == -1 and self.revealed[y][x]:

                        # 显示地雷

                        self.canvas.create_text(x1 + self.cell_size//2,

                                             y1 + self.cell_size//2,

                                             text="💣", font=('Arial', 12))

    

    def get_number_color(self, number):

        colors = ['blue', 'green', 'red', 'purple', 'maroon', 'turquoise', 'black', 'gray']

        return colors[number-1] if 0 < number <= len(colors) else 'black'

    

    def reveal_cell(self, x, y):

        if not (0 <= x < self.board_size and 0 <= y < self.board_size):

            return

        if self.revealed[y][x] or self.flags[y][x]:

            return

            

        self.revealed[y][x] = True

        

        if self.board[y][x] == 0:

            # 如果是空格,递归揭示周围的格子

            for dy in [-1, 0, 1]:

                for dx in [-1, 0, 1]:

                    if dx == 0 and dy == 0:

                        continue

                    self.reveal_cell(x + dx, y + dy)

    

    def handle_left_click(self, event):

        if self.game_over:

            return

            

        # 将点击位置转换为棋盘坐标

        x = (event.x - self.board_margin) // self.cell_size

        y = (event.y - self.board_margin) // self.cell_size

        

        if not (0 <= x < self.board_size and 0 <= y < self.board_size):

            return

            

        if self.flags[y][x]:

            return

            

        if self.board[y][x] == -1:

            # 踩到地雷,游戏结束

            self.game_over = True

            self.reveal_all_mines()

            self.draw_board()

            messagebox.showinfo("游戏结束", "很遗憾,你踩到地雷了!")

            return

            

        self.reveal_cell(x, y)

        self.draw_board()

        

        if self.check_win():

            self.game_over = True

            messagebox.showinfo("恭喜", "你赢了!")

    

    def handle_right_click(self, event):

        if self.game_over:

            return

            

        # 将点击位置转换为棋盘坐标

        x = (event.x - self.board_margin) // self.cell_size

        y = (event.y - self.board_margin) // self.cell_size

        

        if not (0 <= x < self.board_size and 0 <= y < self.board_size):

            return

            

        if not self.revealed[y][x]:

            self.flags[y][x] = not self.flags[y][x]

            self.draw_board()

    

    def handle_both_click(self, event):

        if self.game_over:

            return

            

        # 将点击位置转换为棋盘坐标

        x = (event.x - self.board_margin) // self.cell_size

        y = (event.y - self.board_margin) // self.cell_size

        

        if not (0 <= x < self.board_size and 0 <= y < self.board_size):

            return

            

        if not self.revealed[y][x]:

            return

            

        # 计算周围的旗子数量

        flag_count = 0

        for dy in [-1, 0, 1]:

            for dx in [-1, 0, 1]:

                if dx == 0 and dy == 0:

                    continue

                new_x, new_y = x + dx, y + dy

                if 0 <= new_x < self.board_size and 0 <= new_y < self.board_size:

                    if self.flags[new_y][new_x]:

                        flag_count += 1

        

        # 如果旗子数量等于数字,则揭示周围未标记的格子

        if flag_count == self.board[y][x]:

            for dy in [-1, 0, 1]:

                for dx in [-1, 0, 1]:

                    if dx == 0 and dy == 0:

                        continue

                    new_x, new_y = x + dx, y + dy

                    if 0 <= new_x < self.board_size and 0 <= new_y < self.board_size:

                        if not self.flags[new_y][new_x] and not self.revealed[new_y][new_x]:

                            if self.board[new_y][new_x] == -1:

                                # 如果点到地雷,游戏结束

                                self.game_over = True

                                self.reveal_all_mines()

                                self.draw_board()

                                messagebox.showinfo("游戏结束", "很遗憾,你踩到地雷了!")

                                return

                            self.reveal_cell(new_x, new_y)

            

            self.draw_board()

            if self.check_win():

                self.game_over = True

                messagebox.showinfo("恭喜", "你赢了!")

    

    def reveal_all_mines(self):

        for y in range(self.board_size):

            for x in range(self.board_size):

                if self.board[y][x] == -1:

                    self.revealed[y][x] = True

    

    def check_win(self):

        for y in range(self.board_size):

            for x in range(self.board_size):

                if self.board[y][x] != -1 and not self.revealed[y][x]:

                    return False

        return True

    

    def run(self):

        self.window.mainloop()

    def on_left_press(self, event):

        if self.game_over:

            return

        self.left_pressed = True

        if self.right_pressed:

            self.handle_both_click(event)  # 检查右键状态并处理

        else:

            self.preview_cell(event.x, event.y)

    

    def on_left_release(self, event):

        if self.game_over:

            return

        if self.left_pressed:

            if not self.right_pressed:

                self.handle_left_click(event)

        self.left_pressed = False

        self.draw_board()

    

    def on_right_press(self, event):

        if self.game_over:

            return

        self.right_pressed = True

        if self.left_pressed:

            self.handle_both_click(event)  # 检查左键状态并处理

    

    def on_right_release(self, event):

        if self.game_over:

            return

        if self.right_pressed:

            if not self.left_pressed:

                self.handle_right_click(event)

        self.right_pressed = False

        self.draw_board()

    

    def preview_cell(self, x, y):

        # 将点击位置转换为棋盘坐标

        board_x = (x - self.board_margin) // self.cell_size

        board_y = (y - self.board_margin) // self.cell_size

        

        if not (0 <= board_x < self.board_size and 0 <= board_y < self.board_size):

            return

            

        if not self.revealed[board_y][board_x] and not self.flags[board_y][board_x]:

            # 绘制预览效果

            x1 = board_x * self.cell_size + self.board_margin

            y1 = board_y * self.cell_size + self.board_margin

            x2 = x1 + self.cell_size

            y2 = y1 + self.cell_size

            self.canvas.create_rectangle(x1, y1, x2, y2,

                                      fill='#E8D0AA', outline='#7A6E4E')

if __name__ == "__main__":

    game = Minesweeper()

    game.run()