Skip to content

Commit 07d96b2

Browse files
committed
show mine locations when game is lost (#6); clean up a bit; include #9 functionality
1 parent 328435b commit 07d96b2

File tree

2 files changed

+60
-16
lines changed

2 files changed

+60
-16
lines changed

assets.h

+12
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,18 @@ static uint8_t tile_flag_bits[] = {
118118
0x81,
119119
0xFF,
120120
};
121+
#define tile_udflag_width 8
122+
#define tile_udflag_height 8
123+
static uint8_t tile_udflag_bits[] = {
124+
0xFF,
125+
0x81,
126+
0xB9,
127+
0x91,
128+
0x91,
129+
0x9d,
130+
0x81,
131+
0xFF,
132+
};
121133
#define tile_mine_width 8
122134
#define tile_mine_height 8
123135
static uint8_t tile_mine_bits[] = {

minesweeper.c

+48-16
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ typedef struct {
2727
} PluginEvent;
2828

2929
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
3131
TileType1,
3232
TileType2,
3333
TileType3,
@@ -38,6 +38,7 @@ typedef enum {
3838
TileType8,
3939
TileTypeUncleared,
4040
TileTypeFlag,
41+
TileTypeUdFlag,
4142
TileTypeMine
4243
} TileType;
4344

@@ -53,6 +54,7 @@ typedef struct {
5354
int fields_cleared;
5455
int flags_set;
5556
bool game_started;
57+
bool game_over;
5658
uint32_t game_started_tick;
5759
} Minesweeper;
5860

@@ -80,7 +82,11 @@ static void render_callback(Canvas* const canvas, void* ctx) {
8082
mineStr = furi_string_alloc();
8183
timeStr = furi_string_alloc();
8284

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+
}
8490
canvas_set_font(canvas, FontSecondary);
8591
canvas_draw_str_aligned(canvas, 0, 0, AlignLeft, AlignTop, furi_string_get_cstr(mineStr));
8692

@@ -133,6 +139,9 @@ static void render_callback(Canvas* const canvas, void* ctx) {
133139
case TileTypeFlag:
134140
tile_to_draw = tile_flag_bits;
135141
break;
142+
case TileTypeUdFlag:
143+
tile_to_draw = tile_udflag_bits;
144+
break;
136145
case TileTypeUncleared:
137146
tile_to_draw = tile_uncleared_bits;
138147
break;
@@ -174,7 +183,7 @@ static void setup_playfield(Minesweeper* minesweeper_state) {
174183
int rand_y = rand() % PLAYFIELD_HEIGHT;
175184
// make sure first guess isn't a mine
176185
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)) {
178187
minesweeper_state->minefield[rand_x][rand_y] = FieldMine;
179188
mines_left--;
180189
}
@@ -215,10 +224,7 @@ static bool game_lost(Minesweeper* minesweeper_state) {
215224

216225
dialog_message_set_icon(message, NULL, 0, 10);
217226

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
222228

223229
DialogMessageButton choice = dialog_message_show(dialogs, message);
224230
dialog_message_free(message);
@@ -259,7 +265,12 @@ static bool game_won(Minesweeper* minesweeper_state) {
259265
// returns false if the move loses the game - otherwise true
260266
static bool play_move(Minesweeper* minesweeper_state, int cursor_x, int cursor_y) {
261267
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+
}
263274
return true;
264275
}
265276
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
289300
}
290301
int mines = minesweeper_state->playfield[cursor_x][cursor_y]; // ¯\_(ツ)_/¯
291302
if(flags == mines) {
292-
// auto uncover all non-flags around (to win faster ;)
303+
// auto uncover all non-flags around (to win faster;) )
293304
for(int auto_y = cursor_y - 1; auto_y <= cursor_y + 1; auto_y++) {
294305
for(int auto_x = cursor_x - 1; auto_x <= cursor_x + 1; auto_x++) {
295306
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
342353
if(auto_x >= 0 && auto_x < PLAYFIELD_WIDTH && auto_y >= 0 &&
343354
auto_y < PLAYFIELD_HEIGHT) {
344355
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);
346357
}
347358
}
348359
}
@@ -354,6 +365,7 @@ static bool play_move(Minesweeper* minesweeper_state, int cursor_x, int cursor_y
354365
static void minesweeper_state_init(Minesweeper* const minesweeper_state) {
355366
minesweeper_state->cursor_x = minesweeper_state->cursor_y = 0;
356367
minesweeper_state->game_started = false;
368+
minesweeper_state->game_over = false;
357369
for(int y = 0; y < PLAYFIELD_HEIGHT; y++) {
358370
for(int x = 0; x < PLAYFIELD_WIDTH; x++) {
359371
minesweeper_state->playfield[x][y] = TileTypeUncleared;
@@ -381,7 +393,7 @@ int32_t minesweeper_app(void* p) {
381393

382394
FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(PluginEvent));
383395

384-
Minesweeper* minesweeper_state = malloc(sizeof(Minesweeper));
396+
Minesweeper* minesweeper_state = (Minesweeper*)malloc(sizeof(Minesweeper));
385397
// setup
386398
minesweeper_state_init(minesweeper_state);
387399

@@ -435,18 +447,38 @@ int32_t minesweeper_app(void* p) {
435447
setup_playfield(minesweeper_state);
436448
minesweeper_state->game_started = true;
437449
}
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.
443454
if(game_lost(minesweeper_state)) {
444455
// player wants to restart.
445456
setup_playfield(minesweeper_state);
446457
} else {
447458
// player wants to exit :(
448459
processing = false;
449460
}
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+
}
450482
} else {
451483
// check win condition.
452484
if(minesweeper_state->fields_cleared ==

0 commit comments

Comments
 (0)