refactor: add game state abstraction

This commit is contained in:
2026-09-27 11:37:08 -07:00
parent bfdf3ad573
commit bdaf00129d
3 changed files with 147 additions and 68 deletions
+72
View File
@@ -0,0 +1,72 @@
#include "game_state.h"
#include <stdio.h>
#include <string.h>
#include <assert.h>
#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++;
}
}
+17
View File
@@ -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
+58 -68
View File
@@ -1,90 +1,80 @@
#include <raylib.h>
#include <stdio.h>
#include <string.h>
char *word_bank[] = {
"hypothesis",
"science",
"usurp",
"conditional",
"passionate",
"orion",
NULL // sentinel value marking end
};
#include <assert.h>
#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();
}