diff --git a/applications/external/minesweeper/minesweeper.c b/applications/external/minesweeper/minesweeper.c index 2adca65e9..37332b51d 100644 --- a/applications/external/minesweeper/minesweeper.c +++ b/applications/external/minesweeper/minesweeper.c @@ -47,9 +47,11 @@ typedef enum { typedef enum { FieldEmpty, FieldMine } Field; typedef struct { + FuriMutex* mutex; + DialogsApp* dialogs; + NotificationApp* notifications; Field minefield[PLAYFIELD_WIDTH][PLAYFIELD_HEIGHT]; TileType playfield[PLAYFIELD_WIDTH][PLAYFIELD_HEIGHT]; - FuriTimer* timer; int cursor_x; int cursor_y; int mines_left; @@ -57,16 +59,8 @@ typedef struct { int flags_set; bool game_started; uint32_t game_started_tick; - FuriMutex* mutex; } Minesweeper; -static void timer_callback(void* ctx) { - UNUSED(ctx); - NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION); - notification_message(notification, &sequence_reset_vibro); - furi_record_close(RECORD_NOTIFICATION); -} - static void input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) { furi_assert(event_queue); @@ -179,7 +173,7 @@ static void setup_playfield(Minesweeper* minesweeper_state) { int rand_y = rand() % PLAYFIELD_HEIGHT; // make sure first guess isn't a mine if(minesweeper_state->minefield[rand_x][rand_y] == FieldEmpty && - (minesweeper_state->cursor_x != rand_x && minesweeper_state->cursor_y != rand_y)) { + (minesweeper_state->cursor_x != rand_x || minesweeper_state->cursor_y != rand_y)) { minesweeper_state->minefield[rand_x][rand_y] = FieldMine; mines_left--; } @@ -208,37 +202,25 @@ static void place_flag(Minesweeper* minesweeper_state) { static bool game_lost(Minesweeper* minesweeper_state) { // returns true if the player wants to restart, otherwise false - 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_header(message, "Game Over", 64, 3, AlignCenter, AlignTop); + dialog_message_set_text(message, "You hit a mine!", 64, 32, AlignCenter, AlignCenter); dialog_message_set_buttons(message, NULL, "Play again", NULL); - dialog_message_set_icon(message, NULL, 0, 10); - // Set cursor to initial position minesweeper_state->cursor_x = 0; minesweeper_state->cursor_y = 0; - NotificationApp* notifications = furi_record_open(RECORD_NOTIFICATION); - notification_message(notifications, &sequence_set_vibro_on); - furi_record_close(RECORD_NOTIFICATION); - furi_timer_start(minesweeper_state->timer, (uint32_t)furi_kernel_get_tick_frequency() * 0.2); + notification_message(minesweeper_state->notifications, &sequence_single_vibro); - DialogMessageButton choice = dialog_message_show(dialogs, message); + DialogMessageButton choice = dialog_message_show(minesweeper_state->dialogs, message); dialog_message_free(message); - furi_record_close(RECORD_DIALOGS); return choice == DialogMessageButtonCenter; } static bool game_won(Minesweeper* minesweeper_state) { - DialogsApp* dialogs = furi_record_open(RECORD_DIALOGS); - FuriString* tempStr; tempStr = furi_string_alloc(); @@ -256,15 +238,13 @@ static bool game_won(Minesweeper* minesweeper_state) { dialog_message_set_text( message, furi_string_get_cstr(tempStr), 64, 32, AlignCenter, AlignCenter); dialog_message_set_buttons(message, NULL, "Play again", NULL); - dialog_message_set_icon(message, NULL, 72, 17); // Call dolphin deed when we win the game DOLPHIN_DEED(DolphinDeedPluginGameWin); - DialogMessageButton choice = dialog_message_show(dialogs, message); + DialogMessageButton choice = dialog_message_show(minesweeper_state->dialogs, message); dialog_message_free(message); furi_string_free(tempStr); - furi_record_close(RECORD_DIALOGS); return choice == DialogMessageButtonCenter; } @@ -375,22 +355,6 @@ static void minesweeper_state_init(Minesweeper* const minesweeper_state) { int32_t minesweeper_app(void* p) { UNUSED(p); - DialogsApp* dialogs = furi_record_open(RECORD_DIALOGS); - - DialogMessage* message = dialog_message_alloc(); - const char* header_text = "Minesweeper"; - const char* message_text = "Hold OK pressed to toggle flags.\ngithub.com/panki27"; - - 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", NULL); - - dialog_message_set_icon(message, NULL, 0, 10); - - dialog_message_show(dialogs, message); - dialog_message_free(message); - furi_record_close(RECORD_DIALOGS); - FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(PluginEvent)); Minesweeper* minesweeper_state = malloc(sizeof(Minesweeper)); @@ -405,12 +369,28 @@ int32_t minesweeper_app(void* p) { } // BEGIN IMPLEMENTATION + minesweeper_state->dialogs = furi_record_open(RECORD_DIALOGS); + minesweeper_state->notifications = furi_record_open(RECORD_NOTIFICATION); + + DialogMessage* message = dialog_message_alloc(); + + dialog_message_set_header(message, "Minesweeper", 64, 3, AlignCenter, AlignTop); + dialog_message_set_text( + message, + "Hold OK pressed to toggle flags.\ngithub.com/panki27", + 64, + 32, + AlignCenter, + AlignCenter); + dialog_message_set_buttons(message, NULL, "Play", NULL); + + dialog_message_show(minesweeper_state->dialogs, message); + dialog_message_free(message); + // Set system callbacks ViewPort* view_port = view_port_alloc(); view_port_draw_callback_set(view_port, render_callback, minesweeper_state); view_port_input_callback_set(view_port, input_callback, event_queue); - minesweeper_state->timer = - furi_timer_alloc(timer_callback, FuriTimerTypeOnce, minesweeper_state); // Open GUI and register view_port Gui* gui = furi_record_open(RECORD_GUI); @@ -422,35 +402,42 @@ int32_t minesweeper_app(void* p) { PluginEvent event; for(bool processing = true; processing;) { FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100); - furi_mutex_acquire(minesweeper_state->mutex, FuriWaitForever); if(event_status == FuriStatusOk) { // press events if(event.type == EventTypeKey) { if(event.input.type == InputTypeShort) { switch(event.input.key) { case InputKeyUp: + furi_mutex_acquire(minesweeper_state->mutex, FuriWaitForever); minesweeper_state->cursor_y--; if(minesweeper_state->cursor_y < 0) { minesweeper_state->cursor_y = PLAYFIELD_HEIGHT - 1; } + furi_mutex_release(minesweeper_state->mutex); break; case InputKeyDown: + furi_mutex_acquire(minesweeper_state->mutex, FuriWaitForever); minesweeper_state->cursor_y++; if(minesweeper_state->cursor_y >= PLAYFIELD_HEIGHT) { minesweeper_state->cursor_y = 0; } + furi_mutex_release(minesweeper_state->mutex); break; case InputKeyRight: + furi_mutex_acquire(minesweeper_state->mutex, FuriWaitForever); minesweeper_state->cursor_x++; if(minesweeper_state->cursor_x >= PLAYFIELD_WIDTH) { minesweeper_state->cursor_x = 0; } + furi_mutex_release(minesweeper_state->mutex); break; case InputKeyLeft: + furi_mutex_acquire(minesweeper_state->mutex, FuriWaitForever); minesweeper_state->cursor_x--; if(minesweeper_state->cursor_x < 0) { minesweeper_state->cursor_x = PLAYFIELD_WIDTH - 1; } + furi_mutex_release(minesweeper_state->mutex); break; case InputKeyOk: if(!minesweeper_state->game_started) { @@ -500,7 +487,9 @@ int32_t minesweeper_app(void* p) { break; case InputKeyOk: FURI_LOG_D("Minesweeper", "Toggling flag"); + furi_mutex_acquire(minesweeper_state->mutex, FuriWaitForever); place_flag(minesweeper_state); + furi_mutex_release(minesweeper_state->mutex); break; case InputKeyBack: processing = false; @@ -512,15 +501,15 @@ int32_t minesweeper_app(void* p) { } } view_port_update(view_port); - furi_mutex_release(minesweeper_state->mutex); } view_port_enabled_set(view_port, false); gui_remove_view_port(gui, view_port); furi_record_close(RECORD_GUI); + furi_record_close(RECORD_DIALOGS); + furi_record_close(RECORD_NOTIFICATION); view_port_free(view_port); furi_message_queue_free(event_queue); furi_mutex_free(minesweeper_state->mutex); - furi_timer_free(minesweeper_state->timer); free(minesweeper_state); return 0;