from tkinter import *
from random import *
from tkinter import messagebox
class Minesweeper:
def __init__(self):
self.root = Tk()
self.root.title('扫雷')
self.rows = 9 # 行数(>=2)
self.cols = 9 # 列数(>=4)
self.mines = 10 # 雷数(<=行数*列数-9)
self.btn_color = 'blue' # 按钮默认颜色
self.flag_color = '#FF0000' # 标记颜色
self.buttons = {}
self.mine_positions = []
self.safe_cells = []
self.remaining_flags = self.mines
self.game_active = True
self.first_click = True
self.time_counter = 0
self.init_ui()
self.root.mainloop()
def init_ui(self):
self.time_label = Label(self.root, text='0 秒', width=12, relief='sunken')
self.time_label.grid(row=0, column=0, columnspan=self.cols//2, sticky=W)
self.flag_label = Label(self.root, text=str(self.mines), width=10, relief='sunken')
self.flag_label.grid(row=0, column=self.cols//2, columnspan=self.cols-self.cols//2, sticky=E)
for i in range(self.rows*self.cols):
btn = Button(self.root, bg=self.btn_color, width=3, height=1,\
command=lambda n=i: self.click(n))
btn.grid(row=(i//self.cols)+1, column=i%self.cols)
btn.bind('<Button-3>', lambda e, n=i: self.flag(n))
btn.bind('<Button-1>', lambda e, n=i: self.double_click(n))
self.buttons[i] = btn
self.update_timer()
def update_timer(self):
if self.game_active:
self.time_counter += 1
self.time_label.config(text=f'{self.time_counter} 秒')
self.root.after(1000, self.update_timer)
def flag(self, n):
if not self.game_active or self.buttons[n]['state'] == DISABLED:
return
if self.buttons[n]['bg'] == self.btn_color:
self.buttons[n].config(bg=self.flag_color)
self.remaining_flags -= 1
elif self.buttons[n]['bg'] == self.flag_color:
self.buttons[n].config(bg=self.btn_color)
self.remaining_flags += 1
self.flag_label.config(text=str(self.remaining_flags))
def double_click(self, n):
if not self.game_active or self.buttons[n]['state'] != DISABLED:
return
neighbors = self.get_neighbors(n)
flag_count = sum(1 for cell in neighbors if self.buttons[cell]['bg'] == self.flag_color)
if self.buttons[n]['text'] == str(flag_count):
for cell in neighbors:
if self.buttons[cell]['bg'] == self.btn_color:
self.click(cell)
def click(self, n):
if not self.game_active or self.buttons[n]['state'] == DISABLED:
return
if self.first_click:
self.first_click = False
safe_zone = self.get_neighbors(n) + [n]
available_cells = [i for i in range(self.rows*self.cols) if i not in safe_zone]
self.mine_positions = sample(available_cells, self.mines)
self.safe_cells = [i for i in range(self.rows*self.cols) if i not in self.mine_positions]
if n in self.mine_positions:
self.game_over(False)
return
self.reveal_cell(n)
if len(self.safe_cells) == 0:
self.game_over(True)
def reveal_cell(self, n):
if n in self.mine_positions or self.buttons[n]['state'] == DISABLED:
return
self.buttons[n].config(state=DISABLED, bg='#FFFFFF')
self.safe_cells.remove(n)
neighbors = self.get_neighbors(n)
mine_count = sum(1 for cell in neighbors if cell in self.mine_positions)
if mine_count > 0:
self.buttons[n].config(text=str(mine_count))
else:
for cell in neighbors:
if self.buttons[cell]['bg'] == self.btn_color:
self.reveal_cell(cell)
def get_neighbors(self, n):
col = n % self.cols
row = n // self.cols
neighbors = []
for r in range(max(0, row-1), min(self.rows, row+2)):
for c in range(max(0, col-1), min(self.cols, col+2)):
if r == row and c == col:
continue
neighbors.append(r*self.cols + c)
return neighbors
def game_over(self, victory):
self.game_active = False
for mine in self.mine_positions:
self.buttons[mine].config(bg='#FF0000' if victory else '#000000')
result = '胜利' if victory else '失败'
ret = messagebox.askyesno('游戏结束', f'你{result}了!是否重新开始?')
if ret:
self.root.destroy()
Minesweeper()
else:
self.root.destroy()
if __name__ == '__main__':
Minesweeper()