@@ -27,7 +27,7 @@ typedef struct {
27
27
} PluginEvent ;
28
28
29
29
typedef enum {
30
- TileType0 , // this HAS to be in order, for hint assignment to be ez pz
30
+ TileType0 , // this HAS to be here in order, for hint assignment to be ez pz
31
31
TileType1 ,
32
32
TileType2 ,
33
33
TileType3 ,
@@ -38,6 +38,7 @@ typedef enum {
38
38
TileType8 ,
39
39
TileTypeUncleared ,
40
40
TileTypeFlag ,
41
+ TileTypeUdFlag ,
41
42
TileTypeMine
42
43
} TileType ;
43
44
@@ -53,6 +54,7 @@ typedef struct {
53
54
int fields_cleared ;
54
55
int flags_set ;
55
56
bool game_started ;
57
+ bool game_over ;
56
58
uint32_t game_started_tick ;
57
59
} Minesweeper ;
58
60
@@ -80,7 +82,11 @@ static void render_callback(Canvas* const canvas, void* ctx) {
80
82
mineStr = furi_string_alloc ();
81
83
timeStr = furi_string_alloc ();
82
84
83
- furi_string_printf (mineStr , "Mines: %d" , MINECOUNT - minesweeper_state -> flags_set );
85
+ if (minesweeper_state -> game_over ) {
86
+ furi_string_printf (mineStr , "GAME OVER. * to cont." );
87
+ } else {
88
+ furi_string_printf (mineStr , "Mines: %d" , MINECOUNT - minesweeper_state -> flags_set );
89
+ }
84
90
canvas_set_font (canvas , FontSecondary );
85
91
canvas_draw_str_aligned (canvas , 0 , 0 , AlignLeft , AlignTop , furi_string_get_cstr (mineStr ));
86
92
@@ -133,6 +139,9 @@ static void render_callback(Canvas* const canvas, void* ctx) {
133
139
case TileTypeFlag :
134
140
tile_to_draw = tile_flag_bits ;
135
141
break ;
142
+ case TileTypeUdFlag :
143
+ tile_to_draw = tile_udflag_bits ;
144
+ break ;
136
145
case TileTypeUncleared :
137
146
tile_to_draw = tile_uncleared_bits ;
138
147
break ;
@@ -174,7 +183,7 @@ static void setup_playfield(Minesweeper* minesweeper_state) {
174
183
int rand_y = rand () % PLAYFIELD_HEIGHT ;
175
184
// make sure first guess isn't a mine
176
185
if (minesweeper_state -> minefield [rand_x ][rand_y ] == FieldEmpty &&
177
- (minesweeper_state -> cursor_x != rand_x && minesweeper_state -> cursor_y != rand_y )) {
186
+ (minesweeper_state -> cursor_x != rand_x || minesweeper_state -> cursor_y != rand_y )) {
178
187
minesweeper_state -> minefield [rand_x ][rand_y ] = FieldMine ;
179
188
mines_left -- ;
180
189
}
@@ -215,10 +224,7 @@ static bool game_lost(Minesweeper* minesweeper_state) {
215
224
216
225
dialog_message_set_icon (message , NULL , 0 , 10 );
217
226
218
- NotificationApp * notifications = furi_record_open (RECORD_NOTIFICATION );
219
- notification_message (notifications , & sequence_set_vibro_on );
220
- furi_record_close (RECORD_NOTIFICATION );
221
- furi_timer_start (minesweeper_state -> timer , (uint32_t )furi_kernel_get_tick_frequency () * 0.2 );
227
+ minesweeper_state -> game_over = false; // reset the game state
222
228
223
229
DialogMessageButton choice = dialog_message_show (dialogs , message );
224
230
dialog_message_free (message );
@@ -259,7 +265,12 @@ static bool game_won(Minesweeper* minesweeper_state) {
259
265
// returns false if the move loses the game - otherwise true
260
266
static bool play_move (Minesweeper * minesweeper_state , int cursor_x , int cursor_y ) {
261
267
if (minesweeper_state -> playfield [cursor_x ][cursor_y ] == TileTypeFlag ) {
262
- // we're on a flagged field, do nothing
268
+ // if the game is over and the flagged feild wasn't a mine, let the player know with an
269
+ // upside down flag
270
+ if (minesweeper_state -> game_over &&
271
+ minesweeper_state -> minefield [cursor_x ][cursor_y ] != FieldMine ) {
272
+ minesweeper_state -> playfield [cursor_x ][cursor_y ] = TileTypeUdFlag ;
273
+ }
263
274
return true;
264
275
}
265
276
if (minesweeper_state -> minefield [cursor_x ][cursor_y ] == FieldMine ) {
@@ -289,7 +300,7 @@ static bool play_move(Minesweeper* minesweeper_state, int cursor_x, int cursor_y
289
300
}
290
301
int mines = minesweeper_state -> playfield [cursor_x ][cursor_y ]; // ¯\_(ツ)_/¯
291
302
if (flags == mines ) {
292
- // auto uncover all non-flags around (to win faster ; )
303
+ // auto uncover all non-flags around (to win faster;) )
293
304
for (int auto_y = cursor_y - 1 ; auto_y <= cursor_y + 1 ; auto_y ++ ) {
294
305
for (int auto_x = cursor_x - 1 ; auto_x <= cursor_x + 1 ; auto_x ++ ) {
295
306
if (auto_x == cursor_x && auto_y == cursor_y ) {
@@ -342,7 +353,7 @@ static bool play_move(Minesweeper* minesweeper_state, int cursor_x, int cursor_y
342
353
if (auto_x >= 0 && auto_x < PLAYFIELD_WIDTH && auto_y >= 0 &&
343
354
auto_y < PLAYFIELD_HEIGHT ) {
344
355
if (minesweeper_state -> playfield [auto_x ][auto_y ] == TileTypeUncleared ) {
345
- play_move (minesweeper_state , auto_x , auto_y );
356
+ ( void ) play_move (minesweeper_state , auto_x , auto_y );
346
357
}
347
358
}
348
359
}
@@ -354,6 +365,7 @@ static bool play_move(Minesweeper* minesweeper_state, int cursor_x, int cursor_y
354
365
static void minesweeper_state_init (Minesweeper * const minesweeper_state ) {
355
366
minesweeper_state -> cursor_x = minesweeper_state -> cursor_y = 0 ;
356
367
minesweeper_state -> game_started = false;
368
+ minesweeper_state -> game_over = false;
357
369
for (int y = 0 ; y < PLAYFIELD_HEIGHT ; y ++ ) {
358
370
for (int x = 0 ; x < PLAYFIELD_WIDTH ; x ++ ) {
359
371
minesweeper_state -> playfield [x ][y ] = TileTypeUncleared ;
@@ -381,7 +393,7 @@ int32_t minesweeper_app(void* p) {
381
393
382
394
FuriMessageQueue * event_queue = furi_message_queue_alloc (8 , sizeof (PluginEvent ));
383
395
384
- Minesweeper * minesweeper_state = malloc (sizeof (Minesweeper ));
396
+ Minesweeper * minesweeper_state = ( Minesweeper * ) malloc (sizeof (Minesweeper ));
385
397
// setup
386
398
minesweeper_state_init (minesweeper_state );
387
399
@@ -435,18 +447,38 @@ int32_t minesweeper_app(void* p) {
435
447
setup_playfield (minesweeper_state );
436
448
minesweeper_state -> game_started = true;
437
449
}
438
- if (!play_move (
439
- minesweeper_state ,
440
- minesweeper_state -> cursor_x ,
441
- minesweeper_state -> cursor_y )) {
442
- // ooops. looks like we hit a mine!
450
+ if (minesweeper_state -> game_over ) {
451
+ // if the game is over and the player presses okay, bring them to the
452
+ // game over menu. This allows a player to see all the mine locations
453
+ // before being taken away from the playfield.
443
454
if (game_lost (minesweeper_state )) {
444
455
// player wants to restart.
445
456
setup_playfield (minesweeper_state );
446
457
} else {
447
458
// player wants to exit :(
448
459
processing = false;
449
460
}
461
+ } else if (!play_move (
462
+ minesweeper_state ,
463
+ minesweeper_state -> cursor_x ,
464
+ minesweeper_state -> cursor_y )) {
465
+ // ooops. looks like we hit a mine!
466
+
467
+ // give the player some feedback
468
+ NotificationApp * notifications = furi_record_open (RECORD_NOTIFICATION );
469
+ notification_message (notifications , & sequence_set_vibro_on );
470
+ furi_record_close (RECORD_NOTIFICATION );
471
+ furi_timer_start (
472
+ minesweeper_state -> timer ,
473
+ (uint32_t )furi_kernel_get_tick_frequency () * 0.2 );
474
+
475
+ minesweeper_state -> game_over = true;
476
+ // Call play move for every space to reveal all the mines
477
+ for (int mx = 0 ; mx < PLAYFIELD_WIDTH ; ++ mx ) {
478
+ for (int my = 0 ; my < PLAYFIELD_HEIGHT ; ++ my ) {
479
+ play_move (minesweeper_state , mx , my );
480
+ }
481
+ }
450
482
} else {
451
483
// check win condition.
452
484
if (minesweeper_state -> fields_cleared ==
0 commit comments