115 lines
3.2 KiB
C
115 lines
3.2 KiB
C
|
|
//
|
||
|
|
// Created by Gregory Gauthier on 06/10/2025.
|
||
|
|
//
|
||
|
|
/* game.c - Game logic implementation */
|
||
|
|
#include "../include/game.h"
|
||
|
|
#include "../include/ui.h"
|
||
|
|
#include <string.h>
|
||
|
|
#include <ctype.h>
|
||
|
|
|
||
|
|
/* Initialize game state */
|
||
|
|
void init_game(GameState* game) {
|
||
|
|
int i, j;
|
||
|
|
|
||
|
|
game->word_count = 0;
|
||
|
|
game->target_word[0] = '\0';
|
||
|
|
game->guess_count = 0;
|
||
|
|
game->current_guess[0] = '\0';
|
||
|
|
game->current_guess_length = 0;
|
||
|
|
game->game_over = 0;
|
||
|
|
game->won = 0;
|
||
|
|
|
||
|
|
/* Initialize letter status to unused */
|
||
|
|
for (i = 0; i < 26; i++) {
|
||
|
|
game->letter_status[i] = STATUS_UNUSED;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Clear guesses */
|
||
|
|
for (i = 0; i < MAX_GUESSES; i++) {
|
||
|
|
game->guesses[i][0] = '\0';
|
||
|
|
for (j = 0; j < WORD_LENGTH; j++) {
|
||
|
|
game->guess_colors[i][j] = COLOR_DEFAULT;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Check guess against target word */
|
||
|
|
void check_guess(GameState* game, const char* guess, int* colors) {
|
||
|
|
char target_copy[WORD_LENGTH + 1];
|
||
|
|
char guess_copy[WORD_LENGTH + 1];
|
||
|
|
int i, j;
|
||
|
|
int target_used[WORD_LENGTH] = {0};
|
||
|
|
|
||
|
|
strcpy(target_copy, game->target_word);
|
||
|
|
strcpy(guess_copy, guess);
|
||
|
|
|
||
|
|
/* Ensure uppercase */
|
||
|
|
for (i = 0; i < WORD_LENGTH; i++) {
|
||
|
|
guess_copy[i] = toupper(guess_copy[i]);
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Initialize all as absent */
|
||
|
|
for (i = 0; i < WORD_LENGTH; i++) {
|
||
|
|
colors[i] = COLOR_ABSENT;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* First pass: mark correct positions */
|
||
|
|
for (i = 0; i < WORD_LENGTH; i++) {
|
||
|
|
if (guess_copy[i] == target_copy[i]) {
|
||
|
|
colors[i] = COLOR_CORRECT;
|
||
|
|
target_used[i] = 1;
|
||
|
|
game->letter_status[guess_copy[i] - 'A'] = STATUS_CORRECT;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Second pass: mark present but wrong position */
|
||
|
|
for (i = 0; i < WORD_LENGTH; i++) {
|
||
|
|
if (colors[i] == COLOR_ABSENT) {
|
||
|
|
for (j = 0; j < WORD_LENGTH; j++) {
|
||
|
|
if (!target_used[j] && guess_copy[i] == target_copy[j]) {
|
||
|
|
colors[i] = COLOR_PRESENT;
|
||
|
|
target_used[j] = 1;
|
||
|
|
if (game->letter_status[guess_copy[i] - 'A'] != STATUS_CORRECT) {
|
||
|
|
game->letter_status[guess_copy[i] - 'A'] = STATUS_PRESENT;
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
/* If still absent, mark letter as not in word */
|
||
|
|
if (colors[i] == COLOR_ABSENT) {
|
||
|
|
if (game->letter_status[guess_copy[i] - 'A'] == STATUS_UNUSED) {
|
||
|
|
game->letter_status[guess_copy[i] - 'A'] = STATUS_ABSENT;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Process a guess */
|
||
|
|
int make_guess(GameState* game, const char* guess) {
|
||
|
|
char upper_guess[WORD_LENGTH + 1];
|
||
|
|
int i;
|
||
|
|
|
||
|
|
if (strlen(guess) != WORD_LENGTH) {
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
strcpy(upper_guess, guess);
|
||
|
|
for (i = 0; i < WORD_LENGTH; i++) {
|
||
|
|
upper_guess[i] = toupper(upper_guess[i]);
|
||
|
|
}
|
||
|
|
|
||
|
|
strcpy(game->guesses[game->guess_count], upper_guess);
|
||
|
|
check_guess(game, guess, game->guess_colors[game->guess_count]);
|
||
|
|
game->guess_count++;
|
||
|
|
|
||
|
|
if (strcmp(upper_guess, game->target_word) == 0) {
|
||
|
|
game->game_over = 1;
|
||
|
|
game->won = 1;
|
||
|
|
} else if (game->guess_count >= MAX_GUESSES) {
|
||
|
|
game->game_over = 1;
|
||
|
|
game->won = 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
return 1;
|
||
|
|
}
|