from
tkinter
import
*
from
tkinter
import
messagebox
import
random
class
Minesweeper:
class
MineButton(Button):
def
__init__(
self
, master, xy,
*
*
kw):
super
().__init__(master,
*
*
kw)
self
.xy
=
xy
self
.is_mine
=
False
self
.state
=
0
self
.neighbor_mines
=
0
def
__init__(
self
, width
=
9
, height
=
9
, mines
=
10
):
self
.width
=
width
self
.height
=
height
self
.total_mines
=
mines
self
.flags
=
mines
self
.game_active
=
True
self
.root
=
Tk()
self
.root.title(
'扫雷'
)
self
.setup_ui()
self
.setup_mines()
self
.root.mainloop()
def
setup_ui(
self
):
self
.flag_label
=
Label(
self
.root, text
=
f
'剩余: {self.flags}'
)
self
.flag_label.grid(row
=
0
, column
=
0
, columnspan
=
self
.width)
self
.buttons
=
{}
for
y
in
range
(
self
.height):
for
x
in
range
(
self
.width):
btn
=
self
.MineButton(
self
.root, (x, y),
width
=
2
, font
=
(
'Arial'
,
10
,
'bold'
),
relief
=
'raised'
,
bg
=
'lightgray'
)
btn.bind(
'<Button-1>'
,
lambda
e, b
=
btn:
self
.left_click(b))
btn.bind(
'<Button-3>'
,
lambda
e, b
=
btn:
self
.right_click(b))
btn.grid(row
=
y
+
1
, column
=
x)
self
.buttons[(x, y)]
=
btn
def
setup_mines(
self
):
positions
=
random.sample(
[pos
for
pos
in
self
.buttons],
self
.total_mines
)
for
pos
in
positions:
self
.buttons[pos].is_mine
=
True
for
pos
in
self
.buttons:
self
.calculate_neighbors(pos)
def
calculate_neighbors(
self
, pos):
x, y
=
pos
count
=
0
for
dx
in
(
-
1
,
0
,
1
):
for
dy
in
(
-
1
,
0
,
1
):
if
dx
=
=
0
and
dy
=
=
0
:
continue
nx, ny
=
x
+
dx, y
+
dy
if
(nx, ny)
in
self
.buttons
and
self
.buttons[(nx, ny)].is_mine:
count
+
=
1
self
.buttons[pos].neighbor_mines
=
count
def
left_click(
self
, button):
if
not
self
.game_active
or
button.state !
=
0
:
return
if
button.is_mine:
self
.game_over(
False
)
return
self
.reveal(button.xy)
self
.check_victory()
def
right_click(
self
, button):
if
not
self
.game_active
or
button.state
=
=
1
:
return
states
=
{
0
: (
'🚩'
,
2
),
2
: (
'?'
,
3
),
3
: ('',
0
)}
current
=
button.state
button.config(text
=
states[current][
0
])
button.state
=
states[current][
1
]
if
current
=
=
0
:
self
.flags
-
=
1
elif
current
=
=
2
:
self
.flags
+
=
1
self
.flag_label.config(text
=
f
'剩余: {self.flags}'
)
self
.check_victory()
def
reveal(
self
, pos, visited
=
None
):
if
visited
is
None
:
visited
=
set
()
if
pos
in
visited:
return
visited.add(pos)
button
=
self
.buttons[pos]
button.config(
relief
=
'sunken'
,
bg
=
'white'
,
state
=
'disabled'
)
button.state
=
1
if
button.neighbor_mines >
0
:
colors
=
[
'blue'
,
'green'
,
'red'
,
'navy'
,
'brown'
,
'cyan'
,
'black'
,
'gray'
]
button.config(
text
=
str
(button.neighbor_mines),
fg
=
colors[button.neighbor_mines
-
1
]
)
return
x, y
=
pos
for
dx
in
(
-
1
,
0
,
1
):
for
dy
in
(
-
1
,
0
,
1
):
nx, ny
=
x
+
dx, y
+
dy
neighbor
=
(nx, ny)
if
neighbor
in
self
.buttons
and
self
.buttons[neighbor].state
=
=
0
:
self
.reveal(neighbor, visited)
def
check_victory(
self
):
correct_flags
=
sum
(
1
for
pos
in
self
.buttons
if
self
.buttons[pos].state
=
=
2
and
self
.buttons[pos].is_mine
)
if
correct_flags
=
=
self
.total_mines
and
self
.flags
=
=
0
:
self
.game_over(
True
)
def
game_over(
self
, victory):
self
.game_active
=
False
for
pos
in
self
.buttons:
btn
=
self
.buttons[pos]
if
btn.is_mine:
btn.config(text
=
'💣'
, bg
=
'orange'
if
not
victory
else
'lightgreen'
)
msg
=
'恭喜,你赢了!'
if
victory
else
'游戏结束,你输了!'
messagebox.showinfo(
'游戏结束'
, msg)
self
.root.destroy()
if
__name__
=
=
'__main__'
:
Minesweeper()