From bdaf00129dd46c241cfed1710d9c1969e9c00347 Mon Sep 17 00:00:00 2001 From: talksik Date: Sun, 27 Sep 2026 11:34:55 -0700 Subject: [PATCH] refactor: add game state abstraction --- game_state.c | 72 +++++++++++++++++++++++++++++ game_state.h | 17 +++++++ main.c | 126 ++++++++++++++++++++++++--------------------------- 3 files changed, 147 insertions(+), 68 deletions(-) create mode 100644 game_state.c create mode 100644 game_state.h diff --git a/game_state.c b/game_state.c new file mode 100644 index 0000000..cc521e4 --- /dev/null +++ b/game_state.c @@ -0,0 +1,72 @@ +#include "game_state.h" +#include +#include +#include + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + +char *word_bank[] = { + "hypothesis", + "science", + "usurp", + "conditional", + "passionate", + "orion", + NULL // sentinel value marking end +}; + +struct game_state { + char **curr_el; + unsigned short curr_letter_index; + unsigned short wins; +}; + +static struct game_state state; + +void init_game_state() { + state.curr_el = word_bank; + state.curr_letter_index = 0; + state.wins = 0; +} + +// Gets the word at the current element. Will always return a valid non-null pointer to first char of the word +char *get_curr_word() { + assert(state.curr_el != NULL); + assert((*state.curr_el) != NULL); + return *state.curr_el; +} + +char get_curr_letter() { + char *word = get_curr_word(); + return word[state.curr_letter_index]; +} + +int get_curr_letter_index() { + return state.curr_letter_index; +} + +int get_wins() { + return state.wins; +} + +// goes to the next word in the word bank, wrapping when necessary +static void go_next_word() { + if (*(state.curr_el + 1) == NULL) { + state.curr_el = word_bank; + } else { + state.curr_el++; + } + + state.wins++; + state.curr_letter_index = 0; +} + +// handle either going to the next letter or next word if at the end +void next() { + size_t word_len = strlen(get_curr_word()); + if (state.curr_letter_index >= word_len - 1) { // at last character + go_next_word(); + } else { + state.curr_letter_index++; + } +} diff --git a/game_state.h b/game_state.h new file mode 100644 index 0000000..bffed26 --- /dev/null +++ b/game_state.h @@ -0,0 +1,17 @@ +#ifndef GAMESTATE_H +#define GAMESTATE_H + +void init_game_state(); + +// Gets the word at the current element. Will always return a valid non-null pointer to first char of the word +char *get_curr_word(); + +char get_curr_letter(); +int get_curr_letter_index(); + +int get_wins(); + +// handle either going to the next letter or next word if at the end +void next(); + +#endif diff --git a/main.c b/main.c index 4a7665f..e0ceed5 100644 --- a/main.c +++ b/main.c @@ -1,90 +1,80 @@ #include #include #include - -char *word_bank[] = { - "hypothesis", - "science", - "usurp", - "conditional", - "passionate", - "orion", - NULL // sentinel value marking end -}; +#include +#include "game_state.h" #define WINDOW_HEIGHT 500 #define WINDOW_WIDTH 700 #define CHAR_SPACING 40 -#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) +void process_key_events() { + char buf[2] = {'c', '\0'}; + int k; + const char *key_name; + + while ((k = GetKeyPressed()) != 0) { + key_name = GetKeyName(k); + + char c = get_curr_letter(); + sprintf(buf, "%c\0", c); + + if (key_name != NULL && + strcmp(key_name, buf) == 0) { + next(); + } + } +} + +void render_game_state() { + char buf[2] = {'c', '\0'}; + char *curr_word = get_curr_word(); + int curr_letter_index = get_curr_letter_index(); + size_t word_len = strlen(curr_word); + + DrawText(curr_word, 10, 10, 20, BLACK); + + int x = (WINDOW_WIDTH / 2) - (CHAR_SPACING * (word_len / 2)); + int y = WINDOW_HEIGHT / 2; + + for (int i = 0; i < word_len; i++) { + char c = curr_word[i]; + + sprintf(buf, "%c\0", c); + + Color color; + if (i == curr_letter_index) { + color = GOLD; + } else if (i < curr_letter_index) { + color = DARKGRAY; + } else { + color = GRAY; + } + + DrawText(buf, x, y, 50, color); + x += CHAR_SPACING; + } + + char wins_text[20]; + snprintf(wins_text, 20, "%d wins", get_wins()); + DrawText(wins_text, WINDOW_WIDTH - 100, WINDOW_HEIGHT - 20, 20, GRAY); +} int main(int argc, char *argv[]) { - char **curr_word = word_bank; - unsigned short curr_letter_index = 0; - unsigned short wins = 0; - InitWindow(WINDOW_WIDTH, WINDOW_HEIGHT, "Typing game"); + init_game_state(); + while (!WindowShouldClose()) { - char buf[2] = {'c', '\0'}; - size_t word_len = strlen(*curr_word); + process_key_events(); - int k = 0; - const char *key_name; - // process queued key events - while ((k = GetKeyPressed()) != 0) { - key_name = GetKeyName(k); - - char c = (*curr_word)[curr_letter_index]; - sprintf(buf, "%c\0", c); - - if (key_name != NULL && - strcmp(key_name, buf) == 0) { - if (curr_letter_index < word_len - 1) { // next letter - curr_letter_index++; - } else { // next word - if (*(curr_word + 1) == NULL) { // wrap around - curr_word = word_bank; - } else { - curr_word++; - wins++; - } - curr_letter_index = 0; - } - } - } - - // render BeginDrawing(); ClearBackground(WHITE); - DrawText(*curr_word, 10, 10, 20, BLACK); + + render_game_state(); - int x = (WINDOW_WIDTH / 2) - (CHAR_SPACING * (word_len / 2)); - int y = WINDOW_HEIGHT / 2; - - for (int i = 0; i < word_len; i++) { - char c = (*curr_word)[i]; - - sprintf(buf, "%c\0", c); - - Color color; - if (i == curr_letter_index) { - color = GOLD; - } else if (i < curr_letter_index) { - color = GRAY; - } else { - color = DARKGRAY; - } - - DrawText(buf, x, y, 50, color); - x += CHAR_SPACING; - } - DrawFPS(WINDOW_WIDTH - 100, 10); // top right - char wins_text[20]; - snprintf(wins_text, 20, "%d wins", wins); - DrawText(wins_text, WINDOW_WIDTH - 100, WINDOW_HEIGHT - 20, 20, GRAY); EndDrawing(); }