diff --git a/README.md b/README.md index 266ca50..e7d5de1 100755 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ Proven working on Linux ONLY. Contributions welcome! `make && make install` 4. Run the game -`wordlec` (`wordlec --help` for help) +`wordlec` (`wordlec -h/--help` for help) # How to play diff --git a/src/main.c b/src/main.c index c74558f..800d876 100644 --- a/src/main.c +++ b/src/main.c @@ -3,7 +3,8 @@ */ /* TODO: - * maybe implement user-specified colors for theming + * implement user-specified colors for theming + * therefore renaming the colors from smt like INCORRECT to INCORRECT etc. */ #include @@ -12,18 +13,32 @@ #include #include -char *RESET = "\x1b[0m"; -char *RED = "\x1b[31m"; -char *GREEN = "\x1b[32m"; -char *YELLOW = "\x1b[33m"; -char *GRAY = "\x1b[7m"; +char *RESET = "\x1b[0m"; +char *INCORRECT = "\x1b[31m"; +char *CORRECT = "\x1b[32m"; +char *OUTOFPLACE = "\x1b[33m"; +char *ASCII = "\x1b[7m"; -char wordlist_path[1024]; -char wordlist[16384][6]; // 2^14 -int len_wordlist = 0; -int flag_verbose = 0; -int flag_worldlist = 0; -int flag_light_theme = 0; +int flag_verbose = 0; +int flag_worldlist = 0; +int flag_light_theme = 0; +int len_wordlist = 0; +int lose = 0; +char pf_props[6][5][2] = { + // + // letter 0, 1, 2, 3 or 4 where + // 0 (RESET) is not yet guessed + // 1 (INCORRECT) default red, is incorrect, + // 2 (CORRECT) default green, is correct and + // 3 (OUTOFPLACE) default yellow, is out-of-place + + { " 0", " 0", " 0", " 0", " 0" }, + { " 0", " 0", " 0", " 0", " 0" }, + { " 0", " 0", " 0", " 0", " 0" }, + { " 0", " 0", " 0", " 0", " 0" }, + { " 0", " 0", " 0", " 0", " 0" }, + { " 0", " 0", " 0", " 0", " 0" } +}; char playfield[6][5] = { { ' ', ' ', ' ', ' ', ' ' }, { ' ', ' ', ' ', ' ', ' ' }, @@ -32,247 +47,41 @@ char playfield[6][5] = { { ' ', ' ', ' ', ' ', ' ' }, { ' ', ' ', ' ', ' ', ' ' } }; -char pf_props[6][5][2] = { - // - // letter 0, 1, 2 or 3 where - // 0 (RESET) is not yet guessed - // 1 (RED) is out-of-place, - // 2 (GREEN) is correct and - // 3 (YELLOW) is incorrect - - { " 0", " 0", " 0", " 0", " 0" }, - { " 0", " 0", " 0", " 0", " 0" }, - { " 0", " 0", " 0", " 0", " 0" }, - { " 0", " 0", " 0", " 0", " 0" }, - { " 0", " 0", " 0", " 0", " 0" }, - { " 0", " 0", " 0", " 0", " 0" } -}; +int quit = 0; +int turns = 0; +int win = 0; +char wordlist_path[1024]; +char wordlist[16384][6]; // 2^14 char word_to_guess[5]; -int turns = 0; -int win = 0; -int lose = 0; -int quit = 0; - /* - tests if a file exists - return 0 - yes - return 1 - no -*/ -int file_exists(char path[]) { - if (access(path, F_OK) != 0) { - return 0; - } else { - return 1; - } -} + * + * + * END OF GLOBAL VARIABLES + * ======================= + * START OF FUNCTIONS + * + * + */ -/* - prints the help & usage for the user to know what to do -*/ -void print_help_and_usage() { - fprintf(stdout, - "Help and usage for wordlec:\n" - "\n" - "Help:\n" - "-w/--wordlist ........... specify a custom wordlist\n" - " RULES: five characters on each line (no empty lines),\n" - " each new line is separated by '\\n' (Enter/Return)\n" - "-l/--light-theme ................................ activate light theme\n" - "-v/--verbose .................................... be verbose (show what the program is doing aka debug info)\n" - "-h/--help ....................................... show this help screen\n" - ); -} - -/* - gets a random word from the given wordlist -*/ -void get_random_word(char word_to_guess[], char wordlist_path[]) { - FILE* wordlist_file = fopen(wordlist_path, "r"); - char ch; - int i = 0; - char temp_word[6]; - while ((ch = fgetc(wordlist_file)) != EOF) { - if (ch != '\n') { - temp_word[i] = ch; - i++; - } else { - temp_word[i] = '\0'; - i = 0; - strcpy(wordlist[len_wordlist], temp_word); - len_wordlist++; - } - } - - srand(time(NULL)); - - strcpy(word_to_guess, wordlist[rand() % len_wordlist]); -} - -/* - clears the console/screen -*/ -void clear() { - printf("\e[1;1H\e[2J"); -} - -/* - prints the current state of the game - shows - correct letters - incorrect letters - and out-of-place letters - also the previous attempts -*/ -void show() { - clear(); - printf("%s╔═══╦═══╦═══╦═══╦═══╗%s\n", GRAY, RESET); - for (int i = 0; i < 6; i++) { - for (int j = 0; j < 5; j++) { - switch (pf_props[i][j][1]) { - case '0': - printf("%s║ %c ", GRAY, playfield[i][j]); - break; - case '1': - printf("%s║%s %c %s", GRAY, RED, playfield[i][j], RESET); - break; - case '2': - printf("%s║%s %c %s", GRAY, GREEN, playfield[i][j], RESET); - break; - case '3': - printf("%s║%s %c %s", GRAY, YELLOW, playfield[i][j], RESET); - break; - } - } - printf("%s║%s\n", GRAY, RESET); - if (i < 5) printf("%s╠═══╬═══╬═══╬═══╬═══╣%s\n", GRAY, RESET); - } - printf("%s╚═══╩═══╩═══╩═══╩═══╝%s\n", GRAY, RESET); -} - -/* - prompt the user for their input -*/ -void prompt(char user_input[]) { - int c; - printf(">> "); - scanf("%5s", user_input); - while ((c = getchar()) != '\n' && c != EOF); -} - -/* - linear search helper function for searching within the wordlist -*/ -int search_wordlist(char wordlist[][6], char target[]) { - for (int i = 0; i < len_wordlist; i++) { - if (strcmp(wordlist[i], target) == 0) return i; - } - return -1; -} - -/* - helper function for searching within a string -*/ -int search_word(char word[], char target) { - for (int i = 0; i < strlen(word); i++) { - if (word[i] == target) return i; - } - return -1; -} - -/* - evaluate the loss -*/ -void eval_lose() { - if (turns >= 5 && win == 0) { - lose = 1; - } -} - -/* - evaluate the win -*/ -void eval_win(int i) { - if (strcmp(wordlist[i], word_to_guess) == 0) { - win = 1; - } -} - -/* - helper function for evaluating the properties of a word -*/ -void eval_props(char word[]) { - for (int i = 0; i < 5; i++) { - if (word_to_guess[i] == word[i]) { - pf_props[turns][i][0] = word[i]; - pf_props[turns][i][1] = '2'; - } else if (search_word(word_to_guess, word[i]) != -1 && word_to_guess[i] != word[i]) { - pf_props[turns][i][0] = word[i]; - pf_props[turns][i][1] = '3'; - } else if (search_word(word_to_guess, word[i]) == -1) { - pf_props[turns][i][0] = word[i]; - pf_props[turns][i][1] = '1'; - } - } -} - -/* - put a valid word into the playfield -*/ -void put_word_into_playfield(char word[]) { - strcpy(playfield[turns], word); - turns++; - - // resetting the rest of the playfield - for (int i = turns; i < turns + (6 - turns); i++) { - strcpy(playfield[i], " "); - } -} - -/* - evaluate the word -*/ -void eval_word(char word[]) { - printf("\n%d\n", search_wordlist(wordlist, word)); - if (search_wordlist(wordlist, word) != -1) { - eval_win(search_wordlist(wordlist, word)); - eval_lose(); - eval_props(word); // eval correct/incorrect/oop letters - put_word_into_playfield(word); - } else { - clear(); - printf("Word %s not in wordlist\n", word); - sleep(2); - } -} - -/* - # prerequisites: - & 1 choose a random word from a wordlist - - # algo steps: - & 1 clear the screen - & 2 display the current state of the playfield - & 3 prompt the user to enter a word - & 4 evaluate the word - & 5 print the word on the screen with the corresponding parameters at each letter (right position, wrong position, not in word) - & 6.1 if the user entered the right word, show a winning message and exit - & 6.2 if the user has tried 6 times already, show a losing message, the word and exit -*/ -void game() { - // step 1 & 2 - show(); - - // step 3 - char user_input[5]; - prompt(user_input); - - // implemented a quit function - if (user_input[0] == 'q') quit = 1; - - // step 4 & 5 - eval_word(user_input); -} +int argparse(int argc, char *argv[]); +void clear(); +void eval_lose(); +void eval_props(char word[]); +void eval_win(int i); +void eval_word(char word[]); +int file_exists(char path[]); +void game(); +void get_random_word(char word_to_guess[], char wordlist_path[]); +int main(int argc, char *argv[]); +void print_help_and_usage(); +void prompt(char user_input[]); +void put_word_into_playfield(char word[]); +int search_word(char word[], char target); +int search_wordlist(char wordlist[][6], char target[]); +void set_theme(); +void show(); +void show_win_lose_message(); /* pass the arguments @@ -283,9 +92,22 @@ int argparse(int argc, char *argv[]) { /* look for invalid arguments */ - if (strcmp(argv[i], argv[0]) != 0 && strcmp(argv[i], "--wordlist") != 0 && strcmp(argv[i-1], "--wordlist") != 0 && strcmp(argv[i], "--verbose") != 0 && strcmp(argv[i], "--help") != 0 && strcmp(argv[i], "-h") != 0 && strcmp(argv[i], "-w") != 0 && strcmp(argv[i-1], "-w") != 0 && strcmp(argv[i], "-v") != 0 && strcmp(argv[i], "-l") != 0 && strcmp(argv[i], "--light-theme") != 0) { - fprintf(stderr, "Invalid argument %s\n", argv[i]); - flag_error = 1; + if (strcmp(argv[i], argv[0]) != 0 && + strcmp(argv[i], "-h") != 0 && + strcmp(argv[i], "--help") != 0 && + strcmp(argv[i], "-l") != 0 && + strcmp(argv[i], "--light-theme") != 0 && + strcmp(argv[i], "-t") != 0 && + strcmp(argv[i], "--theme") != 0 + strcmp(argv[i], "-v") != 0 && + strcmp(argv[i], "--verbose") != 0 && + strcmp(argv[i], "-w") != 0 && + strcmp(argv[i-1], "-w") != 0 && + strcmp(argv[i], "--wordlist") != 0 && + strcmp(argv[i-1], "--wordlist") != 0 && + ) { + fprintf(stderr, "Invalid argument %s\n", argv[i]); + flag_error = 1; } /* @@ -363,33 +185,134 @@ int argparse(int argc, char *argv[]) { } /* - shows the message after the game ends + clears the console/screen */ -void show_win_lose_message() { - show(); - if (win == 1 && lose == 0) fprintf(stdout, "You won! It took you %d guesses. The word was %s.\n", turns, word_to_guess); - if (win == 0 && lose == 1) fprintf(stdout, "You lost. :( The word was %s.\n", word_to_guess); +void clear() { + printf("\e[1;1H\e[2J"); } /* - set the theme (light/dark) + evaluate the loss */ -void set_theme() { - if (flag_light_theme == 1) { - RESET = "\x1b[0;0m"; - RED = "\x1b[0;41m"; - GREEN = "\x1b[0;42m"; - YELLOW = "\x1b[0;43m"; - GRAY = "\x1b[0;7m"; - } else { - RESET = "\x1b[37;0m"; - RED = "\x1b[37;41m"; - GREEN = "\x1b[37;42m"; - YELLOW = "\x1b[37;43m"; - GRAY = "\x1b[37;90m"; +void eval_lose() { + if (turns >= 5 && win == 0) { + lose = 1; } } +/* + helper function for evaluating the properties of a word +*/ +void eval_props(char word[]) { + for (int i = 0; i < 5; i++) { + if (word_to_guess[i] == word[i]) { + pf_props[turns][i][0] = word[i]; + pf_props[turns][i][1] = '2'; + } else if (search_word(word_to_guess, word[i]) != -1 && word_to_guess[i] != word[i]) { + pf_props[turns][i][0] = word[i]; + pf_props[turns][i][1] = '3'; + } else if (search_word(word_to_guess, word[i]) == -1) { + pf_props[turns][i][0] = word[i]; + pf_props[turns][i][1] = '1'; + } + } +} + +/* + evaluate the win +*/ +void eval_win(int i) { + if (strcmp(wordlist[i], word_to_guess) == 0) { + win = 1; + } +} + +/* + evaluate the word +*/ +void eval_word(char word[]) { + printf("\n%d\n", search_wordlist(wordlist, word)); + if (search_wordlist(wordlist, word) != -1) { + eval_win(search_wordlist(wordlist, word)); + eval_lose(); + eval_props(word); // eval correct/incorrect/oop letters + put_word_into_playfield(word); + } else { + clear(); + printf("Word %s not in wordlist\n", word); + sleep(2); + } +} + +/* + tests if a file exists + return 0 - yes + return 1 - no +*/ +int file_exists(char path[]) { + if (access(path, F_OK) != 0) { + return 0; + } else { + return 1; + } +} + +/* + # prerequisites: + & 1 choose a random word from a wordlist + + # algo steps: + & 1 clear the screen + & 2 display the current state of the playfield + & 3 prompt the user to enter a word + & 4 evaluate the word + & 5 print the word on the screen with the corresponding parameters at each letter (right position, wrong position, not in word) + & 6.1 if the user entered the right word, show a winning message and exit + & 6.2 if the user has tried 6 times already, show a losing message, the word and exit +*/ +void game() { + // step 1 & 2 + show(); + + // step 3 + char user_input[5]; + prompt(user_input); + + // implemented a quit function + if (user_input[0] == 'q') quit = 1; + + // step 4 & 5 + eval_word(user_input); +} + +/* + gets a random word from the given wordlist +*/ +void get_random_word(char word_to_guess[], char wordlist_path[]) { + FILE* wordlist_file = fopen(wordlist_path, "r"); + char ch; + int i = 0; + char temp_word[6]; + while ((ch = fgetc(wordlist_file)) != EOF) { + if (ch != '\n') { + temp_word[i] = ch; + i++; + } else { + temp_word[i] = '\0'; + i = 0; + strcpy(wordlist[len_wordlist], temp_word); + len_wordlist++; + } + } + + srand(time(NULL)); + + strcpy(word_to_guess, wordlist[rand() % len_wordlist]); +} + +/* + driver code +*/ int main(int argc, char *argv[]) { // pass the arguments int args = argparse(argc, argv); @@ -416,4 +339,137 @@ int main(int argc, char *argv[]) { show_win_lose_message(); return 0; +} + +/* + prints the help & usage for the user to know what to do +*/ +void print_help_and_usage() { + fprintf(stdout, + "Help and usage for wordlec:\n" + "\n" + "Help:\n" + "-w/--wordlist \n" + " specify a custom wordlist\n" + " RULES: five characters on each line (no empty lines),\n" + " each new line is separated by '\\n' (Enter/Return)\n" + "-t/--theme \n" // TODO: make work + " specify the colors in which the playfield will be visible\n" + " RULES: choose the color from this list:\n" + " [ black, red, green, yellow, blue, magenta, cyan, white ]\n" + " append ':b' (background color) or ':f' (foreground color)\n" + " add a ';' between the background and foreground colors\n" + " EXAMPLE: '-t green:f;black:b cyan:b;white:f red:b;black:f white:b;black:f'\n" + "-l/--light-theme\n" + " activate light theme\n" + "-v/--verbose\n" + " be verbose (show what the program is doing aka debug info)\n" + "-h/--help\n" + " show this help screen\n" + ); +} + +/* + prompt the user for their input +*/ +void prompt(char user_input[]) { + int c; + printf(">> "); + scanf("%5s", user_input); + while ((c = getchar()) != '\n' && c != EOF); +} + +/* + put a valid word into the playfield +*/ +void put_word_into_playfield(char word[]) { + strcpy(playfield[turns], word); + turns++; + + // resetting the rest of the playfield + for (int i = turns; i < turns + (6 - turns); i++) { + strcpy(playfield[i], " "); + } +} + +/* + helper function for searching within a string +*/ +int search_word(char word[], char target) { + for (int i = 0; i < strlen(word); i++) { + if (word[i] == target) return i; + } + return -1; +} + +/* + linear search helper function for searching within the wordlist +*/ +int search_wordlist(char wordlist[][6], char target[]) { + for (int i = 0; i < len_wordlist; i++) { + if (strcmp(wordlist[i], target) == 0) return i; + } + return -1; +} + +/* + set the theme (light/dark) +*/ +void set_theme() { + if (flag_light_theme == 1) { + RESET = "\x1b[0;0m"; + INCORRECT = "\x1b[0;41m"; + CORRECT = "\x1b[0;42m"; + OUTOFPLACE = "\x1b[0;43m"; + ASCII = "\x1b[0;7m"; + } else { + RESET = "\x1b[37;0m"; + INCORRECT = "\x1b[37;41m"; + CORRECT = "\x1b[37;42m"; + OUTOFPLACE = "\x1b[37;43m"; + ASCII = "\x1b[37;90m"; + } +} + +/* + prints the current state of the game + shows + correct letters + incorrect letters + and out-of-place letters + also the previous attempts +*/ +void show() { + clear(); + printf("%s╔═══╦═══╦═══╦═══╦═══╗%s\n", ASCII, RESET); + for (int i = 0; i < 6; i++) { + for (int j = 0; j < 5; j++) { + switch (pf_props[i][j][1]) { + case '0': + printf("%s║ %c ", ASCII, playfield[i][j]); + break; + case '1': + printf("%s║%s %c %s", ASCII, INCORRECT, playfield[i][j], RESET); + break; + case '2': + printf("%s║%s %c %s", ASCII, CORRECT, playfield[i][j], RESET); + break; + case '3': + printf("%s║%s %c %s", ASCII, OUTOFPLACE, playfield[i][j], RESET); + break; + } + } + printf("%s║%s\n", ASCII, RESET); + if (i < 5) printf("%s╠═══╬═══╬═══╬═══╬═══╣%s\n", ASCII, RESET); + } + printf("%s╚═══╩═══╩═══╩═══╩═══╝%s\n", ASCII, RESET); +} + +/* + shows the message after the game ends +*/ +void show_win_lose_message() { + show(); + if (win == 1 && lose == 0) fprintf(stdout, "You won! It took you %d guesses. The word was %s.\n", turns, word_to_guess); + if (win == 0 && lose == 1) fprintf(stdout, "You lost. :( The word was %s.\n", word_to_guess); } \ No newline at end of file