]> git.earman.xyz Git - sensor-watch.git/commitdiff
Add delays before registering btns, don't repeat words, cleaned up enum names
authorDavid Volovskiy <devolov@gmail.com>
Tue, 8 Jul 2025 11:51:36 +0000 (07:51 -0400)
committerDavid Volovskiy <devolov@gmail.com>
Tue, 8 Jul 2025 11:51:36 +0000 (07:51 -0400)
movement_config.h
watch-faces/complication/wordle_face.c
watch-faces/complication/wordle_face.h

index 0da8da43ed09ba5f6f82a563ccc765fc1978ab87..c4cb8c368f5d9aec85553a5ef52420f4559f7f79 100644 (file)
@@ -29,6 +29,7 @@
 
 const watch_face_t watch_faces[] = {
     clock_face,
+    wordle_face,
     world_clock_face,
     sunrise_sunset_face,
     moon_phase_face,
index a93a0e0e1b207e3de8fc7c77eea83c1f996eba2d..4873b5a1e44da97f6954f6ca73da2b8fe8d1c3ce 100644 (file)
@@ -35,7 +35,7 @@ static uint32_t get_random(uint32_t max) {
     #endif
 }
 
-static uint8_t get_first_pos(WordleLetterResult *word_elements_result) {
+static uint8_t get_first_pos(wordle_letter_result *word_elements_result) {
     for (size_t i = 0; i < WORDLE_LENGTH; i++) {
         if (word_elements_result[i] != WORDLE_LETTER_CORRECT)
             return i;
@@ -43,7 +43,7 @@ static uint8_t get_first_pos(WordleLetterResult *word_elements_result) {
     return 0;
 }
 
-static uint8_t get_next_pos(uint8_t curr_pos, WordleLetterResult *word_elements_result) {
+static uint8_t get_next_pos(uint8_t curr_pos, wordle_letter_result *word_elements_result) {
     for (size_t pos = curr_pos; pos < WORDLE_LENGTH;) {
         if (word_elements_result[++pos] != WORDLE_LETTER_CORRECT)
             return pos;
@@ -51,7 +51,7 @@ static uint8_t get_next_pos(uint8_t curr_pos, WordleLetterResult *word_elements_
     return WORDLE_LENGTH;
 }
 
-static uint8_t get_prev_pos(uint8_t curr_pos, WordleLetterResult *word_elements_result) {
+static uint8_t get_prev_pos(uint8_t curr_pos, wordle_letter_result *word_elements_result) {
     if (curr_pos == 0) return 0;
     for (int8_t pos = curr_pos; pos >= 0;) {
         if (word_elements_result[--pos] != WORDLE_LETTER_CORRECT)
@@ -99,13 +99,15 @@ static void display_all_letters(wordle_state_t *state) {
 
 #if !WORDLE_ALLOW_NON_WORD_AND_REPEAT_GUESSES
 static void display_not_in_dict(wordle_state_t *state) {
-    state->curr_screen = SCREEN_NO_DICT;
+    state->curr_screen = WORDLE_SCREEN_NO_DICT;
     watch_display_string("nodict", 4);
+    state->ignore_btn_ticks = WORDLE_TICK_BAD_GUESS;
 }
 
 static void display_already_guessed(wordle_state_t *state) {
-    state->curr_screen = SCREEN_ALREADY_GUESSED;
+    state->curr_screen = WORDLE_SCREEN_ALREADY_GUESSED;
     watch_display_string("GUESSD", 4);
+    state->ignore_btn_ticks = WORDLE_TICK_BAD_GUESS;
 }
 
 static uint32_t check_word_in_dict(uint8_t *word_elements) {
@@ -164,8 +166,8 @@ static bool check_word(wordle_state_t *state) {
     return false;
 }
 
-static void show_skip_wrong_letter_indicator(bool skipping, WordleScreen curr_screen) {
-    if (curr_screen >= SCREEN_PLAYING) return;
+static void show_skip_wrong_letter_indicator(bool skipping, wordle_screen curr_screen) {
+    if (curr_screen >= WORDLE_SCREEN_PLAYING) return;
     if (skipping)
         watch_display_string("H", 3);
     else
@@ -201,7 +203,7 @@ static void display_attempt(uint8_t attempt) {
 }
 
 static void display_playing(wordle_state_t *state) {
-    state->curr_screen = SCREEN_PLAYING;
+    state->curr_screen = WORDLE_SCREEN_PLAYING;
     display_attempt(state->attempt);
     display_all_letters(state);
 }
@@ -230,9 +232,18 @@ static void reset_incorrect_elements(wordle_state_t *state) {
     }
 }
 
+static bool is_in_do_not_use_list(uint16_t guess, const uint16_t *not_to_use, uint8_t max_repeats) {
+    for (size_t i = 0; i < max_repeats; i++) {
+        if (guess == not_to_use[i]) return true;
+    }
+    return false;
+}
+
 static void reset_board(wordle_state_t *state) {
     reset_all_elements(state);
-    state->curr_answer = get_random(WORDLE_NUM_WORDS);
+    do {
+        state->curr_answer = get_random(WORDLE_NUM_WORDS);
+     } while (is_in_do_not_use_list(state->curr_answer, state->not_to_use, WORDLE_MAX_BETWEEN_REPEATS));
     watch_clear_colon();
     state->position = get_first_pos(state->word_elements_result);
     display_playing(state);
@@ -243,7 +254,7 @@ static void reset_board(wordle_state_t *state) {
 }
 
 static void display_title(wordle_state_t *state) {
-    state->curr_screen = SCREEN_TITLE;
+    state->curr_screen = WORDLE_SCREEN_TITLE;
     watch_display_string("WO  WordLE", 0);
     show_skip_wrong_letter_indicator(state->skip_wrong_letter, state->curr_screen);
 }
@@ -254,7 +265,7 @@ static void display_continue_result(bool continuing) {
 }
 
 static void display_continue(wordle_state_t *state) {
-    state->curr_screen = SCREEN_CONTINUE;
+    state->curr_screen = WORDLE_SCREEN_CONTINUE;
     watch_display_string("Cont ", 4);
     show_skip_wrong_letter_indicator(state->skip_wrong_letter, state->curr_screen);
     display_continue_result(state->continuing);
@@ -263,7 +274,7 @@ static void display_continue(wordle_state_t *state) {
 
 static void display_streak(wordle_state_t *state) {
     char buf[12];
-    state->curr_screen = SCREEN_STREAK;
+    state->curr_screen = WORDLE_SCREEN_STREAK;
 #if WORDLE_USE_DAILY_STREAK == 2
     if (state->streak > 99)
         sprintf(buf, "WO  St--dy");
@@ -279,7 +290,7 @@ static void display_streak(wordle_state_t *state) {
 
 #if WORDLE_USE_DAILY_STREAK == 2
 static void display_wait(wordle_state_t *state) {
-    state->curr_screen = SCREEN_WAIT;
+    state->curr_screen = WORDLE_SCREEN_WAIT;
     if (state->streak < 40) {
         char buf[13];
         sprintf(buf,"WO%2d WaIt ", state->streak);
@@ -302,14 +313,14 @@ static uint32_t get_day_unix_time(void) {
 
 static void display_lose(wordle_state_t *state, uint8_t subsecond) {
     char buf[WORDLE_LENGTH + 6];
-    sprintf(buf," L   %s", subsecond % 2 ? _valid_words[state->curr_answer] : "     ");
+    sprintf(buf,"   %s", subsecond % 2 ? _valid_words[state->curr_answer] : "     ");
     watch_display_string(buf, 0);
 }
 
 static void display_win(wordle_state_t *state, uint8_t subsecond) {
     (void) state;
     char buf[13];
-    sprintf(buf," W   %s  ", subsecond % 2 ? "NICE" : "JOb ");
+    sprintf(buf,"   %s  ", subsecond % 2 ? "NICE" : "JOb ");
     watch_display_string(buf, 0);
 }
 
@@ -346,15 +357,16 @@ static void display_result(wordle_state_t *state, uint8_t subsecond) {
     watch_display_string(buf, 5);
 }
 
-static bool act_on_btn(wordle_state_t *state, const uint8_t pin) {
+static bool act_on_btn(wordle_state_t *state, const wordle_pin_enum pin) {
+    if (state->ignore_btn_ticks > 0) return true;
     switch (state->curr_screen)
     {
-    case SCREEN_RESULT:
+    case WORDLE_SCREEN_RESULT:
         reset_incorrect_elements(state);
         state->position = get_first_pos(state->word_elements_result);
         display_playing(state);
         return true;
-    case SCREEN_TITLE:
+    case WORDLE_SCREEN_TITLE:
 #if WORDLE_USE_DAILY_STREAK == 2
         if (state->day_last_game_started == get_day_unix_time()) {
             display_wait(state);
@@ -372,26 +384,26 @@ static bool act_on_btn(wordle_state_t *state, const uint8_t pin) {
             display_streak(state);
 #endif
         return true;
-    case SCREEN_STREAK:
+    case WORDLE_SCREEN_STREAK:
         state->day_last_game_started = get_day_unix_time();
         reset_board(state);
         return true;
-    case SCREEN_WIN:
-    case SCREEN_LOSE:
+    case WORDLE_SCREEN_WIN:
+    case WORDLE_SCREEN_LOSE:
         display_title(state);
         return true;
-    case SCREEN_NO_DICT:
-    case SCREEN_ALREADY_GUESSED:
+    case WORDLE_SCREEN_NO_DICT:
+    case WORDLE_SCREEN_ALREADY_GUESSED:
         state->position = get_first_pos(state->word_elements_result);
         display_playing(state);
         return true;
 #if WORDLE_USE_DAILY_STREAK == 2
-    case SCREEN_WAIT:
+    case WORDLE_SCREEN_WAIT:
         (void) pin;
         display_title(state);
         return true;
 #else
-    case SCREEN_CONTINUE:
+    case WORDLE_SCREEN_CONTINUE:
         switch (pin)
         {
         case BTN_ALARM:
@@ -407,6 +419,8 @@ static bool act_on_btn(wordle_state_t *state, const uint8_t pin) {
             state->continuing = !state->continuing;
             display_continue_result(state->continuing);
             break;
+        default:
+            break;
         }
         return true;
 #endif
@@ -416,6 +430,13 @@ static bool act_on_btn(wordle_state_t *state, const uint8_t pin) {
     return false;
 }
 
+static void win_lose_shared(wordle_state_t *state) {
+        reset_all_elements(state);
+        state->ignore_btn_ticks = WORDLE_TICK_WIN_LOSE;
+        state->not_to_use[state->not_to_use_position] = state->curr_answer;
+        state->not_to_use_position = (state->not_to_use_position + 1) % WORDLE_MAX_BETWEEN_REPEATS;        
+}
+
 static void get_result(wordle_state_t *state) {
 #if !WORDLE_ALLOW_NON_WORD_AND_REPEAT_GUESSES
     // Check if it's in the dict
@@ -437,8 +458,8 @@ static void get_result(wordle_state_t *state) {
 #endif
     bool exact_match = check_word(state);
     if (exact_match) {
-        reset_all_elements(state);
-        state->curr_screen = SCREEN_WIN;
+        state->curr_screen = WORDLE_SCREEN_WIN;
+        win_lose_shared(state);
         if (state->streak < 0x7F)
             state->streak++;
 #if WORDLE_USE_DAILY_STREAK == 2
@@ -447,13 +468,14 @@ static void get_result(wordle_state_t *state) {
         return;
     }
     if (++state->attempt >= WORDLE_MAX_ATTEMPTS) {
-        reset_all_elements(state);
-        state->curr_screen = SCREEN_LOSE;
+        state->curr_screen = WORDLE_SCREEN_LOSE;
+        win_lose_shared(state);
         state->streak = 0;
         return;
     }
     update_known_wrong_letters(state);
-    state->curr_screen = SCREEN_RESULT;
+    state->curr_screen = WORDLE_SCREEN_RESULT;
+    state->ignore_btn_ticks = WORDLE_TICKS_RESULT;
     return;
 }
 
@@ -476,21 +498,7 @@ static void insert_random_guess(wordle_state_t *state) {
 }
 #endif
 
-void wordle_face_setup(uint8_t watch_face_index, void ** context_ptr) {
-    (void) watch_face_index;
-    if (*context_ptr == NULL) {
-        *context_ptr = malloc(sizeof(wordle_state_t));
-        memset(*context_ptr, 0, sizeof(wordle_state_t));
-        wordle_state_t *state = (wordle_state_t *)*context_ptr;
-        state->curr_screen = SCREEN_TITLE;
-        state->skip_wrong_letter = false;
-        reset_all_elements(state);
-    }
-    // Do any pin or peripheral setup here; this will be called whenever the watch wakes from deep sleep.
-}
-
-void wordle_face_activate(void *context) {
-    wordle_state_t *state = (wordle_state_t *)context;
+static void _activate(wordle_state_t *state) {
 #if WORDLE_USE_DAILY_STREAK != 0
     uint32_t now = get_day_unix_time();
     uint32_t one_day = 60 *60 * 24;
@@ -501,35 +509,58 @@ void wordle_face_activate(void *context) {
     }
 #endif
     state->using_random_guess = false;
-    if (is_playing(state) && state->curr_screen >= SCREEN_RESULT) {
+    if (is_playing(state) && state->curr_screen >= WORDLE_SCREEN_RESULT) {
         reset_incorrect_elements(state);
         state->position = get_first_pos(state->word_elements_result); 
     }
-    movement_request_tick_frequency(2);
+    movement_request_tick_frequency(WORDLE_FREQ);
+    watch_clear_all_indicators();
+    watch_clear_colon();
     display_title(state);
 }
 
+void wordle_face_setup(uint8_t watch_face_index, void ** context_ptr) {
+    (void) watch_face_index;
+    if (*context_ptr == NULL) {
+        *context_ptr = malloc(sizeof(wordle_state_t));
+        memset(*context_ptr, 0, sizeof(wordle_state_t));
+        wordle_state_t *state = (wordle_state_t *)*context_ptr;
+        state->curr_screen = WORDLE_SCREEN_TITLE;
+        state->skip_wrong_letter = true;
+        reset_all_elements(state);
+        memset(state->not_to_use, 0xff, sizeof(state->not_to_use));
+    }
+    // Do any pin or peripheral setup here; this will be called whenever the watch wakes from deep sleep.
+}
+
+void wordle_face_activate(void *context) {
+    wordle_state_t *state = (wordle_state_t *)context;
+    _activate(state);
+
+}
+
 bool wordle_face_loop(movement_event_t event, void *context) {
     wordle_state_t *state = (wordle_state_t *)context;
 
     switch (event.event_type) {
         case EVENT_TICK:
+            if (state->ignore_btn_ticks > 0) state->ignore_btn_ticks--;
             switch (state->curr_screen)
             {
-            case SCREEN_PLAYING:
+            case WORDLE_SCREEN_PLAYING:
                 if (event.subsecond % 2) {
                     display_letter(state, true);
                 } else {
                     watch_display_string(" ", state->position + 5);
                 }
                 break;
-            case SCREEN_RESULT:
+            case WORDLE_SCREEN_RESULT:
                 display_result(state, event.subsecond);
                 break;
-            case SCREEN_LOSE:
+            case WORDLE_SCREEN_LOSE:
                 display_lose(state, event.subsecond);
                 break;
-            case SCREEN_WIN:
+            case WORDLE_SCREEN_WIN:
                 display_win(state, event.subsecond);
                 break;
             default:
@@ -542,12 +573,12 @@ bool wordle_face_loop(movement_event_t event, void *context) {
             display_letter(state, true);
             break;
         case EVENT_LIGHT_LONG_PRESS:
-            if (state->curr_screen < SCREEN_PLAYING) {
+            if (state->curr_screen < WORDLE_SCREEN_PLAYING) {
                 state->skip_wrong_letter = !state->skip_wrong_letter;
                 show_skip_wrong_letter_indicator(state->skip_wrong_letter, state->curr_screen);
                 break;
             }
-            if (state->curr_screen != SCREEN_PLAYING) break;
+            if (state->curr_screen != WORDLE_SCREEN_PLAYING) break;
             get_prev_letter(state->position, state->word_elements, state->known_wrong_letters, state->skip_wrong_letter);
             display_letter(state, true);
             break; 
@@ -569,7 +600,7 @@ bool wordle_face_loop(movement_event_t event, void *context) {
             }
             break;
         case EVENT_ALARM_LONG_PRESS:
-            if (state->curr_screen != SCREEN_PLAYING) break;
+            if (state->curr_screen != WORDLE_SCREEN_PLAYING) break;
             display_letter(state, true);
             state->position = get_prev_pos(state->position, state->word_elements_result);
             break;
@@ -577,17 +608,24 @@ bool wordle_face_loop(movement_event_t event, void *context) {
         case EVENT_ACTIVATE:
             break;
         case EVENT_TIMEOUT:
-            if (state->curr_screen >= SCREEN_RESULT) {
+            if (state->curr_screen >= WORDLE_SCREEN_RESULT) {
                 reset_incorrect_elements(state);
                 state->position = get_first_pos(state->word_elements_result); 
                 display_title(state);
             }
             break;
         case EVENT_LOW_ENERGY_UPDATE:
-            if (state->curr_screen != SCREEN_TITLE)
+            if (state->curr_screen != WORDLE_SCREEN_TITLE)
                 display_title(state);
             break;
-        default:
+        case EVENT_MODE_LONG_PRESS:
+            if (state->curr_screen >= WORDLE_SCREEN_PLAYING) {
+                _activate(state);
+            } else {
+                movement_move_to_face(0);
+            }
+            break;
+            default:
             return movement_default_loop_handler(event);
     }
     return true;
index 5cc2f09a866de55208dc6f201b6ecaec10963b70..e4f7d0f9e2323d9cc484d3e6564368a874861787 100644 (file)
  *  2 = Allow using a random guess of any value that can be an answer where all of its letters are unique
  *  3 = Allow using a random guess of any value that can be an answer, and it's considered one of the best initial choices.
 */
-#define WORDLE_USE_RANDOM_GUESS 2
+#define WORDLE_USE_RANDOM_GUESS 3
+#define WORDLE_FREQ 2
+// To avoid a button press immedietly skipping a screen, we wait this many ticks
+#define WORDLE_TICKS_RESULT 4  
+#define WORDLE_TICK_WIN_LOSE 2
+#define WORDLE_TICK_BAD_GUESS 0
+
+// Store this many words in our list of words that were already used to avoid too much repetition of guesses
+#define WORDLE_MAX_BETWEEN_REPEATS 50
 #include "wordle_face_dict.h"
 
 #define WORDLE_NUM_WORDS (sizeof(_valid_words) / sizeof(_valid_words[0]))
@@ -95,28 +103,34 @@ typedef enum {
     WORDLE_LETTER_WRONG_LOC,
     WORDLE_LETTER_CORRECT,
     WORDLE_LETTER_COUNT
-} WordleLetterResult;
+} wordle_letter_result;
 
 typedef enum {
-    SCREEN_TITLE = 0,
-    SCREEN_STREAK,
-    SCREEN_CONTINUE,
+    WORDLE_SCREEN_TITLE = 0,
+    WORDLE_SCREEN_STREAK,
+    WORDLE_SCREEN_CONTINUE,
 #if WORDLE_USE_DAILY_STREAK
-    SCREEN_WAIT,
+    WORDLE_SCREEN_WAIT,
 #endif
-    SCREEN_PLAYING,
-    SCREEN_RESULT,
-    SCREEN_WIN,
-    SCREEN_LOSE,
-    SCREEN_NO_DICT,
-    SCREEN_ALREADY_GUESSED,
-    SCREEN_COUNT
-} WordleScreen;
+    WORDLE_SCREEN_PLAYING,
+    WORDLE_SCREEN_RESULT,
+    WORDLE_SCREEN_WIN,
+    WORDLE_SCREEN_LOSE,
+    WORDLE_SCREEN_NO_DICT,
+    WORDLE_SCREEN_ALREADY_GUESSED,
+    WORDLE_SCREEN_COUNT
+} wordle_screen;
+
+typedef enum {
+       BTN_MODE =  0,
+       BTN_ALARM,
+       BTN_LIGHT,
+} wordle_pin_enum;
 
 typedef struct {
     // Anything you need to keep track of, put it here!
     uint8_t word_elements[WORDLE_LENGTH];
-    WordleLetterResult word_elements_result[WORDLE_LENGTH];
+    wordle_letter_result word_elements_result[WORDLE_LENGTH];
 #if !WORDLE_ALLOW_NON_WORD_AND_REPEAT_GUESSES
     uint16_t guessed_words[WORDLE_MAX_ATTEMPTS];
 #endif
@@ -127,9 +141,12 @@ typedef struct {
     bool continuing : 1;
     bool skip_wrong_letter : 1;
     uint8_t streak;
-    WordleScreen curr_screen;
+    wordle_screen curr_screen;
     bool known_wrong_letters[WORDLE_NUM_VALID_LETTERS];
     uint32_t day_last_game_started;
+    uint8_t ignore_btn_ticks;
+    uint16_t not_to_use[WORDLE_MAX_BETWEEN_REPEATS];
+    uint8_t not_to_use_position;
 } wordle_state_t;
 
 void wordle_face_setup(uint8_t watch_face_index, void ** context_ptr);
@@ -146,4 +163,3 @@ void wordle_face_resign(void *context);
 })
 
 #endif // WORDLE_FACE_H_
-