Skip to content

Commit cca6c28

Browse files
[投稿] 添加脚本: 扫雷 — by 我是人
1 parent 7dc35a0 commit cca6c28

1 file changed

Lines changed: 236 additions & 0 deletions

File tree

Lines changed: 236 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,236 @@
1+
import ui
2+
import pygame
3+
import random
4+
5+
# 只保留pygame核心逻辑,不初始化图形
6+
pygame.init()
7+
8+
# 数字颜色(和原版一致)
9+
COLORS = {
10+
1: '#0000FF',
11+
2: '#008000',
12+
3: '#FF0000',
13+
4: '#000080',
14+
5: '#800000',
15+
6: '#008080',
16+
7: '#000000',
17+
8: '#808080'
18+
}
19+
20+
class MineLogic:
21+
def __init__(self, rows, cols, mines):
22+
self.rows = rows
23+
self.cols = cols
24+
self.mines = mines
25+
self.reset()
26+
27+
def reset(self):
28+
self.mine = [[0]*self.cols for _ in range(self.rows)]
29+
self.revealed = [[False]*self.cols for _ in range(self.rows)]
30+
self.flagged = [[False]*self.cols for _ in range(self.rows)]
31+
self.game_over = False
32+
self.win = False
33+
self.first = True
34+
self.mine_pos = set()
35+
36+
def put_mines(self, ar, ac):
37+
while len(self.mine_pos) < self.mines:
38+
r = random.randint(0, self.rows-1)
39+
c = random.randint(0, self.cols-1)
40+
if (r,c) != (ar,ac):
41+
self.mine_pos.add((r,c))
42+
for r,c in self.mine_pos:
43+
self.mine[r][c] = -1
44+
self.calc_numbers()
45+
46+
def calc_numbers(self):
47+
dirs = [(-1,-1),(-1,0),(-1,1),
48+
(0,-1), (0,1),
49+
(1,-1), (1,0),(1,1)]
50+
for r in range(self.rows):
51+
for c in range(self.cols):
52+
if self.mine[r][c] == -1: continue
53+
cnt = 0
54+
for dr,dc in dirs:
55+
nr, nc = r+dr, c+dc
56+
if 0<=nr<self.rows and 0<=nc<self.cols:
57+
if self.mine[nr][nc] == -1:
58+
cnt +=1
59+
self.mine[r][c] = cnt
60+
61+
def reveal_cell(self, r, c):
62+
if self.game_over or self.flagged[r][c] or self.revealed[r][c]:
63+
return
64+
if self.first:
65+
self.put_mines(r,c)
66+
self.first = False
67+
if self.mine[r][c] == -1:
68+
self.game_over = True
69+
return
70+
self.revealed[r][c] = True
71+
# 递归展开0的格子(修复自动扩散逻辑)
72+
if self.mine[r][c] == 0:
73+
dirs = [(-1,-1),(-1,0),(-1,1),(0,-1),(0,1),(1,-1),(1,0),(1,1)]
74+
for dr,dc in dirs:
75+
nr, nc = r+dr, c+dc
76+
if 0<=nr<self.rows and 0<=nc<self.cols:
77+
if not self.revealed[nr][nc]:
78+
self.reveal_cell(nr, nc)
79+
self.check_win()
80+
81+
def flag_cell(self, r, c):
82+
if self.game_over or self.revealed[r][c]:
83+
return
84+
self.flagged[r][c] = not self.flagged[r][c]
85+
86+
def check_win(self):
87+
total = self.rows*self.cols - self.mines
88+
cnt = sum(row.count(True) for row in self.revealed)
89+
if cnt >= total:
90+
self.win = True
91+
self.game_over = True
92+
93+
def mines_left(self):
94+
return self.mines - sum(row.count(True) for row in self.flagged)
95+
96+
class MineUI(ui.View):
97+
def __init__(self, r=9, c=9, m=10):
98+
self.g = MineLogic(r,c,m)
99+
self.cell = 26
100+
self.flag_mode = False # 插旗开关
101+
super().__init__()
102+
self.setup_ui()
103+
104+
def setup_ui(self):
105+
self.background_color = '#c0c0c0'
106+
self.name = '扫雷'
107+
w = self.g.cols * self.cell
108+
109+
# 顶部栏
110+
top = ui.View(frame=(10,10,w,50))
111+
top.background_color = '#c0c0c0'
112+
top.border_width = 2
113+
top.border_color = '#808080'
114+
self.add_subview(top)
115+
116+
# 雷数显示
117+
self.mine_lbl = ui.Label(frame=(10,10,60,30))
118+
self.mine_lbl.background_color = 'black'
119+
self.mine_lbl.text_color = 'red'
120+
self.mine_lbl.font = ('Courier',22)
121+
self.mine_lbl.alignment = ui.ALIGN_CENTER
122+
top.add_subview(self.mine_lbl)
123+
124+
# 笑脸
125+
self.face = ui.Button(frame=(w//2-20,10,30,30))
126+
self.face.title = '😊'
127+
self.face.font = ('System',20)
128+
self.face.action = self.reset
129+
top.add_subview(self.face)
130+
131+
# 插旗模式开关(解决长按不支持的问题)
132+
self.flag_btn = ui.Button(frame=(w-70,10,60,30))
133+
self.flag_btn.title = '🚩'
134+
self.flag_btn.font = ('System',20)
135+
self.flag_btn.action = self.toggle_flag_mode
136+
self.flag_btn.background_color = '#c0c0c0'
137+
self.flag_btn.border_width = 1
138+
self.flag_btn.border_color = '#808080'
139+
top.add_subview(self.flag_btn)
140+
141+
# 棋盘
142+
board = ui.View(frame=(10,70, self.g.cols*self.cell, self.g.rows*self.cell))
143+
board.background_color = '#c0c0c0'
144+
board.border_width = 2
145+
board.border_color = '#808080'
146+
self.add_subview(board)
147+
148+
self.btns = []
149+
for r in range(self.g.rows):
150+
row_btns = []
151+
for c in range(self.g.cols):
152+
btn = ui.Button(frame=(c*self.cell, r*self.cell, self.cell, self.cell))
153+
btn.tag = (r,c)
154+
btn.background_color = '#c0c0c0'
155+
btn.border_width = 1
156+
btn.border_color = '#808080'
157+
btn.font = ('System',14)
158+
btn.action = self.on_cell_click
159+
board.add_subview(btn)
160+
row_btns.append(btn)
161+
self.btns.append(row_btns)
162+
self.refresh()
163+
164+
def toggle_flag_mode(self, sender):
165+
# 切换插旗模式
166+
self.flag_mode = not self.flag_mode
167+
sender.background_color = '#ff9999' if self.flag_mode else '#c0c0c0'
168+
169+
def refresh(self):
170+
self.mine_lbl.text = f'{max(0, self.g.mines_left()):03d}'
171+
if self.g.win:
172+
self.face.title = '😎'
173+
elif self.g.game_over:
174+
self.face.title = '😵'
175+
else:
176+
self.face.title = '😊'
177+
178+
for r in range(self.g.rows):
179+
for c in range(self.g.cols):
180+
b = self.btns[r][c]
181+
if self.g.flagged[r][c]:
182+
b.title = '🚩'
183+
b.background_color = '#c0c0c0'
184+
continue
185+
if not self.g.revealed[r][c]:
186+
b.title = ''
187+
b.background_color = '#c0c0c0'
188+
continue
189+
b.background_color = '#e0e0e0'
190+
v = self.g.mine[r][c]
191+
if v == -1:
192+
b.title = '💣'
193+
elif v == 0:
194+
b.title = ''
195+
else:
196+
b.title = str(v)
197+
b.text_color = COLORS[v]
198+
199+
def on_cell_click(self, btn):
200+
r,c = btn.tag
201+
if self.flag_mode:
202+
# 插旗模式:点一下插旗/拔旗
203+
self.g.flag_cell(r,c)
204+
else:
205+
# 普通模式:点一下翻开,自动扩散
206+
self.g.reveal_cell(r,c)
207+
self.refresh()
208+
209+
def reset(self, btn=None):
210+
self.g.reset()
211+
self.flag_mode = False
212+
self.flag_btn.background_color = '#c0c0c0'
213+
self.refresh()
214+
215+
class MenuUI(ui.View):
216+
def __init__(self):
217+
super().__init__()
218+
self.background_color = '#c0c0c0'
219+
self.frame = (0,0,280,300)
220+
self.name = '扫雷菜单'
221+
self.setup()
222+
223+
def setup(self):
224+
def b(y, t, r, c, m):
225+
btn = ui.Button(frame=(40,y,200,40))
226+
btn.title = t
227+
btn.background_color = '#c0c0c0'
228+
btn.border_width = 2
229+
btn.border_color = '#808080'
230+
btn.action = lambda s: MineUI(r,c,m).present()
231+
self.add_subview(btn)
232+
b(40, '初级 9×9 10雷',9,9,10)
233+
b(90, '中级 16×16 40雷',16,16,40)
234+
b(140, '高级 16×30 99雷',16,30,99)
235+
236+
MenuUI().present()

0 commit comments

Comments
 (0)