Skip to content

Commit

Permalink
game over + win screen
Browse files Browse the repository at this point in the history
  • Loading branch information
panki27 committed Sep 23, 2022
1 parent 7e56f35 commit 1e36565
Show file tree
Hide file tree
Showing 11 changed files with 95 additions and 20 deletions.
Binary file removed .assets.h.swp
Binary file not shown.
Binary file modified assets/tile_0.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified assets/tile_1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified assets/tile_2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified assets/tile_3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified assets/tile_4.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified assets/tile_5.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified assets/tile_6.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified assets/tile_7.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified assets/tile_8.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
115 changes: 95 additions & 20 deletions minesweeper.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <stdlib.h>

#include <notification/notification_messages.h>
#include <dialogs/dialogs.h>

#include "assets.h"

Expand All @@ -13,7 +14,7 @@
#define TILE_WIDTH 8
#define TILE_HEIGHT 8

#define MINECOUNT 27
#define MINECOUNT 12

typedef enum {
EventTypeTick,
Expand Down Expand Up @@ -51,6 +52,9 @@ typedef struct {
int cursor_x;
int cursor_y;
bool game_started;
int mines_left;
int fields_cleared;
bool showing_dialog;
} Minesweeper;

static void input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) {
Expand All @@ -65,6 +69,10 @@ static void render_callback(Canvas* const canvas, void* ctx) {
if (minesweeper_state == NULL) {
return;
}
if (minesweeper_state->showing_dialog) {
release_mutex((ValueMutex*)ctx, minesweeper_state);
return;
}
canvas_set_font(canvas, FontPrimary);
for (int y = 0; y < PLAYFIELD_HEIGHT; y++) {
for (int x = 0; x < PLAYFIELD_WIDTH; x++) {
Expand Down Expand Up @@ -191,6 +199,12 @@ static void render_callback(Canvas* const canvas, void* ctx) {

static void setup_playfield(Minesweeper* minesweeper_state) {
int mines_left = MINECOUNT;
for (int y = 0; y < PLAYFIELD_HEIGHT; y++) {
for (int x = 0; x < PLAYFIELD_WIDTH; x++){
minesweeper_state->minefield[x][y] = FieldEmpty;
minesweeper_state->playfield[x][y] = TileTypeUncleared;
}
}
while(mines_left > 0) {
int rand_x = rand() % PLAYFIELD_WIDTH;
int rand_y = rand() % PLAYFIELD_HEIGHT;
Expand All @@ -200,6 +214,8 @@ static void setup_playfield(Minesweeper* minesweeper_state) {
minesweeper_state->minefield[rand_x][rand_y] = FieldMine;
mines_left--;
}
minesweeper_state->mines_left = MINECOUNT;
minesweeper_state->fields_cleared = 0;
}
}

Expand All @@ -211,24 +227,65 @@ static void place_flag(Minesweeper* minesweeper_state) {
}
}

static void game_lost() {
NotificationApp* notifications = furi_record_open(RECORD_NOTIFICATION);
notification_message(notifications, &sequence_set_vibro_on);
furi_delay_ms(200);
notification_message(notifications, &sequence_reset_vibro);
furi_record_close(RECORD_NOTIFICATION);
static bool game_lost(Minesweeper* minesweeper_state) {
// returns true if the player wants to restart, otherwise false
minesweeper_state->showing_dialog = true;
NotificationApp* notifications = furi_record_open(RECORD_NOTIFICATION);
DialogsApp *dialogs = furi_record_open(RECORD_DIALOGS);

DialogMessage* message = dialog_message_alloc();
const char* header_text = "Game Over";
const char* message_text = "You hit a mine!";

dialog_message_set_header(message, header_text, 64, 3, AlignCenter, AlignTop);
dialog_message_set_text(message, message_text, 64, 32, AlignCenter, AlignCenter);
dialog_message_set_buttons(message, NULL, "Play again", NULL);
// TODO: create icon
dialog_message_set_icon(message, NULL, 72, 17);

notification_message(notifications, &sequence_set_vibro_on);
furi_delay_ms(200);
notification_message(notifications, &sequence_reset_vibro);

DialogMessageButton choice = dialog_message_show(dialogs, message);
dialog_message_free(message);
minesweeper_state->showing_dialog = false;
furi_record_close(RECORD_NOTIFICATION);

return choice == DialogMessageButtonCenter;
}

static bool game_won(Minesweeper* minesweeper_state) {
NotificationApp* notifications = furi_record_open(RECORD_NOTIFICATION);
DialogsApp *dialogs = furi_record_open(RECORD_DIALOGS);

DialogMessage* message = dialog_message_alloc();
const char* header_text = "Game won!";
const char* message_text = "You cleared the minefield!";

dialog_message_set_header(message, header_text, 64, 3, AlignCenter, AlignTop);
dialog_message_set_text(message, message_text, 64, 32, AlignCenter, AlignCenter);
dialog_message_set_buttons(message, NULL, "Play again", NULL);
// TODO: create icon
dialog_message_set_icon(message, NULL, 72, 17);

DialogMessageButton choice = dialog_message_show(dialogs, message);
dialog_message_free(message);
minesweeper_state->showing_dialog = false;
notification_message(notifications, &sequence_reset_vibro);
furi_record_close(RECORD_NOTIFICATION);
return choice == DialogMessageButtonCenter;
}

static void play_move(Minesweeper* minesweeper_state, int cursor_x, int cursor_y) {
static bool play_move(Minesweeper* minesweeper_state, int cursor_x, int cursor_y) {
if (minesweeper_state->playfield[cursor_x][cursor_y] != TileTypeUncleared) {
// we're on an already uncovered field
return;
return true;
}
if (minesweeper_state->minefield[cursor_x][cursor_y] == FieldMine) {
// TODO: player loses!
minesweeper_state->playfield[cursor_x][cursor_y] = TileTypeMine;
game_lost();
return;
return false;
} else {
// get number of surrounding mines.
int hint = 0;
Expand All @@ -248,6 +305,7 @@ static void play_move(Minesweeper* minesweeper_state, int cursor_x, int cursor_y
}
// 〜( ̄▽ ̄〜) don't judge me (〜 ̄▽ ̄)〜
minesweeper_state->playfield[cursor_x][cursor_y] = hint;
minesweeper_state->fields_cleared++;
FURI_LOG_D("Minesweeper", "Setting %d,%d to %d", cursor_x, cursor_y, hint);
if (hint == 0) {
// auto open surrounding fields.
Expand All @@ -264,16 +322,17 @@ static void play_move(Minesweeper* minesweeper_state, int cursor_x, int cursor_y
}
}
}
return true;
}
}

static void minesweeper_state_init(Minesweeper* const plugin_state) {
plugin_state->cursor_x = plugin_state->cursor_y = 0;
plugin_state->game_started = false;
static void minesweeper_state_init(Minesweeper* const minesweeper_state) {
minesweeper_state->cursor_x = minesweeper_state->cursor_y = 0;
minesweeper_state->game_started = false;
minesweeper_state->showing_dialog = false;
for (int y = 0; y < PLAYFIELD_HEIGHT; y++) {
for (int x = 0; x < PLAYFIELD_WIDTH; x++){
plugin_state->minefield[x][y] = FieldEmpty;
plugin_state->playfield[x][y] = TileTypeUncleared;
minesweeper_state->playfield[x][y] = TileTypeUncleared;
}
}
}
Expand Down Expand Up @@ -342,10 +401,26 @@ int32_t minesweeper_app(void* p) {
setup_playfield(minesweeper_state);
minesweeper_state->game_started = true;
}
play_move(
minesweeper_state,
minesweeper_state->cursor_x,
minesweeper_state->cursor_y);
if (!play_move(minesweeper_state, minesweeper_state->cursor_x, minesweeper_state->cursor_y)) {
// ooops. looks like we hit a mine!
if (game_lost(minesweeper_state)) {
// player wants to restart.
setup_playfield(minesweeper_state);
} else {
// player wants to exit :(
processing = false;
}
} else {
// check win condition.
if (minesweeper_state->fields_cleared == (PLAYFIELD_HEIGHT*PLAYFIELD_WIDTH) - MINECOUNT){
if (game_won(minesweeper_state)) {
//player wants to restart
setup_playfield(minesweeper_state);
} else {
processing = false;
}
}
}
break;
case InputKeyBack:
// Exit the plugin
Expand Down

0 comments on commit 1e36565

Please sign in to comment.