
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()