diff --git a/main.c b/main.c index 502c22a14def718f5b1b364be32ee66155dac803..0a8049a82395812b8271c6d5dcbeeb984fb79ffb 100644 --- a/main.c +++ b/main.c @@ -14,7 +14,7 @@ int main(void) { while ((menu_choice = show_menu()) != MENU_QUIT) { clear(); - set_gamemode(menu_choice); + set_gamemode((Gamemode)menu_choice); launch_game(); }; diff --git a/tool/test/tool-test.c b/tool/test/tool-test.c index 18c1a4e4dcb08f0b6a332399e733985913e25a2d..59152a23c4889552766b2d87af5d202870ad9b20 100644 --- a/tool/test/tool-test.c +++ b/tool/test/tool-test.c @@ -6,14 +6,15 @@ void test_compute_matches_should_be_empty(void) { set_answer("BALAI"); - set_try("BALAE"); - int *pattern = generate_pattern(); - possibility_t **p = compute_matches("BALAE", pattern); + set_try("BRUTE"); + Pattern *pattern = generate_pattern(); + possibility_t **p = compute_matches("BRUTE", pattern); - printf("%d\n", get_remaning_bank_count()); - // for (int i = 0; i < get_remaning_bank_count(); i++) - // printf("%s\n", p[i]->word); + printf("%d\n", get_remaining_bank_count()); + for (int i = 0; i < get_remaining_bank_count(); i++) + printf("%s\n", p[i]->word); free(pattern); destroy_possibilities(p); + destroy_tool(); } diff --git a/tool/tool.c b/tool/tool.c index b120d8b623d59be113b75d6dfe948293c6bf2b47..8ebacd478da9f1f5de57723735b781eff62784ac 100644 --- a/tool/tool.c +++ b/tool/tool.c @@ -4,14 +4,14 @@ // PRIVATE //========================== int possibility_count = 0; -char **remaning_bank; -int remaning_bank_count; +char **remaining_bank; +int remaining_bank_count; possibility_t **possibilities; -possibility_t *create_possibility(char *word, double probability) { +possibility_t *create_possibility(char *word, double entropy) { possibility_t *p = malloc(sizeof(possibility_t)); p->word = word; - p->probability = probability; + p->entropy = entropy; return p; } @@ -19,8 +19,20 @@ possibility_t *create_possibility(char *word, double probability) { // PUBLIC //========================== void init_tool() { - remaning_bank = get_bank(); - remaning_bank_count = get_bank_size(); + remaining_bank_count = get_bank_size(); + remaining_bank = malloc(remaining_bank_count * sizeof(char *)); + + char **tmp = get_bank(); + for (int i = 0; i < remaining_bank_count; i++) { + remaining_bank[i] = malloc((WORD_LENGHT + 1) * sizeof(char)); + strcpy(remaining_bank[i], tmp[i]); + } +} + +void destroy_tool() { + for (int i = 0; i < remaining_bank_count; i++) + free(remaining_bank[i]); + free(remaining_bank); } void destroy_possibilities(possibility_t **p) { @@ -29,38 +41,55 @@ void destroy_possibilities(possibility_t **p) { free(p); } -possibility_t **compute_matches(char *word, int *pattern) { +possibility_t **compute_matches(char *word, Pattern *pattern) { possibility_count = 0; - char tmp_poss[remaning_bank_count][WORD_LENGHT + 1]; + char tmp_poss[remaining_bank_count][WORD_LENGHT + 1]; - for (int i = 0; i < remaning_bank_count; i++) + for (int i = 0; i < remaining_bank_count; i++) *tmp_poss[i] = *"\0"; - char **tmp_bank = remaning_bank; - for (int j = 0; j < remaning_bank_count; j++) { - int valid_word = 0; + for (int j = 0; j < remaining_bank_count; j++) { + char current_word[WORD_LENGHT + 1]; + strcpy(current_word, remaining_bank[j]); + bool valid_word = true; for (int i = 0; i < WORD_LENGHT; i++) { - if (pattern[i] == LETTER_NOT_PRESENT) - continue; - - char tmp_c[2] = {word[i], '\0'}; - - if (pattern[i] == LETTER_PLACED) { - if (strcspn(tmp_bank[j], tmp_c) == i) { - printf("%ld\t%c\t%s\t%s\n", strcspn(tmp_bank[j], tmp_c), word[i], tmp_bank[j], word); - strcpy(tmp_poss[j], tmp_bank[j]); - possibility_count++; - continue; - } - } + // Forced to create a string of only 1 char to get his position in the word + char current_char[2] = {word[i], '\0'}; + + // Filter out the non-valid words + if ((pattern[i] == WRONG && (int)strcspn(current_word, current_char) != WORD_LENGHT) || + (pattern[i] == MISPLACED && (int)strcspn(current_word, current_char) == WORD_LENGHT) || + (pattern[i] == CORRECT && (int)strcspn(current_word, current_char) != i)) + valid_word = false; + + // Clear the current char to not impact futur letter checks + current_word[i] = ' '; } + + if (!valid_word) + continue; + + strcpy(tmp_poss[j], remaining_bank[j]); + possibility_count++; } - possibilities = calloc(possibility_count, sizeof(possibility_t *)); + // Free non-matching words + for (int i = possibility_count; i < remaining_bank_count; i++) + free(remaining_bank[i]); + + int previous_remaining_count = remaining_bank_count; + + // Realloc for the new matching words + remaining_bank_count = possibility_count; + remaining_bank = realloc(remaining_bank, remaining_bank_count * sizeof(char *)); + + // Create the new possibilities list + possibilities = calloc(remaining_bank_count, sizeof(possibility_t *)); int idx = 0; - for (int i = 0; i < remaning_bank_count; i++) { + for (int i = 0; i < previous_remaining_count; i++) { if (strlen(tmp_poss[i]) != 0) { + strcpy(remaining_bank[idx], tmp_poss[i]); possibilities[idx] = create_possibility(tmp_poss[i], 0.0); idx++; } @@ -69,9 +98,9 @@ possibility_t **compute_matches(char *word, int *pattern) { return possibilities; } -int get_remaning_bank_count() { return remaning_bank_count; } +int get_remaining_bank_count() { return remaining_bank_count; } -char **agregate_possibilities(char *word, int *pattern) { +char **aggregate_possibilities(char *word, Pattern *pattern) { char **words = malloc(sizeof(char *) * POSSIBILITY_SET); possibility_t **matches = compute_matches(word, pattern); diff --git a/tool/tool.h b/tool/tool.h index 8ea019c7e3c001253f71d023a93de25cfd46a9a2..b7b855df1e3f0067ce39d45319c28b689ccd1a4b 100644 --- a/tool/tool.h +++ b/tool/tool.h @@ -3,13 +3,14 @@ #include "../word-bank/bank.h" #include "../wordle/wordle.h" +#include <stdbool.h> // Tool maximum possibility set #define POSSIBILITY_SET 10 typedef struct _possibility_t { char *word; - double probability; + double entropy; } possibility_t; /** @@ -17,6 +18,11 @@ typedef struct _possibility_t { */ void init_tool(); +/** + * @brief Destroy the tool + */ +void destroy_tool(); + /** * @brief Destroy possibilities * @param p @@ -30,14 +36,14 @@ void destroy_possibilities(possibility_t **p); * @param pattern * @return */ -possibility_t **compute_matches(char *word, int *pattern); +possibility_t **compute_matches(char *word, Pattern *pattern); /** * @brief Get the remaning bank count * * @return */ -int get_remaning_bank_count(); +int get_remaining_bank_count(); /** * @brief Agregate a defined set of possibile words from a given pattern @@ -46,6 +52,6 @@ int get_remaning_bank_count(); * @param pattern * @return */ -char **agregate_possibilities(char *word, int *pattern); +char **agregate_possibilities(char *word, Pattern *pattern); #endif diff --git a/wordle/test/wordle-test.c b/wordle/test/wordle-test.c index 8d372f2c95f21aa695c3171be9bb9db3fca8d267..489a6be21b827b5e0fccb6abc1795adf82f3b2d3 100644 --- a/wordle/test/wordle-test.c +++ b/wordle/test/wordle-test.c @@ -49,13 +49,13 @@ void test_validate_letter_should_be_true(void) { } void test_generate_pattern_should_return_all_0(void) { - int target[WORD_LENGHT] = {0, 0, 0, 0, 0}; + Pattern target[WORD_LENGHT] = {WRONG, WRONG, WRONG, WRONG, WRONG}; set_gamemode(MENU_SOLO); set_answer("BALAI"); set_try("PONTS"); - int *pattern = generate_pattern(); + Pattern *pattern = generate_pattern(); TEST_ASSERT_EQUAL_INT_ARRAY(target, pattern, WORD_LENGHT); diff --git a/wordle/wordle.c b/wordle/wordle.c index 9da722e81dd5f584488639fab0120f2deae9c119..20992deb13c844ab1abd8c89c6086fc9dedd3a3f 100644 --- a/wordle/wordle.c +++ b/wordle/wordle.c @@ -3,7 +3,7 @@ //========================== // PRIVATE //========================== -int gamemode = -1; +Gamemode mode; bool _game_finished = false; int score = 0; char **tries; @@ -16,16 +16,16 @@ int current_try_letter_id = 0; * @brief Render the game for the selected gamemode */ void render_game() { - switch (gamemode) { - case GAMEMODE_SOLO: + switch (mode) { + case SOLO: draw_title(SOLO_TITLE_ID); break; - case GAMEMODE_1_V_1: + case VERSUS: draw_title(ONE_V_ONE_TITLE_ID); break; - case GAMEMODE_COMPUTER: + case TOOL_ASSISTED: draw_title(COMPUTER_TITLE_ID); break; } @@ -53,7 +53,7 @@ void handle_controls(int key) { break; // Validations - int *pattern = generate_pattern(); + Pattern *pattern = generate_pattern(); for (int i = 0; i < WORD_LENGHT; i++) validations[current_try_id][i] = pattern[i]; free(pattern); @@ -64,7 +64,7 @@ void handle_controls(int key) { // Place correct letters from previous in the current one if (current_try_id < TRIES_COUNT) { for (int i = 0; i < WORD_LENGHT; i++) { - if (validations[current_try_id - 1][i] == LETTER_PLACED) + if (validations[current_try_id - 1][i] == CORRECT) tries[current_try_id][i] = tries[current_try_id - 1][i]; } } @@ -125,7 +125,7 @@ bool lose_condition() { return (current_try_id > TRIES_COUNT - 1); } bool win_condition() { for (int i = 0; i < WORD_LENGHT; i++) { - if (validations[current_try_id - (current_try_id > 0 ? 1 : 0)][i] != LETTER_PLACED) + if (validations[current_try_id - (current_try_id > 0 ? 1 : 0)][i] != CORRECT) return false; } @@ -134,8 +134,8 @@ bool win_condition() { bool validate_letter(int key) { return (islower(key) || isupper(key)); } -int *generate_pattern() { - int *validation = calloc(WORD_LENGHT, sizeof(int)); +Pattern *generate_pattern() { + Pattern *validation = calloc(WORD_LENGHT, sizeof(int)); char cpy[WORD_LENGHT + 1]; strcpy(cpy, chosen_word); @@ -144,14 +144,14 @@ int *generate_pattern() { continue; if (tries[current_try_id][i] == chosen_word[i]) { - validation[i] = LETTER_PLACED; + validation[i] = CORRECT; cpy[i] = ' '; continue; } char *addr; if ((addr = strchr(chosen_word, tries[current_try_id][i])) != NULL) { - validation[i] = LETTER_WRONG_PLACE; + validation[i] = MISPLACED; cpy[(int)(addr - chosen_word)] = ' '; // Get the index of the found char and replace with space continue; } @@ -183,13 +183,13 @@ bool validate_guess(char current_try[WORD_LENGHT]) { return true; } -void set_gamemode(int menu_gamemode) { gamemode = menu_gamemode; } +void set_gamemode(Gamemode menu_gamemode) { mode = menu_gamemode; } void set_answer(char answer[WORD_LENGHT]) { chosen_word = answer; } void set_try(char current_try[WORD_LENGHT]) { strcpy(tries[current_try_id], current_try); } -int get_gamemode() { return gamemode; } +Gamemode get_gamemode() { return mode; } char *get_answer() { return chosen_word; } diff --git a/wordle/wordle.h b/wordle/wordle.h index 9f86eda80b22d2f45c3e5568478519b2c56f4ea8..0c1f3a8ab0b5c6387e23bed2cd77a88cc41dad52 100644 --- a/wordle/wordle.h +++ b/wordle/wordle.h @@ -7,19 +7,13 @@ #include <stdbool.h> #include <string.h> -// Gamemodes -#define GAMEMODE_SOLO 0 -#define GAMEMODE_1_V_1 1 -#define GAMEMODE_COMPUTER 2 - // Game setup #define TRIES_COUNT 6 #define WORD_LENGHT 5 -// Try validation values -#define LETTER_PLACED 2 -#define LETTER_WRONG_PLACE 1 -#define LETTER_NOT_PRESENT 0 +// Enums +typedef enum Gamemode { SOLO, VERSUS, TOOL_ASSISTED } Gamemode; +typedef enum Pattern { WRONG, MISPLACED, CORRECT } Pattern; /** * @brief Initialize the game @@ -71,7 +65,7 @@ bool validate_letter(int key); /** * @brief Control the placement of each letter */ -int *generate_pattern(); +Pattern *generate_pattern(); /** * @brief Is a try valid @@ -87,7 +81,7 @@ bool validate_guess(char current_try[WORD_LENGHT]); * * @param menu_gamemode */ -void set_gamemode(int menu_gamemode); +void set_gamemode(Gamemode menu_gamemode); /** * @brief Set the answer @@ -108,9 +102,9 @@ void set_try(char current_try[WORD_LENGHT]); /** * @brief Get the gamemode * - * @return int + * @return Gamemode */ -int get_gamemode(); +Gamemode get_gamemode(); /** * @brief Get the answer