Просмотр исходного кода

Merge minesweeper from https://github.com/xMasterX/all-the-plugins

# Conflicts:
#	minesweeper/helpers/mine_sweeper_haptic.c
#	minesweeper/helpers/mine_sweeper_storage.c
#	minesweeper/scenes/info_scene.c
#	minesweeper/scenes/settings_scene.c
#	minesweeper/views/minesweeper_game_screen.c
Willy-JL 1 год назад
Родитель
Сommit
354e084884

+ 1 - 1
minesweeper/application.fam

@@ -15,7 +15,7 @@ App(
     fap_icon="assets/minesweeper.png",  # 10x10 1-bit PNG
     fap_icon="assets/minesweeper.png",  # 10x10 1-bit PNG
     fap_category="Games",
     fap_category="Games",
     # Optional values
     # Optional values
-    fap_version="1.1",
+    fap_version="1.2",
     fap_description="Flipper Zero Minesweeper Implementation",
     fap_description="Flipper Zero Minesweeper Implementation",
     fap_author="Alexander Rodriguez",
     fap_author="Alexander Rodriguez",
     fap_weburl="https://github.com/squee72564/F0_Minesweeper_Fap",
     fap_weburl="https://github.com/squee72564/F0_Minesweeper_Fap",

+ 8 - 23
minesweeper/docs/changelog.md

@@ -1,32 +1,17 @@
-
 # Changelog
 # Changelog
-## TODO:
-- Add settings options to toggle hardware feedback
-- Maybe take a look at the board verifier algo and try to make faster/multi-thread or anything to allow better maps
+
+## Version 1.2.0 - 1/25/2024
+
+Added ability to toggle sound and haptic feedback.
+
+Minor reformats and fixes.
 
 
 ## Version 1.1.0 - 1/11/2024
 ## Version 1.1.0 - 1/11/2024
 
 
 Added haptic / led functionality
 Added haptic / led functionality
 
 
-## Added
-- Haptic feedback on all button presses.
-    - Out of bounds movement
-    - Ok to clear tiles
-    - Holding back for flags
-    - Different haptic feedback on win/loss
-- LED changes on win loss
-    - Initially LED is just reset
-    - Set to red on loss
-    - Set to blue on win
-- Sound on some presses
+Code Reformats
 
 
 ## Version 1.0.0 - 1/10/2024
 ## Version 1.0.0 - 1/10/2024
 
 
-Initial Full release for the game.
-
-## Added
-- Mine sweeper game with settings menu to choose variable board dimensions from 16x7 to 32x32.
-- Ability to set difficulty, width, and height for the game board in settings.
-- Ability to enable solvable boards only
-- The core game functionality is complete for the game with multiple types of button presses registered for different inputs.
-- The game will save your settings (besides "enable solvable") when you leave the game.
+Initial Full release for the game.

+ 5 - 5
minesweeper/helpers/mine_sweeper_haptic.c

@@ -4,7 +4,7 @@
 void mine_sweeper_play_happy_bump(void* context) {
 void mine_sweeper_play_happy_bump(void* context) {
     MineSweeperApp* app = context;
     MineSweeperApp* app = context;
 
 
-    notification_message(app->notification, &sequence_set_vibro_on);
+    if(app->feedback_enabled) notification_message(app->notification, &sequence_set_vibro_on);
     furi_thread_flags_wait(0, FuriFlagWaitAny, 20);
     furi_thread_flags_wait(0, FuriFlagWaitAny, 20);
     notification_message(app->notification, &sequence_reset_vibro);
     notification_message(app->notification, &sequence_reset_vibro);
 }
 }
@@ -13,7 +13,7 @@ void mine_sweeper_play_long_ok_bump(void* context) {
     MineSweeperApp* app = context;
     MineSweeperApp* app = context;
 
 
     for(int i = 0; i < 2; i++) {
     for(int i = 0; i < 2; i++) {
-        notification_message(app->notification, &sequence_set_vibro_on);
+        if(app->feedback_enabled) notification_message(app->notification, &sequence_set_vibro_on);
         furi_thread_flags_wait(0, FuriFlagWaitAny, 20);
         furi_thread_flags_wait(0, FuriFlagWaitAny, 20);
         notification_message(app->notification, &sequence_reset_vibro);
         notification_message(app->notification, &sequence_reset_vibro);
         furi_thread_flags_wait(0, FuriFlagWaitAny, 20);
         furi_thread_flags_wait(0, FuriFlagWaitAny, 20);
@@ -23,7 +23,7 @@ void mine_sweeper_play_long_ok_bump(void* context) {
 void mine_sweeper_play_oob_bump(void* context) {
 void mine_sweeper_play_oob_bump(void* context) {
     MineSweeperApp* app = context;
     MineSweeperApp* app = context;
 
 
-    notification_message(app->notification, &sequence_set_vibro_on);
+    if(app->feedback_enabled) notification_message(app->notification, &sequence_set_vibro_on);
     furi_thread_flags_wait(0, FuriFlagWaitAny, 20);
     furi_thread_flags_wait(0, FuriFlagWaitAny, 20);
     notification_message(app->notification, &sequence_reset_vibro);
     notification_message(app->notification, &sequence_reset_vibro);
 }
 }
@@ -31,7 +31,7 @@ void mine_sweeper_play_oob_bump(void* context) {
 void mine_sweeper_play_lose_bump(void* context) {
 void mine_sweeper_play_lose_bump(void* context) {
     MineSweeperApp* app = context;
     MineSweeperApp* app = context;
 
 
-    notification_message(app->notification, &sequence_set_vibro_on);
+    if(app->feedback_enabled) notification_message(app->notification, &sequence_set_vibro_on);
     furi_thread_flags_wait(0, FuriFlagWaitAny, 100);
     furi_thread_flags_wait(0, FuriFlagWaitAny, 100);
     notification_message(app->notification, &sequence_reset_vibro);
     notification_message(app->notification, &sequence_reset_vibro);
     furi_thread_flags_wait(0, FuriFlagWaitAny, 400);
     furi_thread_flags_wait(0, FuriFlagWaitAny, 400);
@@ -41,7 +41,7 @@ void mine_sweeper_play_win_bump(void* context) {
     MineSweeperApp* app = context;
     MineSweeperApp* app = context;
 
 
     for(int i = 0; i < 4; i++) {
     for(int i = 0; i < 4; i++) {
-        notification_message(app->notification, &sequence_set_vibro_on);
+        if(app->feedback_enabled) notification_message(app->notification, &sequence_set_vibro_on);
         furi_thread_flags_wait(0, FuriFlagWaitAny, 50);
         furi_thread_flags_wait(0, FuriFlagWaitAny, 50);
         notification_message(app->notification, &sequence_reset_vibro);
         notification_message(app->notification, &sequence_reset_vibro);
         furi_thread_flags_wait(0, FuriFlagWaitAny, 100);
         furi_thread_flags_wait(0, FuriFlagWaitAny, 100);

+ 23 - 6
minesweeper/helpers/mine_sweeper_speaker.c

@@ -5,7 +5,10 @@ static const float volume = 0.8f;
 
 
 void mine_sweeper_play_ok_sound(void* context) {
 void mine_sweeper_play_ok_sound(void* context) {
     MineSweeperApp* app = context;
     MineSweeperApp* app = context;
-    UNUSED(app);
+
+    if(!app->feedback_enabled) {
+        return;
+    }
 
 
     if(furi_hal_speaker_is_mine() || furi_hal_speaker_acquire(30)) {
     if(furi_hal_speaker_is_mine() || furi_hal_speaker_acquire(30)) {
         furi_hal_speaker_start(NOTE_LOSE, volume);
         furi_hal_speaker_start(NOTE_LOSE, volume);
@@ -14,7 +17,10 @@ void mine_sweeper_play_ok_sound(void* context) {
 
 
 void mine_sweeper_play_flag_sound(void* context) {
 void mine_sweeper_play_flag_sound(void* context) {
     MineSweeperApp* app = context;
     MineSweeperApp* app = context;
-    UNUSED(app);
+
+    if(!app->feedback_enabled) {
+        return;
+    }
 
 
     if(furi_hal_speaker_is_mine() || furi_hal_speaker_acquire(30)) {
     if(furi_hal_speaker_is_mine() || furi_hal_speaker_acquire(30)) {
         furi_hal_speaker_start(NOTE_FLAG, volume);
         furi_hal_speaker_start(NOTE_FLAG, volume);
@@ -23,7 +29,10 @@ void mine_sweeper_play_flag_sound(void* context) {
 
 
 void mine_sweeper_play_oob_sound(void* context) {
 void mine_sweeper_play_oob_sound(void* context) {
     MineSweeperApp* app = context;
     MineSweeperApp* app = context;
-    UNUSED(app);
+
+    if(!app->feedback_enabled) {
+        return;
+    }
 
 
     if(furi_hal_speaker_is_mine() || furi_hal_speaker_acquire(30)) {
     if(furi_hal_speaker_is_mine() || furi_hal_speaker_acquire(30)) {
         furi_hal_speaker_start(NOTE_OOB, volume);
         furi_hal_speaker_start(NOTE_OOB, volume);
@@ -32,7 +41,10 @@ void mine_sweeper_play_oob_sound(void* context) {
 
 
 void mine_sweeper_play_win_sound(void* context) {
 void mine_sweeper_play_win_sound(void* context) {
     MineSweeperApp* app = context;
     MineSweeperApp* app = context;
-    UNUSED(app);
+
+    if(!app->feedback_enabled) {
+        return;
+    }
 
 
     if(furi_hal_speaker_is_mine() || furi_hal_speaker_acquire(30)) {
     if(furi_hal_speaker_is_mine() || furi_hal_speaker_acquire(30)) {
         furi_hal_speaker_start(NOTE_WIN, volume);
         furi_hal_speaker_start(NOTE_WIN, volume);
@@ -41,8 +53,10 @@ void mine_sweeper_play_win_sound(void* context) {
 
 
 void mine_sweeper_play_lose_sound(void* context) {
 void mine_sweeper_play_lose_sound(void* context) {
     MineSweeperApp* app = context;
     MineSweeperApp* app = context;
-    UNUSED(app);
 
 
+    if(!app->feedback_enabled) {
+        return;
+    }
     if(furi_hal_speaker_is_mine() || furi_hal_speaker_acquire(30)) {
     if(furi_hal_speaker_is_mine() || furi_hal_speaker_acquire(30)) {
         furi_hal_speaker_start(NOTE_LOSE, volume);
         furi_hal_speaker_start(NOTE_LOSE, volume);
     }
     }
@@ -50,7 +64,10 @@ void mine_sweeper_play_lose_sound(void* context) {
 
 
 void mine_sweeper_stop_all_sound(void* context) {
 void mine_sweeper_stop_all_sound(void* context) {
     MineSweeperApp* app = context;
     MineSweeperApp* app = context;
-    UNUSED(app);
+
+    if(!app->feedback_enabled) {
+        return;
+    }
 
 
     if(furi_hal_speaker_is_mine()) {
     if(furi_hal_speaker_is_mine()) {
         furi_hal_speaker_stop();
         furi_hal_speaker_stop();

+ 12 - 13
minesweeper/helpers/mine_sweeper_storage.c

@@ -47,16 +47,14 @@ void mine_sweeper_save_settings(void* context) {
     // Store Settings
     // Store Settings
     flipper_format_write_header_cstr(
     flipper_format_write_header_cstr(
         fff_file, MINESWEEPER_SETTINGS_HEADER, MINESWEEPER_SETTINGS_FILE_VERSION);
         fff_file, MINESWEEPER_SETTINGS_HEADER, MINESWEEPER_SETTINGS_FILE_VERSION);
-    flipper_format_write_uint32(fff_file, MINESWEEPER_SETTINGS_KEY_HAPTIC, &app->haptic, 1);
-    flipper_format_write_uint32(fff_file, MINESWEEPER_SETTINGS_KEY_SPEAKER, &app->speaker, 1);
-    flipper_format_write_uint32(fff_file, MINESWEEPER_SETTINGS_KEY_LED, &app->led, 1);
 
 
     uint32_t w = app->settings_info.board_width, h = app->settings_info.board_height,
     uint32_t w = app->settings_info.board_width, h = app->settings_info.board_height,
-             d = app->settings_info.difficulty;
+             d = app->settings_info.difficulty, f = app->feedback_enabled;
 
 
     flipper_format_write_uint32(fff_file, MINESWEEPER_SETTINGS_KEY_WIDTH, &w, 1);
     flipper_format_write_uint32(fff_file, MINESWEEPER_SETTINGS_KEY_WIDTH, &w, 1);
     flipper_format_write_uint32(fff_file, MINESWEEPER_SETTINGS_KEY_HEIGHT, &h, 1);
     flipper_format_write_uint32(fff_file, MINESWEEPER_SETTINGS_KEY_HEIGHT, &h, 1);
     flipper_format_write_uint32(fff_file, MINESWEEPER_SETTINGS_KEY_DIFFICULTY, &d, 1);
     flipper_format_write_uint32(fff_file, MINESWEEPER_SETTINGS_KEY_DIFFICULTY, &d, 1);
+    flipper_format_write_uint32(fff_file, MINESWEEPER_SETTINGS_KEY_FEEDBACK, &f, 1);
 
 
     if(!flipper_format_rewind(fff_file)) {
     if(!flipper_format_rewind(fff_file)) {
         FURI_LOG_E(TAG, "Rewind error");
         FURI_LOG_E(TAG, "Rewind error");
@@ -108,19 +106,20 @@ bool mine_sweeper_read_settings(void* context) {
         return false;
         return false;
     }
     }
 
 
-    uint32_t w = 7, h = 16, d = 0;
+    uint32_t w = 7, h = 16, d = 0, f = 1;
     flipper_format_read_uint32(fff_file, MINESWEEPER_SETTINGS_KEY_WIDTH, &w, 1);
     flipper_format_read_uint32(fff_file, MINESWEEPER_SETTINGS_KEY_WIDTH, &w, 1);
     flipper_format_read_uint32(fff_file, MINESWEEPER_SETTINGS_KEY_HEIGHT, &h, 1);
     flipper_format_read_uint32(fff_file, MINESWEEPER_SETTINGS_KEY_HEIGHT, &h, 1);
     flipper_format_read_uint32(fff_file, MINESWEEPER_SETTINGS_KEY_DIFFICULTY, &d, 1);
     flipper_format_read_uint32(fff_file, MINESWEEPER_SETTINGS_KEY_DIFFICULTY, &d, 1);
+    flipper_format_read_uint32(fff_file, MINESWEEPER_SETTINGS_KEY_FEEDBACK, &f, 1);
 
 
-    if(w > 146) {
-        w = 146;
+    if(w > 32) {
+        w = 32;
     }
     }
     if(w < 16) {
     if(w < 16) {
         w = 16;
         w = 16;
     }
     }
-    if(h > 64) {
-        h = 64;
+    if(h > 32) {
+        h = 32;
     }
     }
     if(h < 7) {
     if(h < 7) {
         h = 7;
         h = 7;
@@ -128,14 +127,14 @@ bool mine_sweeper_read_settings(void* context) {
     if(d > 2) {
     if(d > 2) {
         d = 2;
         d = 2;
     }
     }
+    if(f > 1) {
+        f = 1;
+    }
 
 
     app->settings_info.board_width = (uint8_t)w;
     app->settings_info.board_width = (uint8_t)w;
     app->settings_info.board_height = (uint8_t)h;
     app->settings_info.board_height = (uint8_t)h;
     app->settings_info.difficulty = (uint8_t)d;
     app->settings_info.difficulty = (uint8_t)d;
-
-    flipper_format_read_uint32(fff_file, MINESWEEPER_SETTINGS_KEY_HAPTIC, &app->haptic, 1);
-    flipper_format_read_uint32(fff_file, MINESWEEPER_SETTINGS_KEY_SPEAKER, &app->speaker, 1);
-    flipper_format_read_uint32(fff_file, MINESWEEPER_SETTINGS_KEY_LED, &app->led, 1);
+    app->feedback_enabled = (uint8_t)f;
 
 
     flipper_format_rewind(fff_file);
     flipper_format_rewind(fff_file);
 
 

+ 7 - 9
minesweeper/helpers/mine_sweeper_storage.h

@@ -7,21 +7,19 @@
 #include <flipper_format/flipper_format.h>
 #include <flipper_format/flipper_format.h>
 #include "../minesweeper.h"
 #include "../minesweeper.h"
 
 
-#define MINESWEEPER_SETTINGS_FILE_VERSION 1
-#define CONFIG_FILE_DIRECTORY_PATH EXT_PATH("apps_data/f0_mine_sweeper")
-#define MINESWEEPER_SETTINGS_SAVE_PATH CONFIG_FILE_DIRECTORY_PATH "/f0_mine_sweeper.conf"
+#define MINESWEEPER_SETTINGS_FILE_VERSION 2
+#define CONFIG_FILE_DIRECTORY_PATH EXT_PATH("apps_data/mine_sweeper_redux")
+#define MINESWEEPER_SETTINGS_SAVE_PATH CONFIG_FILE_DIRECTORY_PATH "/mine_sweeper_redux.conf"
 #define MINESWEEPER_SETTINGS_SAVE_PATH_TMP MINESWEEPER_SETTINGS_SAVE_PATH ".tmp"
 #define MINESWEEPER_SETTINGS_SAVE_PATH_TMP MINESWEEPER_SETTINGS_SAVE_PATH ".tmp"
-#define MINESWEEPER_SETTINGS_HEADER "Mine Sweeper Config File"
+#define MINESWEEPER_SETTINGS_HEADER "Mine Sweeper Redux Config File"
 
 
 #define MINESWEEPER_SETTINGS_KEY_WIDTH "BoardWidth"
 #define MINESWEEPER_SETTINGS_KEY_WIDTH "BoardWidth"
 #define MINESWEEPER_SETTINGS_KEY_HEIGHT "BoardHeight"
 #define MINESWEEPER_SETTINGS_KEY_HEIGHT "BoardHeight"
 #define MINESWEEPER_SETTINGS_KEY_DIFFICULTY "BoardDifficulty"
 #define MINESWEEPER_SETTINGS_KEY_DIFFICULTY "BoardDifficulty"
+#define MINESWEEPER_SETTINGS_KEY_FEEDBACK "FeedbackEnabled"
 
 
-#define MINESWEEPER_SETTINGS_KEY_HAPTIC "Haptic"
-#define MINESWEEPER_SETTINGS_KEY_LED "Led"
-#define MINESWEEPER_SETTINGS_KEY_SPEAKER "Speaker"
-
+void mine_sweeper_quick_save_feedback(void* context);
 void mine_sweeper_save_settings(void* context);
 void mine_sweeper_save_settings(void* context);
 bool mine_sweeper_read_settings(void* context);
 bool mine_sweeper_read_settings(void* context);
 
 
-#endif
+#endif

+ 1 - 3
minesweeper/minesweeper.c

@@ -55,9 +55,7 @@ static MineSweeperApp* app_alloc() {
         app->settings_info.board_width = 16;
         app->settings_info.board_width = 16;
         app->settings_info.board_height = 7;
         app->settings_info.board_height = 7;
         app->settings_info.difficulty = 0;
         app->settings_info.difficulty = 0;
-        app->haptic = 1;
-        app->speaker = 1;
-        app->led = 1;
+        app->feedback_enabled = 1;
 
 
         mine_sweeper_save_settings(app);
         mine_sweeper_save_settings(app);
     } else {
     } else {

+ 2 - 4
minesweeper/minesweeper.h

@@ -58,12 +58,10 @@ typedef struct MineSweeperApp {
     MineSweeperAppSettings settings_info;
     MineSweeperAppSettings settings_info;
     MineSweeperAppSettings t_settings_info;
     MineSweeperAppSettings t_settings_info;
 
 
-    bool is_settings_changed;
+    uint8_t is_settings_changed;
     bool ensure_map_solvable;
     bool ensure_map_solvable;
 
 
-    uint32_t haptic;
-    uint32_t speaker;
-    uint32_t led;
+    uint8_t feedback_enabled;
 } MineSweeperApp;
 } MineSweeperApp;
 
 
 // View Id Enumeration
 // View Id Enumeration

+ 13 - 5
minesweeper/scenes/info_scene.c

@@ -1,5 +1,5 @@
 #include "../minesweeper.h"
 #include "../minesweeper.h"
-static const char* info_string = "GAME INFO BELOW\n\n"
+static const char* info_string = "--   GAME INFO BELOW   --\n\n"
                                  "1. Press OK to clear a tile.\n\n"
                                  "1. Press OK to clear a tile.\n\n"
                                  "2. Hold OK on a numbered tile\n"
                                  "2. Hold OK on a numbered tile\n"
                                  "to clear all surrounding\n"
                                  "to clear all surrounding\n"
@@ -10,18 +10,26 @@ static const char* info_string = "GAME INFO BELOW\n\n"
                                  "4. Hold back on a cleared\n"
                                  "4. Hold back on a cleared\n"
                                  "tile to jump to the\n"
                                  "tile to jump to the\n"
                                  "closest tile.\n\n"
                                  "closest tile.\n\n"
-                                 "SETTINGS INFO\n\n"
+                                 "---    SETTINGS INFO    ---\n\n"
                                  "Difficulty and map\n"
                                  "Difficulty and map\n"
                                  "dimensions can be changed\n"
                                  "dimensions can be changed\n"
                                  "in the settings with a\n"
                                  "in the settings with a\n"
                                  "max map size of 1024\n"
                                  "max map size of 1024\n"
-                                 "tiles (32x32).\n\n"
-                                 "ENSURE SOLVABLE\n"
+                                 "tiles (32x32).\n"
+                                 "You will be prompted to\n"
+                                 "confirm any changes to these\n"
+                                 "settings as it will reset the\n"
+                                 "board.\n\n"
+                                 "----      FEEDBACK     ----\n"
+                                 "This settings enables/disables\n"
+                                 "Haptic/Sound feedback for the\n"
+                                 "game.\n\n"
+                                 "-  ENSURE SOLVABLE  -\n"
                                  "This is a setting that\n"
                                  "This is a setting that\n"
                                  "enables a board verifier\n"
                                  "enables a board verifier\n"
                                  "when generating a new\n"
                                  "when generating a new\n"
                                  "board.\n\n"
                                  "board.\n\n"
-                                 "-- WARNING --\n"
+                                 "WARNING!:\n"
                                  "This setting will introduce\n"
                                  "This setting will introduce\n"
                                  "a variable amount of\n"
                                  "a variable amount of\n"
                                  "overhead when generating\n"
                                  "overhead when generating\n"

+ 35 - 3
minesweeper/scenes/settings_scene.c

@@ -21,6 +21,7 @@ typedef enum {
     MineSweeperSettingsScreenEventHeightChange,
     MineSweeperSettingsScreenEventHeightChange,
     MineSweeperSettingsScreenEventSolvableChange,
     MineSweeperSettingsScreenEventSolvableChange,
     MineSweeperSettingsScreenEventInfoChange,
     MineSweeperSettingsScreenEventInfoChange,
+    MineSweeperSettingsScreenEventFeedbackChange,
 } MineSweeperSettingsScreenEvent;
 } MineSweeperSettingsScreenEvent;
 
 
 static const char* settings_screen_difficulty_text[MineSweeperSettingsScreenDifficultyTypeNum] = {
 static const char* settings_screen_difficulty_text[MineSweeperSettingsScreenDifficultyTypeNum] = {
@@ -167,6 +168,23 @@ static void minesweeper_scene_settings_screen_set_solvable(VariableItem* item) {
         app->view_dispatcher, MineSweeperSettingsScreenEventSolvableChange);
         app->view_dispatcher, MineSweeperSettingsScreenEventSolvableChange);
 }
 }
 
 
+static void minesweeper_scene_settings_screen_set_feedback(VariableItem* item) {
+    furi_assert(item);
+
+    MineSweeperApp* app = variable_item_get_context(item);
+
+    uint8_t index = variable_item_get_current_value_index(item);
+
+    app->feedback_enabled = index;
+
+    FURI_LOG_I(TAG, "FEEDBACK CALLBACK INDEX %d", app->feedback_enabled);
+
+    variable_item_set_current_value_text(item, ((index) ? "Enabled" : "Disabled"));
+
+    view_dispatcher_send_custom_event(
+        app->view_dispatcher, MineSweeperSettingsScreenEventFeedbackChange);
+}
+
 static void minesweeper_scene_settings_screen_set_info(VariableItem* item) {
 static void minesweeper_scene_settings_screen_set_info(VariableItem* item) {
     furi_assert(item);
     furi_assert(item);
 
 
@@ -247,6 +265,16 @@ void minesweeper_scene_settings_screen_on_enter(void* context) {
 
 
     variable_item_set_current_value_text(item, settings_screen_verifier_text[idx]);
     variable_item_set_current_value_text(item, settings_screen_verifier_text[idx]);
 
 
+    variable_item_set_current_value_text(item, settings_screen_verifier_text[idx]);
+
+    // Set sound feedback item
+    item = variable_item_list_add(
+        va, "Feedback", 2, minesweeper_scene_settings_screen_set_feedback, app);
+
+    variable_item_set_current_value_index(item, app->feedback_enabled);
+
+    variable_item_set_current_value_text(item, ((app->feedback_enabled) ? "Enabled" : "Disabled"));
+
     // Set info item
     // Set info item
     item = variable_item_list_add(
     item = variable_item_list_add(
         va, "Right For Info", 2, minesweeper_scene_settings_screen_set_info, app);
         va, "Right For Info", 2, minesweeper_scene_settings_screen_set_info, app);
@@ -291,19 +319,23 @@ bool minesweeper_scene_settings_screen_on_event(void* context, SceneManagerEvent
 
 
         case MineSweeperSettingsScreenEventInfoChange:
         case MineSweeperSettingsScreenEventInfoChange:
 
 
-            scene_manager_next_scene(app->scene_manager, MineSweeperSceneInfoScreen);
+        case MineSweeperSettingsScreenEventFeedbackChange:
+            // If only the feedback option is changed we can just save without restarting
+            mine_sweeper_save_settings(app);
             break;
             break;
-
         default:
         default:
             break;
             break;
         };
         };
         consumed = true;
         consumed = true;
 
 
     } else if(event.type == SceneManagerEventTypeBack) {
     } else if(event.type == SceneManagerEventTypeBack) {
-        // If there are changes in the width, height, or difficulty go to confirmation scren
         if(app->is_settings_changed) {
         if(app->is_settings_changed) {
+            // If there are changes in the width, height, or difficulty go to confirmation screen for restart
+
             scene_manager_next_scene(app->scene_manager, MineSweeperSceneConfirmationScreen);
             scene_manager_next_scene(app->scene_manager, MineSweeperSceneConfirmationScreen);
         } else {
         } else {
+            // Otherwise just go back
+
             memset(&app->t_settings_info, 0, sizeof(app->t_settings_info));
             memset(&app->t_settings_info, 0, sizeof(app->t_settings_info));
 
 
             if(!scene_manager_search_and_switch_to_previous_scene(
             if(!scene_manager_search_and_switch_to_previous_scene(

+ 410 - 482
minesweeper/views/minesweeper_game_screen.c

@@ -1,12 +1,4 @@
 #include "minesweeper_game_screen.h"
 #include "minesweeper_game_screen.h"
-#include "minesweeper_redux_icons.h"
-
-#include <gui/elements.h>
-#include <gui/icon_animation.h>
-#include <input/input.h>
-
-#include <furi.h>
-#include <furi_hal.h>
 
 
 static const Icon* tile_icons[13] = {
 static const Icon* tile_icons[13] = {
     &I_tile_empty_8x8,
     &I_tile_empty_8x8,
@@ -77,8 +69,9 @@ typedef struct {
     uint32_t start_tick;
     uint32_t start_tick;
     FuriString* info_str;
     FuriString* info_str;
     bool ensure_solvable_board;
     bool ensure_solvable_board;
-    bool is_win_triggered;
+    bool is_restart_triggered;
     bool is_holding_down_button;
     bool is_holding_down_button;
+    bool has_lost_game;
 } MineSweeperGameScreenModel;
 } MineSweeperGameScreenModel;
 
 
 // Multipliers for ratio of mines to tiles
 // Multipliers for ratio of mines to tiles
@@ -143,15 +136,15 @@ static void mine_sweeper_game_screen_set_board_information(
 
 
 static bool try_clear_surrounding_tiles(MineSweeperGameScreenModel* model);
 static bool try_clear_surrounding_tiles(MineSweeperGameScreenModel* model);
 
 
-static Point bfs_to_closest_tile(MineSweeperGameScreenModel* model);
+static void
+    bfs_to_closest_tile(MineSweeperGameScreen* instance, MineSweeperGameScreenModel* model);
 
 
 // Currently not using enter/exit callback
 // Currently not using enter/exit callback
 static void mine_sweeper_game_screen_view_enter(void* context);
 static void mine_sweeper_game_screen_view_enter(void* context);
 static void mine_sweeper_game_screen_view_exit(void* context);
 static void mine_sweeper_game_screen_view_exit(void* context);
 
 
 // Different input/draw callbacks for play/win/lose state
 // Different input/draw callbacks for play/win/lose state
-static void mine_sweeper_game_screen_view_win_draw_callback(Canvas* canvas, void* _model);
-static void mine_sweeper_game_screen_view_lose_draw_callback(Canvas* canvas, void* _model);
+static void mine_sweeper_game_screen_view_end_draw_callback(Canvas* canvas, void* _model);
 static void mine_sweeper_game_screen_view_play_draw_callback(Canvas* canvas, void* _model);
 static void mine_sweeper_game_screen_view_play_draw_callback(Canvas* canvas, void* _model);
 
 
 // These consolidate the function calls for led/haptic/sound for specific events
 // These consolidate the function calls for led/haptic/sound for specific events
@@ -163,6 +156,17 @@ static void mine_sweeper_oob_effect(void* context);
 static void mine_sweeper_lose_effect(void* context);
 static void mine_sweeper_lose_effect(void* context);
 static void mine_sweeper_win_effect(void* context);
 static void mine_sweeper_win_effect(void* context);
 
 
+static inline bool handle_player_move(
+    MineSweeperGameScreen* instance,
+    MineSweeperGameScreenModel* model,
+    InputEvent* event);
+static int8_t
+    handle_short_ok_input(MineSweeperGameScreen* instance, MineSweeperGameScreenModel* model);
+static int8_t
+    handle_long_ok_input(MineSweeperGameScreen* instance, MineSweeperGameScreenModel* model);
+static bool
+    handle_long_back_flag_input(MineSweeperGameScreen* instance, MineSweeperGameScreenModel* model);
+
 static bool mine_sweeper_game_screen_view_end_input_callback(InputEvent* event, void* context);
 static bool mine_sweeper_game_screen_view_end_input_callback(InputEvent* event, void* context);
 static bool mine_sweeper_game_screen_view_play_input_callback(InputEvent* event, void* context);
 static bool mine_sweeper_game_screen_view_play_input_callback(InputEvent* event, void* context);
 
 
@@ -197,7 +201,7 @@ static void setup_board(MineSweeperGameScreen* instance) {
      * and manipulate then save to actual model
      * and manipulate then save to actual model
      */
      */
     MineSweeperGameScreenTileType tiles[MINESWEEPER_BOARD_MAX_TILES];
     MineSweeperGameScreenTileType tiles[MINESWEEPER_BOARD_MAX_TILES];
-    memset(&tiles, MineSweeperGameScreenTileNone, sizeof(tiles));
+    memset(&tiles, MineSweeperGameScreenTileZero, sizeof(tiles));
 
 
     // Randomly place tiles except in the corners to help guarantee solvability
     // Randomly place tiles except in the corners to help guarantee solvability
     for(uint16_t i = 0; i < num_mines; i++) {
     for(uint16_t i = 0; i < num_mines; i++) {
@@ -272,7 +276,8 @@ static void setup_board(MineSweeperGameScreen* instance) {
             model->curr_pos.y_abs = 0;
             model->curr_pos.y_abs = 0;
             model->right_boundary = MINESWEEPER_SCREEN_TILE_WIDTH;
             model->right_boundary = MINESWEEPER_SCREEN_TILE_WIDTH;
             model->bottom_boundary = MINESWEEPER_SCREEN_TILE_HEIGHT;
             model->bottom_boundary = MINESWEEPER_SCREEN_TILE_HEIGHT;
-            model->is_win_triggered = false;
+            model->is_restart_triggered = false;
+            model->has_lost_game = false;
         },
         },
         true);
         true);
 }
 }
@@ -638,7 +643,7 @@ static bool try_clear_surrounding_tiles(MineSweeperGameScreenModel* model) {
 
 
     MineSweeperTile tile = model->board[curr_pos_1d];
     MineSweeperTile tile = model->board[curr_pos_1d];
 
 
-    // Return true if tile is zero tile or not cleared
+    // Return false if tile is zero tile or not cleared
     if(tile.tile_state != MineSweeperGameScreenTileStateCleared ||
     if(tile.tile_state != MineSweeperGameScreenTileStateCleared ||
        tile.tile_type == MineSweeperGameScreenTileZero) {
        tile.tile_type == MineSweeperGameScreenTileZero) {
         return false;
         return false;
@@ -695,7 +700,8 @@ static bool try_clear_surrounding_tiles(MineSweeperGameScreenModel* model) {
  * Function is used on a long backpress on a cleared tile and returns the position
  * Function is used on a long backpress on a cleared tile and returns the position
  * of the first found uncleared tile using a bfs search
  * of the first found uncleared tile using a bfs search
  */
  */
-static inline Point bfs_to_closest_tile(MineSweeperGameScreenModel* model) {
+static void
+    bfs_to_closest_tile(MineSweeperGameScreen* instance, MineSweeperGameScreenModel* model) {
     furi_assert(model);
     furi_assert(model);
 
 
     // Init both the set and dequeue
     // Init both the set and dequeue
@@ -706,7 +712,7 @@ static inline Point bfs_to_closest_tile(MineSweeperGameScreenModel* model) {
     point_set_init(set);
     point_set_init(set);
 
 
     // Return the value in this point
     // Return the value in this point
-    Point result;
+    Point result = (Point){.x = 0, .y = 0};
 
 
     // Point_t pos will be used to keep track of the current point
     // Point_t pos will be used to keep track of the current point
     Point_t pos;
     Point_t pos;
@@ -757,100 +763,317 @@ static inline Point bfs_to_closest_tile(MineSweeperGameScreenModel* model) {
     point_set_clear(set);
     point_set_clear(set);
     point_deq_clear(deq);
     point_deq_clear(deq);
 
 
-    return result;
+    // Save cursor to new closest tile position
+    // If the cursor moves outisde of the model boundaries we need to
+    // move the boundary appropriately
+
+    model->curr_pos.x_abs = result.x;
+    model->curr_pos.y_abs = result.y;
+
+    bool is_outside_top_boundary = model->curr_pos.x_abs <
+                                   (model->bottom_boundary - MINESWEEPER_SCREEN_TILE_HEIGHT);
+
+    bool is_outside_bottom_boundary = model->curr_pos.x_abs >= model->bottom_boundary;
+
+    bool is_outside_left_boundary = model->curr_pos.y_abs <
+                                    (model->right_boundary - MINESWEEPER_SCREEN_TILE_WIDTH);
+
+    bool is_outside_right_boundary = model->curr_pos.y_abs >= model->right_boundary;
+
+    if(is_outside_top_boundary) {
+        model->bottom_boundary = model->curr_pos.x_abs + MINESWEEPER_SCREEN_TILE_HEIGHT;
+    } else if(is_outside_bottom_boundary) {
+        model->bottom_boundary = model->curr_pos.x_abs + 1;
+    }
+
+    if(is_outside_right_boundary) {
+        model->right_boundary = model->curr_pos.y_abs + 1;
+    } else if(is_outside_left_boundary) {
+        model->right_boundary = model->curr_pos.y_abs + MINESWEEPER_SCREEN_TILE_WIDTH;
+    }
+
+    mine_sweeper_play_happy_bump(instance->context);
 }
 }
 
 
-static void mine_sweeper_game_screen_view_enter(void* context) {
+static void mine_sweeper_short_ok_effect(void* context) {
     furi_assert(context);
     furi_assert(context);
-    UNUSED(context);
+    MineSweeperGameScreen* instance = context;
+
+    mine_sweeper_led_blink_magenta(instance->context);
+    mine_sweeper_play_ok_sound(instance->context);
+    mine_sweeper_play_happy_bump(instance->context);
+    mine_sweeper_stop_all_sound(instance->context);
 }
 }
 
 
-static void mine_sweeper_game_screen_view_exit(void* context) {
+static void mine_sweeper_long_ok_effect(void* context) {
     furi_assert(context);
     furi_assert(context);
-    UNUSED(context);
+    MineSweeperGameScreen* instance = context;
+
+    mine_sweeper_led_blink_magenta(instance->context);
+    mine_sweeper_play_ok_sound(instance->context);
+    mine_sweeper_play_long_ok_bump(instance->context);
+    mine_sweeper_stop_all_sound(instance->context);
 }
 }
 
 
-static void mine_sweeper_game_screen_view_win_draw_callback(Canvas* canvas, void* _model) {
-    furi_assert(canvas);
-    furi_assert(_model);
-    MineSweeperGameScreenModel* model = _model;
+static void mine_sweeper_flag_effect(void* context) {
+    furi_assert(context);
+    MineSweeperGameScreen* instance = context;
 
 
-    canvas_clear(canvas);
+    mine_sweeper_led_blink_cyan(instance->context);
+    mine_sweeper_play_flag_sound(instance->context);
+    mine_sweeper_play_happy_bump(instance->context);
+    mine_sweeper_stop_all_sound(instance->context);
+}
 
 
-    canvas_set_color(canvas, ColorBlack);
+static void mine_sweeper_move_effect(void* context) {
+    furi_assert(context);
+    MineSweeperGameScreen* instance = context;
 
 
-    uint16_t cursor_pos_1d = model->curr_pos.x_abs * model->board_width + model->curr_pos.y_abs;
+    mine_sweeper_play_happy_bump(instance->context);
+}
 
 
-    for(uint8_t x_rel = 0; x_rel < MINESWEEPER_SCREEN_TILE_HEIGHT; x_rel++) {
-        uint16_t x_abs = (model->bottom_boundary - MINESWEEPER_SCREEN_TILE_HEIGHT) + x_rel;
+static void mine_sweeper_oob_effect(void* context) {
+    furi_assert(context);
+    MineSweeperGameScreen* instance = context;
 
 
-        for(uint8_t y_rel = 0; y_rel < MINESWEEPER_SCREEN_TILE_WIDTH; y_rel++) {
-            uint16_t y_abs = (model->right_boundary - MINESWEEPER_SCREEN_TILE_WIDTH) + y_rel;
+    mine_sweeper_led_blink_red(instance->context);
+    mine_sweeper_play_flag_sound(instance->context);
+    mine_sweeper_play_oob_bump(instance->context);
+    mine_sweeper_stop_all_sound(instance->context);
+}
 
 
-            uint16_t curr_rendering_tile_pos_1d = x_abs * model->board_width + y_abs;
-            MineSweeperTile tile = model->board[curr_rendering_tile_pos_1d];
+static void mine_sweeper_lose_effect(void* context) {
+    furi_assert(context);
+    MineSweeperGameScreen* instance = context;
 
 
-            if(cursor_pos_1d == curr_rendering_tile_pos_1d) {
-                canvas_set_color(canvas, ColorWhite);
-            } else {
-                canvas_set_color(canvas, ColorBlack);
-            }
+    mine_sweeper_led_set_rgb(instance->context, 255, 0, 000);
+    mine_sweeper_play_lose_sound(instance->context);
+    mine_sweeper_play_lose_bump(instance->context);
+    mine_sweeper_stop_all_sound(instance->context);
+}
 
 
-            canvas_draw_icon(
-                canvas,
-                y_rel * icon_get_width(tile.icon_element.icon),
-                x_rel * icon_get_height(tile.icon_element.icon),
-                tile.icon_element.icon);
+static void mine_sweeper_win_effect(void* context) {
+    furi_assert(context);
+    MineSweeperGameScreen* instance = context;
+
+    mine_sweeper_led_set_rgb(instance->context, 0, 0, 255);
+    mine_sweeper_play_win_sound(instance->context);
+    mine_sweeper_play_win_bump(instance->context);
+    mine_sweeper_stop_all_sound(instance->context);
+}
+
+static inline bool handle_player_move(
+    MineSweeperGameScreen* instance,
+    MineSweeperGameScreenModel* model,
+    InputEvent* event) {
+    bool consumed = false;
+    bool is_outside_boundary;
+
+    switch(event->key) {
+    case InputKeyUp:
+        (model->curr_pos.x_abs - 1 < 0) ? mine_sweeper_oob_effect(instance) :
+                                          mine_sweeper_move_effect(instance);
+
+        model->curr_pos.x_abs = (model->curr_pos.x_abs - 1 < 0) ? 0 : model->curr_pos.x_abs - 1;
+
+        is_outside_boundary = model->curr_pos.x_abs <
+                              (model->bottom_boundary - MINESWEEPER_SCREEN_TILE_HEIGHT);
+
+        if(is_outside_boundary) {
+            model->bottom_boundary--;
+        }
+
+        consumed = true;
+        break;
+
+    case InputKeyDown:
+
+        (model->curr_pos.x_abs + 1 >= model->board_height) ? mine_sweeper_oob_effect(instance) :
+                                                             mine_sweeper_move_effect(instance);
+
+        model->curr_pos.x_abs = (model->curr_pos.x_abs + 1 >= model->board_height) ?
+                                    model->board_height - 1 :
+                                    model->curr_pos.x_abs + 1;
+
+        is_outside_boundary = model->curr_pos.x_abs >= model->bottom_boundary;
+
+        if(is_outside_boundary) {
+            model->bottom_boundary++;
+        }
+
+        consumed = true;
+        break;
+
+    case InputKeyLeft:
+        (model->curr_pos.y_abs - 1 < 0) ? mine_sweeper_oob_effect(instance) :
+                                          mine_sweeper_move_effect(instance);
+
+        model->curr_pos.y_abs = (model->curr_pos.y_abs - 1 < 0) ? 0 : model->curr_pos.y_abs - 1;
+
+        is_outside_boundary = model->curr_pos.y_abs <
+                              (model->right_boundary - MINESWEEPER_SCREEN_TILE_WIDTH);
+
+        if(is_outside_boundary) {
+            model->right_boundary--;
+        }
+
+        consumed = true;
+        break;
+
+    case InputKeyRight:
+        (model->curr_pos.y_abs + 1 >= model->board_width) ? mine_sweeper_oob_effect(instance) :
+                                                            mine_sweeper_move_effect(instance);
+
+        model->curr_pos.y_abs = (model->curr_pos.y_abs + 1 >= model->board_width) ?
+                                    model->board_width - 1 :
+                                    model->curr_pos.y_abs + 1;
+
+        is_outside_boundary = model->curr_pos.y_abs >= model->right_boundary;
+
+        if(is_outside_boundary) {
+            model->right_boundary++;
         }
         }
+
+        consumed = true;
+        break;
+
+    default:
+        consumed = true;
+        break;
     }
     }
 
 
-    canvas_set_color(canvas, ColorBlack);
-    // If any borders are at the limits of the game board we draw a border line
+    return consumed;
+}
 
 
-    // Right border
-    if(model->right_boundary == model->board_width) {
-        canvas_draw_line(canvas, 127, 0, 127, 63 - 8);
+static int8_t
+    handle_short_ok_input(MineSweeperGameScreen* instance, MineSweeperGameScreenModel* model) {
+    furi_assert(instance);
+    furi_assert(model);
+
+    uint16_t curr_pos_1d = model->curr_pos.x_abs * model->board_width + model->curr_pos.y_abs;
+    bool is_win_condition_triggered = false;
+    bool is_lose_condition_triggered = false;
+
+    MineSweeperGameScreenTileState state = model->board[curr_pos_1d].tile_state;
+    MineSweeperGameScreenTileType type = model->board[curr_pos_1d].tile_type;
+
+    // LOSE/WIN CONDITION OR TILE CLEAR
+    if(state == MineSweeperGameScreenTileStateUncleared && type == MineSweeperGameScreenTileMine) {
+        is_lose_condition_triggered = true;
+        model->board[curr_pos_1d].tile_state = MineSweeperGameScreenTileStateCleared;
+
+    } else if(state == MineSweeperGameScreenTileStateUncleared) {
+        uint16_t tiles_cleared = bfs_tile_clear(
+            model->board,
+            model->board_width,
+            model->board_height,
+            (uint16_t)model->curr_pos.x_abs,
+            (uint16_t)model->curr_pos.y_abs);
+
+        model->tiles_left -= tiles_cleared;
+
+        // Check win condition
+        if(model->mines_left == 0 && model->flags_left == 0 && model->tiles_left == 0) {
+            is_win_condition_triggered = true;
+        } else {
+            // if not met play ok effect
+            mine_sweeper_short_ok_effect(instance);
+        }
     }
     }
 
 
-    // Left border
-    if((model->right_boundary - MINESWEEPER_SCREEN_TILE_WIDTH) == 0) {
-        canvas_draw_line(canvas, 0, 0, 0, 63 - 8);
+    if(is_lose_condition_triggered) {
+        return -1;
+    } else if(is_win_condition_triggered) {
+        return 1;
     }
     }
 
 
-    // Bottom border
-    if(model->bottom_boundary == model->board_height) {
-        canvas_draw_line(canvas, 0, 63 - 8, 127, 63 - 8);
+    return 0;
+}
+
+static int8_t
+    handle_long_ok_input(MineSweeperGameScreen* instance, MineSweeperGameScreenModel* model) {
+    furi_assert(instance);
+    furi_assert(model);
+
+    uint16_t curr_pos_1d = model->curr_pos.x_abs * model->board_width + model->curr_pos.y_abs;
+    bool is_win_condition_triggered = false;
+    bool is_lose_condition_triggered = false;
+
+    MineSweeperGameScreenTileType type = model->board[curr_pos_1d].tile_type;
+
+    // Try to clear surrounding tiles if correct number is flagged.
+    is_lose_condition_triggered = try_clear_surrounding_tiles(model);
+    model->is_holding_down_button = true;
+
+    // Check win condition
+    if(model->mines_left == 0 && model->flags_left == 0 && model->tiles_left == 0) {
+        is_win_condition_triggered = true;
     }
     }
 
 
-    // Top border
-    if((model->bottom_boundary - MINESWEEPER_SCREEN_TILE_HEIGHT) == 0) {
-        canvas_draw_line(canvas, 0, 0, 127, 0);
+    // We need to check if it is ok to play this or else we conflict
+    // with the lose effect and crash
+    if(!is_win_condition_triggered && !is_lose_condition_triggered &&
+       type != MineSweeperGameScreenTileZero) {
+        mine_sweeper_long_ok_effect(instance);
     }
     }
 
 
-    // Draw win text
-    furi_string_printf(model->info_str, "YOU WIN!");
+    if(is_lose_condition_triggered) {
+        return -1;
+    } else if(is_win_condition_triggered) {
+        return 1;
+    }
 
 
-    canvas_draw_str_aligned(
-        canvas, 0, 64 - 7, AlignLeft, AlignTop, furi_string_get_cstr(model->info_str));
+    return 0;
+}
 
 
-    // Draw time text
-    uint32_t ticks_elapsed = furi_get_tick() - model->start_tick;
-    uint32_t sec = ticks_elapsed / furi_kernel_get_tick_frequency();
-    uint32_t minutes = sec / 60;
-    sec = sec % 60;
+static bool handle_long_back_flag_input(
+    MineSweeperGameScreen* instance,
+    MineSweeperGameScreenModel* model) {
+    furi_assert(instance);
+    furi_assert(model);
 
 
-    furi_string_printf(model->info_str, "%02ld:%02ld", minutes, sec);
+    uint16_t curr_pos_1d = model->curr_pos.x_abs * model->board_width + model->curr_pos.y_abs;
+    MineSweeperGameScreenTileState state = model->board[curr_pos_1d].tile_state;
 
 
-    canvas_draw_str_aligned(
-        canvas,
-        126 - canvas_string_width(canvas, furi_string_get_cstr(model->info_str)),
-        64 - 7,
-        AlignLeft,
-        AlignTop,
-        furi_string_get_cstr(model->info_str));
+    bool is_win_condition_triggered = false;
+
+    if(state == MineSweeperGameScreenTileStateFlagged) {
+        if(model->board[curr_pos_1d].tile_type == MineSweeperGameScreenTileMine)
+            model->mines_left++;
+        model->board[curr_pos_1d].tile_state = MineSweeperGameScreenTileStateUncleared;
+        model->flags_left++;
+
+    } else if(model->flags_left > 0) {
+        if(model->board[curr_pos_1d].tile_type == MineSweeperGameScreenTileMine)
+            model->mines_left--;
+        model->board[curr_pos_1d].tile_state = MineSweeperGameScreenTileStateFlagged;
+        model->flags_left--;
+    }
+
+    // WIN CONDITION
+    // This can be a win condition where the non-mine tiles are cleared and they place the last flag
+    if(model->flags_left == 0 && model->mines_left == 0 && model->tiles_left == 0) {
+        is_win_condition_triggered = true;
+        mine_sweeper_win_effect(instance);
+        mine_sweeper_led_set_rgb(instance->context, 0, 0, 255);
+    } else {
+        mine_sweeper_flag_effect(instance);
+    }
+
+    return is_win_condition_triggered;
+}
+
+static void mine_sweeper_game_screen_view_enter(void* context) {
+    furi_assert(context);
+    UNUSED(context);
 }
 }
 
 
-static void mine_sweeper_game_screen_view_lose_draw_callback(Canvas* canvas, void* _model) {
+static void mine_sweeper_game_screen_view_exit(void* context) {
+    furi_assert(context);
+    UNUSED(context);
+}
+
+static void mine_sweeper_game_screen_view_end_draw_callback(Canvas* canvas, void* _model) {
     furi_assert(canvas);
     furi_assert(canvas);
     furi_assert(_model);
     furi_assert(_model);
     MineSweeperGameScreenModel* model = _model;
     MineSweeperGameScreenModel* model = _model;
@@ -905,8 +1128,16 @@ static void mine_sweeper_game_screen_view_lose_draw_callback(Canvas* canvas, voi
         canvas_draw_line(canvas, 0, 0, 127, 0);
         canvas_draw_line(canvas, 0, 0, 127, 0);
     }
     }
 
 
-    // Draw lose text
-    furi_string_printf(model->info_str, "YOU LOSE!");
+    const char* end_status_str = "";
+
+    if(model->has_lost_game) {
+        end_status_str = "YOU LOSE!  PRESS OK.\0";
+    } else {
+        end_status_str = "YOU WIN!   PRESS OK.\0";
+    }
+
+    // Draw win/lose text
+    furi_string_printf(model->info_str, "%s", end_status_str);
 
 
     canvas_draw_str_aligned(
     canvas_draw_str_aligned(
         canvas, 0, 64 - 7, AlignLeft, AlignTop, furi_string_get_cstr(model->info_str));
         canvas, 0, 64 - 7, AlignLeft, AlignTop, furi_string_get_cstr(model->info_str));
@@ -1041,73 +1272,6 @@ static void mine_sweeper_game_screen_view_play_draw_callback(Canvas* canvas, voi
         furi_string_get_cstr(model->info_str));
         furi_string_get_cstr(model->info_str));
 }
 }
 
 
-static void mine_sweeper_short_ok_effect(void* context) {
-    furi_assert(context);
-    MineSweeperGameScreen* instance = context;
-
-    mine_sweeper_led_blink_magenta(instance->context);
-    mine_sweeper_play_ok_sound(instance->context);
-    mine_sweeper_play_happy_bump(instance->context);
-    mine_sweeper_stop_all_sound(instance->context);
-}
-
-static void mine_sweeper_long_ok_effect(void* context) {
-    furi_assert(context);
-    MineSweeperGameScreen* instance = context;
-
-    mine_sweeper_led_blink_magenta(instance->context);
-    mine_sweeper_play_ok_sound(instance->context);
-    mine_sweeper_play_long_ok_bump(instance->context);
-    mine_sweeper_stop_all_sound(instance->context);
-}
-
-static void mine_sweeper_flag_effect(void* context) {
-    furi_assert(context);
-    MineSweeperGameScreen* instance = context;
-
-    mine_sweeper_led_blink_cyan(instance->context);
-    mine_sweeper_play_flag_sound(instance->context);
-    mine_sweeper_play_happy_bump(instance->context);
-    mine_sweeper_stop_all_sound(instance->context);
-}
-
-static void mine_sweeper_move_effect(void* context) {
-    furi_assert(context);
-    MineSweeperGameScreen* instance = context;
-
-    mine_sweeper_play_happy_bump(instance->context);
-}
-
-static void mine_sweeper_oob_effect(void* context) {
-    furi_assert(context);
-    MineSweeperGameScreen* instance = context;
-
-    mine_sweeper_led_blink_red(instance->context);
-    mine_sweeper_play_flag_sound(instance->context);
-    mine_sweeper_play_oob_bump(instance->context);
-    mine_sweeper_stop_all_sound(instance->context);
-}
-
-static void mine_sweeper_lose_effect(void* context) {
-    furi_assert(context);
-    MineSweeperGameScreen* instance = context;
-
-    mine_sweeper_led_set_rgb(instance->context, 255, 0, 000);
-    mine_sweeper_play_lose_sound(instance->context);
-    mine_sweeper_play_lose_bump(instance->context);
-    mine_sweeper_stop_all_sound(instance->context);
-}
-
-static void mine_sweeper_win_effect(void* context) {
-    furi_assert(context);
-    MineSweeperGameScreen* instance = context;
-
-    mine_sweeper_led_set_rgb(instance->context, 0, 0, 255);
-    mine_sweeper_play_win_sound(instance->context);
-    mine_sweeper_play_win_bump(instance->context);
-    mine_sweeper_stop_all_sound(instance->context);
-}
-
 static bool mine_sweeper_game_screen_view_end_input_callback(InputEvent* event, void* context) {
 static bool mine_sweeper_game_screen_view_end_input_callback(InputEvent* event, void* context) {
     furi_assert(context);
     furi_assert(context);
     furi_assert(event);
     furi_assert(event);
@@ -1119,104 +1283,58 @@ static bool mine_sweeper_game_screen_view_end_input_callback(InputEvent* event,
         instance->view,
         instance->view,
         MineSweeperGameScreenModel * model,
         MineSweeperGameScreenModel * model,
         {
         {
-            if(event->type == InputTypeRelease) {
+            if(model->is_holding_down_button && event->type == InputTypeRelease) {
+                //When we lose we are holding the button down, record this release
+
                 model->is_holding_down_button = false;
                 model->is_holding_down_button = false;
                 consumed = true;
                 consumed = true;
+            }
 
 
-            } else if(
-                !model->is_holding_down_button &&
-                (event->type == InputTypePress || event->type == InputTypeRepeat)) {
-                bool is_outside_boundary;
-                switch(event->key) {
-                case InputKeyUp:
-                    model->curr_pos.x_abs =
-                        (model->curr_pos.x_abs - 1 < 0) ? 0 : model->curr_pos.x_abs - 1;
-
-                    is_outside_boundary = model->curr_pos.x_abs < (model->bottom_boundary -
-                                                                   MINESWEEPER_SCREEN_TILE_HEIGHT);
-
-                    if(is_outside_boundary) {
-                        model->bottom_boundary--;
-                    }
-
-                    consumed = true;
-                    break;
-
-                case InputKeyDown:
-                    model->curr_pos.x_abs = (model->curr_pos.x_abs + 1 >= model->board_height) ?
-                                                model->board_height - 1 :
-                                                model->curr_pos.x_abs + 1;
-
-                    is_outside_boundary = model->curr_pos.x_abs >= model->bottom_boundary;
-
-                    if(is_outside_boundary) {
-                        model->bottom_boundary++;
-                    }
-
-                    consumed = true;
-                    break;
-
-                case InputKeyLeft:
-                    model->curr_pos.y_abs =
-                        (model->curr_pos.y_abs - 1 < 0) ? 0 : model->curr_pos.y_abs - 1;
-
-                    is_outside_boundary = model->curr_pos.y_abs <
-                                          (model->right_boundary - MINESWEEPER_SCREEN_TILE_WIDTH);
-
-                    if(is_outside_boundary) {
-                        model->right_boundary--;
-                    }
-
-                    consumed = true;
-                    break;
-
-                case InputKeyRight:
-                    model->curr_pos.y_abs = (model->curr_pos.y_abs + 1 >= model->board_width) ?
-                                                model->board_width - 1 :
-                                                model->curr_pos.y_abs + 1;
+            if(!model->is_holding_down_button && event->key == InputKeyOk &&
+               event->type == InputTypeRelease) {
+                // After release when user presses and releases ok we want to restart the next time this function is pressed
 
 
-                    is_outside_boundary = model->curr_pos.y_abs >= model->right_boundary;
+                model->is_restart_triggered = true;
+                consumed = true;
 
 
-                    if(is_outside_boundary) {
-                        model->right_boundary++;
-                    }
+            } else if(
+                !model->is_holding_down_button && model->is_restart_triggered &&
+                event->key == InputKeyOk) {
+                // After restart flagged is triggered this should also trigger and restart the game
 
 
-                    consumed = true;
-                    break;
+                mine_sweeper_led_reset(instance->context);
 
 
-                default: // Anything other than movement around the screen should restart game
-                    mine_sweeper_led_reset(instance->context);
+                mine_sweeper_game_screen_reset_clock(instance);
+                view_set_draw_callback(
+                    instance->view, mine_sweeper_game_screen_view_play_draw_callback);
+                view_set_input_callback(
+                    instance->view, mine_sweeper_game_screen_view_play_input_callback);
 
 
-                    mine_sweeper_game_screen_reset_clock(instance);
-                    view_set_draw_callback(
-                        instance->view, mine_sweeper_game_screen_view_play_draw_callback);
-                    view_set_input_callback(
-                        instance->view, mine_sweeper_game_screen_view_play_input_callback);
+                // Here we are going to generate a valid map for the player
+                bool is_valid_board = false;
 
 
-                    // Here we are going to generate a valid map for the player
-                    bool is_valid_board = false;
+                size_t memsz = sizeof(MineSweeperTile) * MINESWEEPER_BOARD_MAX_TILES;
 
 
-                    size_t memsz = sizeof(MineSweeperTile) * MINESWEEPER_BOARD_MAX_TILES;
+                do {
+                    setup_board(instance);
 
 
-                    do {
-                        setup_board(instance);
+                    memset(board_t, 0, memsz);
+                    memcpy(
+                        board_t,
+                        model->board,
+                        sizeof(MineSweeperTile) * (model->board_width * model->board_height));
 
 
-                        memset(board_t, 0, memsz);
-                        memcpy(
-                            board_t,
-                            model->board,
-                            sizeof(MineSweeperTile) * (model->board_width * model->board_height));
+                    is_valid_board = check_board_with_verifier(
+                        board_t, model->board_width, model->board_height, model->mines_left);
 
 
-                        is_valid_board = check_board_with_verifier(
-                            board_t, model->board_width, model->board_height, model->mines_left);
+                } while(model->ensure_solvable_board && !is_valid_board);
 
 
-                    } while(model->ensure_solvable_board && !is_valid_board);
+                consumed = true;
 
 
-                    consumed = true;
-                    break;
-                }
+            } else if((event->type == InputTypePress || event->type == InputTypeRepeat)) {
+                // Any other input we consider generic player movement
 
 
-                consumed = true;
+                consumed = handle_player_move(instance, model, event);
             }
             }
         },
         },
         false);
         false);
@@ -1231,300 +1349,110 @@ static bool mine_sweeper_game_screen_view_play_input_callback(InputEvent* event,
     MineSweeperGameScreen* instance = context;
     MineSweeperGameScreen* instance = context;
     bool consumed = false;
     bool consumed = false;
 
 
-    // Checking button types
+    with_view_model(
+        instance->view,
+        MineSweeperGameScreenModel * model,
+        {
+            // Checking button types
 
 
-    if(event->type == InputTypeRelease) {
-        with_view_model(
-            instance->view,
-            MineSweeperGameScreenModel * model,
-            {
+            if(event->type == InputTypeRelease) {
                 model->is_holding_down_button = false;
                 model->is_holding_down_button = false;
                 consumed = true;
                 consumed = true;
-            },
-            true);
-    }
-
-    if(!consumed &&
-       event->key == InputKeyOk) { // Attempt to Clear Space !! THIS CAN BE A LOSE CONDITION
 
 
-        bool is_lose_condition_triggered = false;
-        bool is_win_condition_triggered = false;
+            } else if(event->key == InputKeyOk) { // Attempt to Clear Space !! THIS CAN BE A LOSE CONDITION
 
 
-        with_view_model(
-            instance->view,
-            MineSweeperGameScreenModel * model,
-            {
-                uint16_t curr_pos_1d =
-                    model->curr_pos.x_abs * model->board_width + model->curr_pos.y_abs;
+                bool is_lose_condition_triggered = false;
+                bool is_win_condition_triggered = false;
 
 
                 if(!model->is_holding_down_button && event->type == InputTypePress) {
                 if(!model->is_holding_down_button && event->type == InputTypePress) {
-                    MineSweeperGameScreenTileState state = model->board[curr_pos_1d].tile_state;
-                    MineSweeperGameScreenTileType type = model->board[curr_pos_1d].tile_type;
-
-                    // LOSE/WIN CONDITION OR TILE CLEAR
-                    if(state == MineSweeperGameScreenTileStateUncleared &&
-                       type == MineSweeperGameScreenTileMine) {
-                        is_lose_condition_triggered = true;
-                        model->board[curr_pos_1d].tile_state =
-                            MineSweeperGameScreenTileStateCleared;
-
-                    } else if(state == MineSweeperGameScreenTileStateUncleared) {
-                        uint16_t tiles_cleared = bfs_tile_clear(
-                            model->board,
-                            model->board_width,
-                            model->board_height,
-                            (uint16_t)model->curr_pos.x_abs,
-                            (uint16_t)model->curr_pos.y_abs);
-
-                        model->tiles_left -= tiles_cleared;
-
-                        // Check win condition
-                        if(model->mines_left == 0 && model->flags_left == 0 &&
-                           model->tiles_left == 0) {
-                            is_win_condition_triggered = true;
-                        } else {
-                            // if not met play ok effect
-                            mine_sweeper_short_ok_effect(instance);
-                        }
+                    //ret : -1 lose condition, 1 win condition, 0 neutral
+                    int8_t ret = handle_short_ok_input(instance, model);
+
+                    if(ret != 0) {
+                        (ret == -1) ? (is_lose_condition_triggered = true) :
+                                      (is_win_condition_triggered = true);
                     }
                     }
 
 
                     // LOSE/WIN CONDITION OR CLEAR SURROUNDING
                     // LOSE/WIN CONDITION OR CLEAR SURROUNDING
                 } else if(!model->is_holding_down_button && event->type == InputTypeLong) {
                 } else if(!model->is_holding_down_button && event->type == InputTypeLong) {
-                    // Try to clear surrounding tiles if correct number is flagged.
-                    is_lose_condition_triggered = try_clear_surrounding_tiles(model);
-                    model->is_holding_down_button = true;
-
-                    // Check win condition
-                    if(model->mines_left == 0 && model->flags_left == 0 &&
-                       model->tiles_left == 0) {
-                        is_win_condition_triggered = true;
-                    }
+                    //ret : -1 lose condition, 1 win condition, 0 neutral
+                    int8_t ret = handle_long_ok_input(instance, model);
 
 
-                    // We need to check if it is ok to play this or else we conflict
-                    // with the lose effect and crash
-                    if(!is_win_condition_triggered && !is_lose_condition_triggered &&
-                       model->board[curr_pos_1d].tile_type != MineSweeperGameScreenTileZero) {
-                        mine_sweeper_long_ok_effect(instance);
+                    if(ret != 0) {
+                        (ret == -1) ? (is_lose_condition_triggered = true) :
+                                      (is_win_condition_triggered = true);
                     }
                     }
                 }
                 }
-            },
-            true);
 
 
-        // Check  if win or lose condition was triggered on OK press
-        if(is_lose_condition_triggered) {
-            mine_sweeper_lose_effect(instance);
-            view_set_draw_callback(
-                instance->view, mine_sweeper_game_screen_view_lose_draw_callback);
-            view_set_input_callback(
-                instance->view, mine_sweeper_game_screen_view_end_input_callback);
-        } else if(is_win_condition_triggered) {
-            mine_sweeper_win_effect(instance);
-            view_set_draw_callback(
-                instance->view, mine_sweeper_game_screen_view_win_draw_callback);
-            view_set_input_callback(
-                instance->view, mine_sweeper_game_screen_view_end_input_callback);
-        }
-
-        consumed = true;
-    }
-
-    if(!consumed &&
-       (event->key == InputKeyBack)) { // We can use holding the back button for either
-        // Setting a flag on a covered tile, or moving to
-        // the next closest covered tile on when on a uncovered
-        // tile
-
-        if(event->type == InputTypeLong ||
-           event->type == InputTypeRepeat) { // Only process longer back keys;
-            // short presses should take
-            // us to the menu
-            with_view_model(
-                instance->view,
-                MineSweeperGameScreenModel * model,
-                {
-                    uint16_t curr_pos_1d =
-                        model->curr_pos.x_abs * model->board_width + model->curr_pos.y_abs;
-
-                    MineSweeperGameScreenTileState state = model->board[curr_pos_1d].tile_state;
+                // Check  if win or lose condition was triggered on OK press
+                if(is_lose_condition_triggered) {
+                    model->has_lost_game = true;
+                    mine_sweeper_lose_effect(instance);
 
 
-                    if(state == MineSweeperGameScreenTileStateCleared) {
-                        // BFS to closest uncovered position
-                        Point res = bfs_to_closest_tile(model);
+                    view_set_draw_callback(
+                        instance->view, mine_sweeper_game_screen_view_end_draw_callback);
+                    view_set_input_callback(
+                        instance->view, mine_sweeper_game_screen_view_end_input_callback);
 
 
-                        // Save cursor to new closest tile position
-                        // If the cursor moves outisde of the model boundaries we need to
-                        // move the boundary appropriately
+                } else if(is_win_condition_triggered) {
+                    mine_sweeper_win_effect(instance);
 
 
-                        model->curr_pos.x_abs = res.x;
-                        model->curr_pos.y_abs = res.y;
+                    view_set_draw_callback(
+                        instance->view, mine_sweeper_game_screen_view_end_draw_callback);
+                    view_set_input_callback(
+                        instance->view, mine_sweeper_game_screen_view_end_input_callback);
+                }
 
 
-                        bool is_outside_top_boundary =
-                            model->curr_pos.x_abs <
-                            (model->bottom_boundary - MINESWEEPER_SCREEN_TILE_HEIGHT);
+                consumed = true;
 
 
-                        bool is_outside_bottom_boundary = model->curr_pos.x_abs >=
-                                                          model->bottom_boundary;
+            } else if(event->key == InputKeyBack) { // We can use holding the back button for either
+                // Setting a flag on a covered tile, or moving to
+                // the next closest covered tile on when on a uncovered
+                // tile
 
 
-                        bool is_outside_left_boundary =
-                            model->curr_pos.y_abs <
-                            (model->right_boundary - MINESWEEPER_SCREEN_TILE_WIDTH);
+                if(event->type == InputTypeLong ||
+                   event->type == InputTypeRepeat) { // Only process longer back keys;
+                    // short presses should take
+                    // us to the menu
 
 
-                        bool is_outside_right_boundary = model->curr_pos.y_abs >=
-                                                         model->right_boundary;
+                    bool is_win_condition_triggered = false;
 
 
-                        if(is_outside_top_boundary) {
-                            model->bottom_boundary =
-                                model->curr_pos.x_abs + MINESWEEPER_SCREEN_TILE_HEIGHT;
-                        } else if(is_outside_bottom_boundary) {
-                            model->bottom_boundary = model->curr_pos.x_abs + 1;
-                        }
+                    uint16_t curr_pos_1d =
+                        model->curr_pos.x_abs * model->board_width + model->curr_pos.y_abs;
+                    MineSweeperGameScreenTileState state = model->board[curr_pos_1d].tile_state;
 
 
-                        if(is_outside_right_boundary) {
-                            model->right_boundary = model->curr_pos.y_abs + 1;
-                        } else if(is_outside_left_boundary) {
-                            model->right_boundary =
-                                model->curr_pos.y_abs + MINESWEEPER_SCREEN_TILE_WIDTH;
-                        }
+                    if(state == MineSweeperGameScreenTileStateCleared) {
+                        // BFS to closest uncovered position
+                        bfs_to_closest_tile(instance, model);
 
 
-                        mine_sweeper_play_happy_bump(instance->context);
                         model->is_holding_down_button = true;
                         model->is_holding_down_button = true;
 
 
                         // Flag or Unflag tile and check win condition
                         // Flag or Unflag tile and check win condition
                     } else if(
                     } else if(
                         !model->is_holding_down_button &&
                         !model->is_holding_down_button &&
-                        (state == MineSweeperGameScreenTileStateUncleared ||
-                         state == MineSweeperGameScreenTileStateFlagged)) {
-                        if(state == MineSweeperGameScreenTileStateFlagged) {
-                            if(model->board[curr_pos_1d].tile_type ==
-                               MineSweeperGameScreenTileMine)
-                                model->mines_left++;
-                            model->board[curr_pos_1d].tile_state =
-                                MineSweeperGameScreenTileStateUncleared;
-                            model->flags_left++;
-                            model->is_holding_down_button = true;
-
-                        } else if(model->flags_left > 0) {
-                            if(model->board[curr_pos_1d].tile_type ==
-                               MineSweeperGameScreenTileMine)
-                                model->mines_left--;
-                            model->board[curr_pos_1d].tile_state =
-                                MineSweeperGameScreenTileStateFlagged;
-                            model->flags_left--;
-                            model->is_holding_down_button = true;
-                        }
-
-                        // WIN CONDITION
-                        // This can be a win condition where the non-mine tiles are cleared and they place the last flag
-                        if(model->flags_left == 0 && model->mines_left == 0 &&
-                           model->tiles_left == 0) {
-                            //mine_sweeper_play_long_bump(instance->context);
+                        state != MineSweeperGameScreenTileStateCleared) {
+                        is_win_condition_triggered = handle_long_back_flag_input(instance, model);
 
 
-                            mine_sweeper_win_effect(instance);
-                            mine_sweeper_led_set_rgb(instance->context, 0, 0, 255);
+                        model->is_holding_down_button = true;
 
 
+                        if(is_win_condition_triggered) {
                             view_set_draw_callback(
                             view_set_draw_callback(
-                                instance->view, mine_sweeper_game_screen_view_win_draw_callback);
+                                instance->view, mine_sweeper_game_screen_view_end_draw_callback);
                             view_set_input_callback(
                             view_set_input_callback(
                                 instance->view, mine_sweeper_game_screen_view_end_input_callback);
                                 instance->view, mine_sweeper_game_screen_view_end_input_callback);
-                        } else {
-                            // Making sure that win and flag effect are not played together
-                            mine_sweeper_flag_effect(instance);
                         }
                         }
                     }
                     }
-                },
-                false);
-
-            consumed = true;
-        }
-    }
-
-    if(!consumed &&
-       (event->type == InputTypePress || event->type == InputTypeRepeat)) { // Finally handle move
-
-        with_view_model(
-            instance->view,
-            MineSweeperGameScreenModel * model,
-            {
-                bool is_outside_boundary;
-                switch(event->key) {
-                case InputKeyUp:
-                    (model->curr_pos.x_abs - 1 < 0) ? mine_sweeper_oob_effect(instance) :
-                                                      mine_sweeper_move_effect(instance);
-
-                    model->curr_pos.x_abs =
-                        (model->curr_pos.x_abs - 1 < 0) ? 0 : model->curr_pos.x_abs - 1;
-
-                    is_outside_boundary = model->curr_pos.x_abs < (model->bottom_boundary -
-                                                                   MINESWEEPER_SCREEN_TILE_HEIGHT);
-
-                    if(is_outside_boundary) {
-                        model->bottom_boundary--;
-                    }
-
-                    consumed = true;
-                    break;
-
-                case InputKeyDown:
-
-                    (model->curr_pos.x_abs + 1 >= model->board_height) ?
-                        mine_sweeper_oob_effect(instance) :
-                        mine_sweeper_move_effect(instance);
-
-                    model->curr_pos.x_abs = (model->curr_pos.x_abs + 1 >= model->board_height) ?
-                                                model->board_height - 1 :
-                                                model->curr_pos.x_abs + 1;
-
-                    is_outside_boundary = model->curr_pos.x_abs >= model->bottom_boundary;
-
-                    if(is_outside_boundary) {
-                        model->bottom_boundary++;
-                    }
 
 
                     consumed = true;
                     consumed = true;
-                    break;
-
-                case InputKeyLeft:
-                    (model->curr_pos.y_abs - 1 < 0) ? mine_sweeper_oob_effect(instance) :
-                                                      mine_sweeper_move_effect(instance);
-
-                    model->curr_pos.y_abs =
-                        (model->curr_pos.y_abs - 1 < 0) ? 0 : model->curr_pos.y_abs - 1;
-
-                    is_outside_boundary = model->curr_pos.y_abs <
-                                          (model->right_boundary - MINESWEEPER_SCREEN_TILE_WIDTH);
-
-                    if(is_outside_boundary) {
-                        model->right_boundary--;
-                    }
-
-                    consumed = true;
-                    break;
-
-                case InputKeyRight:
-                    (model->curr_pos.y_abs + 1 >= model->board_width) ?
-                        mine_sweeper_oob_effect(instance) :
-                        mine_sweeper_move_effect(instance);
-
-                    model->curr_pos.y_abs = (model->curr_pos.y_abs + 1 >= model->board_width) ?
-                                                model->board_width - 1 :
-                                                model->curr_pos.y_abs + 1;
-
-                    is_outside_boundary = model->curr_pos.y_abs >= model->right_boundary;
-
-                    if(is_outside_boundary) {
-                        model->right_boundary++;
-                    }
-
-                    consumed = true;
-                    break;
-
-                default:
-                    consumed = true;
-                    break;
                 }
                 }
-            },
-            true);
-    }
+            } else if(
+                event->type == InputTypePress ||
+                event->type == InputTypeRepeat) { // Finally handle move
+
+                consumed = handle_player_move(instance, model, event);
+            }
+        },
+        true);
 
 
     if(!consumed && instance->input_callback != NULL) {
     if(!consumed && instance->input_callback != NULL) {
         consumed = instance->input_callback(event, instance->context);
         consumed = instance->input_callback(event, instance->context);

+ 7 - 0
minesweeper/views/minesweeper_game_screen.h

@@ -8,6 +8,13 @@
 
 
 #include <gui/view.h>
 #include <gui/view.h>
 
 
+#include <gui/elements.h>
+#include <gui/icon_animation.h>
+#include <input/input.h>
+#include <furi.h>
+#include <furi_hal.h>
+
+#include "minesweeper_redux_icons.h"
 #include "minesweeper_game_screen_i.h"
 #include "minesweeper_game_screen_i.h"
 #include "../helpers/mine_sweeper_haptic.h"
 #include "../helpers/mine_sweeper_haptic.h"
 #include "../helpers/mine_sweeper_led.h"
 #include "../helpers/mine_sweeper_led.h"