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