From 8ea779874f0405fbe5dd99e13208833ecae4eb42 Mon Sep 17 00:00:00 2001 From: David Volovskiy Date: Thu, 15 Aug 2024 17:02:14 -0400 Subject: [PATCH] Face compares the values correctly now and does a dict lookup first --- .../watch_faces/complication/wordle_face.c | 177 +++++++++++------- .../watch_faces/complication/wordle_face.h | 7 +- 2 files changed, 113 insertions(+), 71 deletions(-) diff --git a/movement/watch_faces/complication/wordle_face.c b/movement/watch_faces/complication/wordle_face.c index f701fc4..13b4b6f 100644 --- a/movement/watch_faces/complication/wordle_face.c +++ b/movement/watch_faces/complication/wordle_face.c @@ -33,9 +33,8 @@ /* TODO: -* Add quick iteration (8x freq to get to the letter we want) -* Fix the word matching (if answer is AAAAA and we put in AACAA, the C blinks) * Add a way to recount previous attempts +* Only allow dictionary attempts - Show "nodict" otherwise */ @@ -106,6 +105,41 @@ static uint32_t get_random(uint32_t max) { #endif } +static uint8_t get_first_pos(WordleLetterResult *word_elements_result) { + for (size_t i = 0; i < WORDLE_LENGTH; i++) { + if (word_elements_result[i] != WORDLE_LETTER_CORRECT) + return i; + } + return 0; +} + +static uint8_t get_next_pos(uint8_t curr_pos, WordleLetterResult *word_elements_result) { + for (size_t pos = curr_pos+1; pos < WORDLE_LENGTH; pos++) { + if (word_elements_result[pos] != WORDLE_LETTER_CORRECT) + return pos; + } + return WORDLE_LENGTH; +} + +static uint8_t get_prev_pos(uint8_t curr_pos, WordleLetterResult *word_elements_result) { + if (curr_pos == 0) return 0; + for (size_t pos = curr_pos-1; pos > 0; pos--) { + if (word_elements_result[pos] != WORDLE_LETTER_CORRECT) + return pos; + } + return curr_pos; +} + +static void get_next_letter(uint8_t curr_pos, uint8_t *word_elements) { + if (word_elements[curr_pos] >= _num_valid_letters) word_elements[curr_pos] = 0; + else word_elements[curr_pos] = (word_elements[curr_pos] + 1) % _num_valid_letters; +} + +static void get_prev_letter(uint8_t curr_pos, uint8_t *word_elements) { + if (word_elements[curr_pos] >= _num_valid_letters) word_elements[curr_pos] = _num_valid_letters - 1; + else word_elements[curr_pos] = (word_elements[curr_pos] + _num_valid_letters - 1) % _num_valid_letters; +} + static void display_letter(wordle_state_t *state, bool display_dash) { char buf[1 + 1]; if (state->word_elements[state->position] >= _num_valid_letters) { @@ -121,6 +155,7 @@ static void display_letter(wordle_state_t *state, bool display_dash) { static void display_all_letters(wordle_state_t *state) { uint8_t prev_pos = state->position; + watch_display_string(" ", 4); for (size_t i = 0; i < WORDLE_LENGTH; i++) { state->position = i; display_letter(state, false); @@ -128,31 +163,47 @@ static void display_all_letters(wordle_state_t *state) { state->position = prev_pos; } +static bool check_word_in_dict(uint8_t *word_elements) { + bool is_exact_match; + for (uint16_t i = 0; i < _num_words; i++) { + is_exact_match = true; + for (size_t j = 0; j < WORDLE_LENGTH; j++) { + if (_valid_letters[word_elements[j]] != _legal_words[i][j]) { + is_exact_match = false; + break; + } + } + if (is_exact_match) return true; + } + return false; +} + static bool check_word(wordle_state_t *state) { - WordleLetterResult checked_letter_in_answer[WORDLE_LENGTH] = {WORDLE_LETTER_WRONG}; // Exact bool is_exact_match = true; for (size_t i = 0; i < WORDLE_LENGTH; i++) { - if (_valid_letters[state->word_elements[i]] == _legal_words[state->curr_answer][i]) { - state->word_elements_result[i] = checked_letter_in_answer[i] = WORDLE_LETTER_CORRECT; - } + if (_valid_letters[state->word_elements[i]] == _legal_words[state->curr_answer][i]) + state->word_elements_result[i] = WORDLE_LETTER_CORRECT; else { state->word_elements_result[i] = WORDLE_LETTER_WRONG; is_exact_match = false; } } - + if (is_exact_match) return true; // Wrong Location - for (size_t i = 0; i < WORDLE_LENGTH; i++) { + bool answer_found_wrong_loc[WORDLE_LENGTH] = { false }; + for (size_t i = 0; i < WORDLE_LENGTH; i++) { + if (state->word_elements_result[i] != WORDLE_LETTER_WRONG) continue; for (size_t j = 0; j < WORDLE_LENGTH; j++) { - if (checked_letter_in_answer[j] != WORDLE_LETTER_WRONG) continue; + if (answer_found_wrong_loc[j]) continue; if (_valid_letters[state->word_elements[i]] == _legal_words[state->curr_answer][j]) { - state->word_elements_result[i] = checked_letter_in_answer[j] = WORDLE_LETTER_WRONG_LOC; + state->word_elements_result[i] = WORDLE_LETTER_WRONG_LOC; + answer_found_wrong_loc[j] = true; break; } } } - return is_exact_match; + return false; } static void display_attempt(uint8_t attempt) { @@ -161,19 +212,27 @@ static void display_attempt(uint8_t attempt) { watch_display_string(buf, 3); } +static void show_start_of_attempt(wordle_state_t *state) { + for (size_t i = 0; i < WORDLE_LENGTH; i++) { + if (state->word_elements_result[i] != WORDLE_LETTER_CORRECT) + state->word_elements[i] = _num_valid_letters; + } + display_attempt(state->attempt); + display_all_letters(state); + state->position = get_first_pos(state->word_elements_result); + state->curr_screen = SCREEN_PLAYING; +} + static void reset_board(wordle_state_t *state) { for (size_t i = 0; i < WORDLE_LENGTH; i++) { state->word_elements[i] = _num_valid_letters; state->word_elements_result[i] = WORDLE_LETTER_WRONG; } state->curr_answer = get_random(_num_words); - state->position = 0; state->attempt = 1; - state->curr_screen = SCREEN_PLAYING; watch_clear_colon(); watch_display_string(" ", 4); - display_attempt(state->attempt); - display_all_letters(state); + show_start_of_attempt(state); watch_display_string("-", 5); #if __EMSCRIPTEN__ printf("ANSWER: %s\r\n", _legal_words[state->curr_answer]); @@ -182,7 +241,7 @@ static void reset_board(wordle_state_t *state) { static void display_title(wordle_state_t *state) { state->curr_screen = SCREEN_TITLE; - watch_display_string("WO WORDLE", 0); + watch_display_string("WO WordLE", 0); } static void display_streak(wordle_state_t *state) { @@ -211,6 +270,11 @@ static void display_wait(wordle_state_t *state) { } #endif +static void display_not_in_dict(wordle_state_t *state) { + state->curr_screen = SCREEN_NO_DICT; + watch_display_string("WO nodict", 0); +} + static void display_lose(wordle_state_t *state, uint8_t subsecond) { char buf[WORDLE_LENGTH + 6]; sprintf(buf," L %s", subsecond % 2 ? _legal_words[state->curr_answer] : " "); @@ -224,41 +288,6 @@ static void display_win(wordle_state_t *state, uint8_t subsecond) { watch_display_string(buf, 0); } -static uint8_t get_first_pos(WordleLetterResult *word_elements_result) { - for (size_t i = 0; i < WORDLE_LENGTH; i++) { - if (word_elements_result[i] != WORDLE_LETTER_CORRECT) - return i; - } - return 0; -} - -static uint8_t get_next_pos(uint8_t curr_pos, WordleLetterResult *word_elements_result) { - for (size_t pos = curr_pos+1; pos < WORDLE_LENGTH; pos++) { - if (word_elements_result[pos] != WORDLE_LETTER_CORRECT) - return pos; - } - return WORDLE_LENGTH; -} - -static uint8_t get_prev_pos(uint8_t curr_pos, WordleLetterResult *word_elements_result) { - if (curr_pos == 0) return 0; - for (int8_t pos = curr_pos-1; pos >= 0; pos--) { - if (word_elements_result[pos] != WORDLE_LETTER_CORRECT) - return pos; - } - return curr_pos; -} - -static void get_next_letter(uint8_t curr_pos, uint8_t *word_elements) { - if (word_elements[curr_pos] >= _num_valid_letters) word_elements[curr_pos] = 0; - else word_elements[curr_pos] = (word_elements[curr_pos] + 1) % _num_valid_letters; -} - -static void get_prev_letter(uint8_t curr_pos, uint8_t *word_elements) { - if (word_elements[curr_pos] >= _num_valid_letters) word_elements[curr_pos] = _num_valid_letters - 1; - else word_elements[curr_pos] = (word_elements[curr_pos] + _num_valid_letters - 1) % _num_valid_letters; -} - #if USE_DAILY_STREAK static uint32_t get_day_unix_time(void) { watch_date_time now = watch_rtc_get_date_time(); @@ -295,14 +324,7 @@ static bool act_on_btn(wordle_state_t *state) { switch (state->curr_screen) { case SCREEN_RESULT: - for (size_t i = 0; i < WORDLE_LENGTH; i++) { - if (state->word_elements_result[i] != WORDLE_LETTER_CORRECT) - state->word_elements[i] = _num_valid_letters; - } - display_attempt(state->attempt); - display_all_letters(state); - state->position = get_first_pos(state->word_elements_result); - state->curr_screen = SCREEN_PLAYING; + show_start_of_attempt(state); return true; case SCREEN_TITLE: #if USE_DAILY_STREAK @@ -311,15 +333,24 @@ static bool act_on_btn(wordle_state_t *state) { return true; } #endif - display_streak(state); + if (state->playing) + show_start_of_attempt(state); + else + display_streak(state); return true; case SCREEN_STREAK: +#if USE_DAILY_STREAK + state->curr_day = get_day_unix_time(); +#endif reset_board(state); return true; case SCREEN_WIN: case SCREEN_LOSE: display_title(state); return true; + case SCREEN_NO_DICT: + show_start_of_attempt(state); + return true; #if USE_DAILY_STREAK case SCREEN_WAIT: display_title(state); @@ -346,22 +377,19 @@ void wordle_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void wordle_face_activate(movement_settings_t *settings, void *context) { (void) settings; wordle_state_t *state = (wordle_state_t *)context; - movement_request_tick_frequency(FREQ); #if USE_DAILY_STREAK - if (state->prev_day <= (get_day_unix_time() + (60 *60 * 24))) state->streak = 0; + uint32_t now = get_day_unix_time() ; + if (state->prev_day <= (now + (60 *60 * 24))) state->streak = 0; + if (state->curr_day != now) state->playing = false; #endif - if (state->curr_screen == SCREEN_TITLE) - display_title(state); + movement_request_tick_frequency(FREQ); + display_title(state); } bool wordle_face_loop(movement_event_t event, movement_settings_t *settings, void *context) { wordle_state_t *state = (wordle_state_t *)context; switch (event.event_type) { - case EVENT_ACTIVATE: - if (state->curr_screen == SCREEN_PLAYING) - display_all_letters(state); - break; case EVENT_TICK: switch (state->curr_screen) { @@ -399,10 +427,17 @@ bool wordle_face_loop(movement_event_t event, movement_settings_t *settings, voi if (act_on_btn(state)) break; display_letter(state, true); if (state->word_elements[state->position] == _num_valid_letters) break; + state->playing = true; state->position = get_next_pos(state->position, state->word_elements_result); if (state->position >= WORDLE_LENGTH) { + bool in_dict = check_word_in_dict(state->word_elements); + if (!in_dict) { + display_not_in_dict(state); + break; + } bool exact_match = check_word(state); if (exact_match) { + state->playing = false; state->curr_screen = SCREEN_WIN; state->streak++; #if USE_DAILY_STREAK @@ -411,6 +446,7 @@ bool wordle_face_loop(movement_event_t event, movement_settings_t *settings, voi break; } if (state->attempt++ >= WORDLE_MAX_ATTEMPTS) { + state->playing = false; state->curr_screen = SCREEN_LOSE; state->streak = 0; break; @@ -425,9 +461,12 @@ bool wordle_face_loop(movement_event_t event, movement_settings_t *settings, voi state->position = get_prev_pos(state->position, state->word_elements_result); break; case EVENT_LIGHT_BUTTON_DOWN: - break; + case EVENT_ACTIVATE: case EVENT_TIMEOUT: + break; case EVENT_LOW_ENERGY_UPDATE: + if (state->curr_screen == SCREEN_TITLE) + display_title(state); break; default: return movement_default_loop_handler(event, settings); diff --git a/movement/watch_faces/complication/wordle_face.h b/movement/watch_faces/complication/wordle_face.h index 15b2a94..633d3a2 100644 --- a/movement/watch_faces/complication/wordle_face.h +++ b/movement/watch_faces/complication/wordle_face.h @@ -35,7 +35,7 @@ */ #define WORDLE_LENGTH 5 -#define WORDLE_MAX_ATTEMPTS 5 +#define WORDLE_MAX_ATTEMPTS 6 #define USE_DAILY_STREAK true typedef enum { @@ -55,6 +55,7 @@ typedef enum { #endif SCREEN_WIN, SCREEN_LOSE, + SCREEN_NO_DICT, SCREEN_COUNT } WordleScreen; @@ -64,12 +65,14 @@ typedef struct { WordleLetterResult word_elements_result[WORDLE_LENGTH]; uint8_t attempt : 3; uint8_t position : 3; - uint8_t unused : 2; + bool playing : 1; + bool unused : 1; uint16_t curr_answer; uint8_t streak; WordleScreen curr_screen; #if USE_DAILY_STREAK uint32_t prev_day; + uint32_t curr_day; #endif } wordle_state_t;