Add delays before registering btns, don't repeat words, cleaned up enum names

This commit is contained in:
David Volovskiy
2025-07-08 07:51:36 -04:00
parent 4d2e4172a2
commit 0711622210
3 changed files with 129 additions and 74 deletions

View File

@@ -29,6 +29,7 @@
const watch_face_t watch_faces[] = { const watch_face_t watch_faces[] = {
clock_face, clock_face,
wordle_face,
world_clock_face, world_clock_face,
sunrise_sunset_face, sunrise_sunset_face,
moon_phase_face, moon_phase_face,

View File

@@ -35,7 +35,7 @@ static uint32_t get_random(uint32_t max) {
#endif #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++) { for (size_t i = 0; i < WORDLE_LENGTH; i++) {
if (word_elements_result[i] != WORDLE_LETTER_CORRECT) if (word_elements_result[i] != WORDLE_LETTER_CORRECT)
return i; return i;
@@ -43,7 +43,7 @@ static uint8_t get_first_pos(WordleLetterResult *word_elements_result) {
return 0; 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;) { for (size_t pos = curr_pos; pos < WORDLE_LENGTH;) {
if (word_elements_result[++pos] != WORDLE_LETTER_CORRECT) if (word_elements_result[++pos] != WORDLE_LETTER_CORRECT)
return pos; return pos;
@@ -51,7 +51,7 @@ static uint8_t get_next_pos(uint8_t curr_pos, WordleLetterResult *word_elements_
return WORDLE_LENGTH; 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; if (curr_pos == 0) return 0;
for (int8_t pos = curr_pos; pos >= 0;) { for (int8_t pos = curr_pos; pos >= 0;) {
if (word_elements_result[--pos] != WORDLE_LETTER_CORRECT) 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 #if !WORDLE_ALLOW_NON_WORD_AND_REPEAT_GUESSES
static void display_not_in_dict(wordle_state_t *state) { 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); watch_display_string("nodict", 4);
state->ignore_btn_ticks = WORDLE_TICK_BAD_GUESS;
} }
static void display_already_guessed(wordle_state_t *state) { 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); watch_display_string("GUESSD", 4);
state->ignore_btn_ticks = WORDLE_TICK_BAD_GUESS;
} }
static uint32_t check_word_in_dict(uint8_t *word_elements) { 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; return false;
} }
static void show_skip_wrong_letter_indicator(bool skipping, WordleScreen curr_screen) { static void show_skip_wrong_letter_indicator(bool skipping, wordle_screen curr_screen) {
if (curr_screen >= SCREEN_PLAYING) return; if (curr_screen >= WORDLE_SCREEN_PLAYING) return;
if (skipping) if (skipping)
watch_display_string("H", 3); watch_display_string("H", 3);
else else
@@ -201,7 +203,7 @@ static void display_attempt(uint8_t attempt) {
} }
static void display_playing(wordle_state_t *state) { static void display_playing(wordle_state_t *state) {
state->curr_screen = SCREEN_PLAYING; state->curr_screen = WORDLE_SCREEN_PLAYING;
display_attempt(state->attempt); display_attempt(state->attempt);
display_all_letters(state); 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) { static void reset_board(wordle_state_t *state) {
reset_all_elements(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(); watch_clear_colon();
state->position = get_first_pos(state->word_elements_result); state->position = get_first_pos(state->word_elements_result);
display_playing(state); display_playing(state);
@@ -243,7 +254,7 @@ static void reset_board(wordle_state_t *state) {
} }
static void display_title(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); watch_display_string("WO WordLE", 0);
show_skip_wrong_letter_indicator(state->skip_wrong_letter, state->curr_screen); 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) { static void display_continue(wordle_state_t *state) {
state->curr_screen = SCREEN_CONTINUE; state->curr_screen = WORDLE_SCREEN_CONTINUE;
watch_display_string("Cont ", 4); watch_display_string("Cont ", 4);
show_skip_wrong_letter_indicator(state->skip_wrong_letter, state->curr_screen); show_skip_wrong_letter_indicator(state->skip_wrong_letter, state->curr_screen);
display_continue_result(state->continuing); 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) { static void display_streak(wordle_state_t *state) {
char buf[12]; char buf[12];
state->curr_screen = SCREEN_STREAK; state->curr_screen = WORDLE_SCREEN_STREAK;
#if WORDLE_USE_DAILY_STREAK == 2 #if WORDLE_USE_DAILY_STREAK == 2
if (state->streak > 99) if (state->streak > 99)
sprintf(buf, "WO St--dy"); sprintf(buf, "WO St--dy");
@@ -279,7 +290,7 @@ static void display_streak(wordle_state_t *state) {
#if WORDLE_USE_DAILY_STREAK == 2 #if WORDLE_USE_DAILY_STREAK == 2
static void display_wait(wordle_state_t *state) { static void display_wait(wordle_state_t *state) {
state->curr_screen = SCREEN_WAIT; state->curr_screen = WORDLE_SCREEN_WAIT;
if (state->streak < 40) { if (state->streak < 40) {
char buf[13]; char buf[13];
sprintf(buf,"WO%2d WaIt ", state->streak); 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) { static void display_lose(wordle_state_t *state, uint8_t subsecond) {
char buf[WORDLE_LENGTH + 6]; char buf[WORDLE_LENGTH + 6];
sprintf(buf," L %s", subsecond % 2 ? _valid_words[state->curr_answer] : " "); sprintf(buf,"L %s", subsecond % 2 ? _valid_words[state->curr_answer] : " ");
watch_display_string(buf, 0); watch_display_string(buf, 0);
} }
static void display_win(wordle_state_t *state, uint8_t subsecond) { static void display_win(wordle_state_t *state, uint8_t subsecond) {
(void) state; (void) state;
char buf[13]; char buf[13];
sprintf(buf," W %s ", subsecond % 2 ? "NICE" : "JOb "); sprintf(buf,"W %s ", subsecond % 2 ? "NICE" : "JOb ");
watch_display_string(buf, 0); 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); 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) switch (state->curr_screen)
{ {
case SCREEN_RESULT: case WORDLE_SCREEN_RESULT:
reset_incorrect_elements(state); reset_incorrect_elements(state);
state->position = get_first_pos(state->word_elements_result); state->position = get_first_pos(state->word_elements_result);
display_playing(state); display_playing(state);
return true; return true;
case SCREEN_TITLE: case WORDLE_SCREEN_TITLE:
#if WORDLE_USE_DAILY_STREAK == 2 #if WORDLE_USE_DAILY_STREAK == 2
if (state->day_last_game_started == get_day_unix_time()) { if (state->day_last_game_started == get_day_unix_time()) {
display_wait(state); display_wait(state);
@@ -372,26 +384,26 @@ static bool act_on_btn(wordle_state_t *state, const uint8_t pin) {
display_streak(state); display_streak(state);
#endif #endif
return true; return true;
case SCREEN_STREAK: case WORDLE_SCREEN_STREAK:
state->day_last_game_started = get_day_unix_time(); state->day_last_game_started = get_day_unix_time();
reset_board(state); reset_board(state);
return true; return true;
case SCREEN_WIN: case WORDLE_SCREEN_WIN:
case SCREEN_LOSE: case WORDLE_SCREEN_LOSE:
display_title(state); display_title(state);
return true; return true;
case SCREEN_NO_DICT: case WORDLE_SCREEN_NO_DICT:
case SCREEN_ALREADY_GUESSED: case WORDLE_SCREEN_ALREADY_GUESSED:
state->position = get_first_pos(state->word_elements_result); state->position = get_first_pos(state->word_elements_result);
display_playing(state); display_playing(state);
return true; return true;
#if WORDLE_USE_DAILY_STREAK == 2 #if WORDLE_USE_DAILY_STREAK == 2
case SCREEN_WAIT: case WORDLE_SCREEN_WAIT:
(void) pin; (void) pin;
display_title(state); display_title(state);
return true; return true;
#else #else
case SCREEN_CONTINUE: case WORDLE_SCREEN_CONTINUE:
switch (pin) switch (pin)
{ {
case BTN_ALARM: case BTN_ALARM:
@@ -407,6 +419,8 @@ static bool act_on_btn(wordle_state_t *state, const uint8_t pin) {
state->continuing = !state->continuing; state->continuing = !state->continuing;
display_continue_result(state->continuing); display_continue_result(state->continuing);
break; break;
default:
break;
} }
return true; return true;
#endif #endif
@@ -416,6 +430,13 @@ static bool act_on_btn(wordle_state_t *state, const uint8_t pin) {
return false; 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) { static void get_result(wordle_state_t *state) {
#if !WORDLE_ALLOW_NON_WORD_AND_REPEAT_GUESSES #if !WORDLE_ALLOW_NON_WORD_AND_REPEAT_GUESSES
// Check if it's in the dict // Check if it's in the dict
@@ -437,8 +458,8 @@ static void get_result(wordle_state_t *state) {
#endif #endif
bool exact_match = check_word(state); bool exact_match = check_word(state);
if (exact_match) { if (exact_match) {
reset_all_elements(state); state->curr_screen = WORDLE_SCREEN_WIN;
state->curr_screen = SCREEN_WIN; win_lose_shared(state);
if (state->streak < 0x7F) if (state->streak < 0x7F)
state->streak++; state->streak++;
#if WORDLE_USE_DAILY_STREAK == 2 #if WORDLE_USE_DAILY_STREAK == 2
@@ -447,13 +468,14 @@ static void get_result(wordle_state_t *state) {
return; return;
} }
if (++state->attempt >= WORDLE_MAX_ATTEMPTS) { if (++state->attempt >= WORDLE_MAX_ATTEMPTS) {
reset_all_elements(state); state->curr_screen = WORDLE_SCREEN_LOSE;
state->curr_screen = SCREEN_LOSE; win_lose_shared(state);
state->streak = 0; state->streak = 0;
return; return;
} }
update_known_wrong_letters(state); update_known_wrong_letters(state);
state->curr_screen = SCREEN_RESULT; state->curr_screen = WORDLE_SCREEN_RESULT;
state->ignore_btn_ticks = WORDLE_TICKS_RESULT;
return; return;
} }
@@ -476,21 +498,7 @@ static void insert_random_guess(wordle_state_t *state) {
} }
#endif #endif
void wordle_face_setup(uint8_t watch_face_index, void ** context_ptr) { static void _activate(wordle_state_t *state) {
(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;
#if WORDLE_USE_DAILY_STREAK != 0 #if WORDLE_USE_DAILY_STREAK != 0
uint32_t now = get_day_unix_time(); uint32_t now = get_day_unix_time();
uint32_t one_day = 60 *60 * 24; uint32_t one_day = 60 *60 * 24;
@@ -501,35 +509,58 @@ void wordle_face_activate(void *context) {
} }
#endif #endif
state->using_random_guess = false; 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); reset_incorrect_elements(state);
state->position = get_first_pos(state->word_elements_result); 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); 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) { bool wordle_face_loop(movement_event_t event, void *context) {
wordle_state_t *state = (wordle_state_t *)context; wordle_state_t *state = (wordle_state_t *)context;
switch (event.event_type) { switch (event.event_type) {
case EVENT_TICK: case EVENT_TICK:
if (state->ignore_btn_ticks > 0) state->ignore_btn_ticks--;
switch (state->curr_screen) switch (state->curr_screen)
{ {
case SCREEN_PLAYING: case WORDLE_SCREEN_PLAYING:
if (event.subsecond % 2) { if (event.subsecond % 2) {
display_letter(state, true); display_letter(state, true);
} else { } else {
watch_display_string(" ", state->position + 5); watch_display_string(" ", state->position + 5);
} }
break; break;
case SCREEN_RESULT: case WORDLE_SCREEN_RESULT:
display_result(state, event.subsecond); display_result(state, event.subsecond);
break; break;
case SCREEN_LOSE: case WORDLE_SCREEN_LOSE:
display_lose(state, event.subsecond); display_lose(state, event.subsecond);
break; break;
case SCREEN_WIN: case WORDLE_SCREEN_WIN:
display_win(state, event.subsecond); display_win(state, event.subsecond);
break; break;
default: default:
@@ -542,12 +573,12 @@ bool wordle_face_loop(movement_event_t event, void *context) {
display_letter(state, true); display_letter(state, true);
break; break;
case EVENT_LIGHT_LONG_PRESS: 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; state->skip_wrong_letter = !state->skip_wrong_letter;
show_skip_wrong_letter_indicator(state->skip_wrong_letter, state->curr_screen); show_skip_wrong_letter_indicator(state->skip_wrong_letter, state->curr_screen);
break; 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); get_prev_letter(state->position, state->word_elements, state->known_wrong_letters, state->skip_wrong_letter);
display_letter(state, true); display_letter(state, true);
break; break;
@@ -569,7 +600,7 @@ bool wordle_face_loop(movement_event_t event, void *context) {
} }
break; break;
case EVENT_ALARM_LONG_PRESS: case EVENT_ALARM_LONG_PRESS:
if (state->curr_screen != SCREEN_PLAYING) break; if (state->curr_screen != WORDLE_SCREEN_PLAYING) break;
display_letter(state, true); display_letter(state, true);
state->position = get_prev_pos(state->position, state->word_elements_result); state->position = get_prev_pos(state->position, state->word_elements_result);
break; break;
@@ -577,17 +608,24 @@ bool wordle_face_loop(movement_event_t event, void *context) {
case EVENT_ACTIVATE: case EVENT_ACTIVATE:
break; break;
case EVENT_TIMEOUT: case EVENT_TIMEOUT:
if (state->curr_screen >= SCREEN_RESULT) { if (state->curr_screen >= WORDLE_SCREEN_RESULT) {
reset_incorrect_elements(state); reset_incorrect_elements(state);
state->position = get_first_pos(state->word_elements_result); state->position = get_first_pos(state->word_elements_result);
display_title(state); display_title(state);
} }
break; break;
case EVENT_LOW_ENERGY_UPDATE: case EVENT_LOW_ENERGY_UPDATE:
if (state->curr_screen != SCREEN_TITLE) if (state->curr_screen != WORDLE_SCREEN_TITLE)
display_title(state); display_title(state);
break; 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 movement_default_loop_handler(event);
} }
return true; return true;

View File

@@ -83,7 +83,15 @@
* 2 = Allow using a random guess of any value that can be an answer where all of its letters are unique * 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. * 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" #include "wordle_face_dict.h"
#define WORDLE_NUM_WORDS (sizeof(_valid_words) / sizeof(_valid_words[0])) #define WORDLE_NUM_WORDS (sizeof(_valid_words) / sizeof(_valid_words[0]))
@@ -95,28 +103,34 @@ typedef enum {
WORDLE_LETTER_WRONG_LOC, WORDLE_LETTER_WRONG_LOC,
WORDLE_LETTER_CORRECT, WORDLE_LETTER_CORRECT,
WORDLE_LETTER_COUNT WORDLE_LETTER_COUNT
} WordleLetterResult; } wordle_letter_result;
typedef enum { typedef enum {
SCREEN_TITLE = 0, WORDLE_SCREEN_TITLE = 0,
SCREEN_STREAK, WORDLE_SCREEN_STREAK,
SCREEN_CONTINUE, WORDLE_SCREEN_CONTINUE,
#if WORDLE_USE_DAILY_STREAK #if WORDLE_USE_DAILY_STREAK
SCREEN_WAIT, WORDLE_SCREEN_WAIT,
#endif #endif
SCREEN_PLAYING, WORDLE_SCREEN_PLAYING,
SCREEN_RESULT, WORDLE_SCREEN_RESULT,
SCREEN_WIN, WORDLE_SCREEN_WIN,
SCREEN_LOSE, WORDLE_SCREEN_LOSE,
SCREEN_NO_DICT, WORDLE_SCREEN_NO_DICT,
SCREEN_ALREADY_GUESSED, WORDLE_SCREEN_ALREADY_GUESSED,
SCREEN_COUNT WORDLE_SCREEN_COUNT
} WordleScreen; } wordle_screen;
typedef enum {
BTN_MODE = 0,
BTN_ALARM,
BTN_LIGHT,
} wordle_pin_enum;
typedef struct { typedef struct {
// Anything you need to keep track of, put it here! // Anything you need to keep track of, put it here!
uint8_t word_elements[WORDLE_LENGTH]; 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 #if !WORDLE_ALLOW_NON_WORD_AND_REPEAT_GUESSES
uint16_t guessed_words[WORDLE_MAX_ATTEMPTS]; uint16_t guessed_words[WORDLE_MAX_ATTEMPTS];
#endif #endif
@@ -127,9 +141,12 @@ typedef struct {
bool continuing : 1; bool continuing : 1;
bool skip_wrong_letter : 1; bool skip_wrong_letter : 1;
uint8_t streak; uint8_t streak;
WordleScreen curr_screen; wordle_screen curr_screen;
bool known_wrong_letters[WORDLE_NUM_VALID_LETTERS]; bool known_wrong_letters[WORDLE_NUM_VALID_LETTERS];
uint32_t day_last_game_started; 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; } wordle_state_t;
void wordle_face_setup(uint8_t watch_face_index, void ** context_ptr); 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_ #endif // WORDLE_FACE_H_