/* Wordle game implementation in the C programming language */ #include #include #include #include #include #define RESET "\x1b[0m" // color 0 #define RED "\x1b[31m" // color 1 #define GREEN "\x1b[32m" // color 2 #define YELLOW "\x1b[33m" // color 3 char wordlist_path[1024]; char wordlist[16384][6]; // 2^14 int len_wordlist = 0; int flag_verbose = 0; int flag_worldlist = 0; 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" } }; 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; } } /* prints the help & usage for the user to know what to do */ void print_help_and_usage() { fprintf(stdout, "Help and usage for Wordle:\n" "\n" "Help:\n" "--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" "--verbose ............................ be verbose (show what the program is doing aka debug info)\n" "--help ............................... show this help screen\n" "\n" "Usage:\n" "\n" "wordle\n" "=> starts Wordle with the default wordlist\n" "wordle --wordlist \n" "=> starts Wordle with a specified wordlist\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("╔═══╦═══╦═══╦═══╦═══╗\n"); for (int i = 0; i < 6; i++) { for (int j = 0; j < 5; j++) { switch (pf_props[i][j][1]) { case '0': printf("║ %c ", playfield[i][j]); break; case '1': printf("║ " RED "%c " RESET, playfield[i][j]); break; case '2': printf("║ " GREEN "%c " RESET, playfield[i][j]); break; case '3': printf("║ " YELLOW "%c " RESET, playfield[i][j]); break; } } printf("║\n"); if (i < 5) printf("╠═══╬═══╬═══╬═══╬═══╣\n"); } printf("╚═══╩═══╩═══╩═══╩═══╝\n"); } /* prompt the user for their input */ void prompt(char user_input[]) { printf(">> "); scanf("%5s", user_input); } /* 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 < sizeof(word)/sizeof(word[0]); 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); } /* pass the arguments */ int argparse(int argc, char *argv[]) { int flag_error = 0; for (int i = 0; i < argc; i++) { /* look for invalid arguments */ for (int j = 1; j < argc; j++) { if (strcmp(argv[j], "--wordlist") != 0 && strcmp(argv[j-1], "--wordlist") != 0 && strcmp(argv[j], "--verbose") != 0 && strcmp(argv[j], "--help") != 0) { fprintf(stderr, "Invalid argument %s\n", argv[j]); flag_error = 1; } } /* print the help & usage */ if (strcmp(argv[i], "--help") == 0) { print_help_and_usage(); return 0; } /* getting the debug flag for debug printing */ if (strcmp(argv[i], "--verbose") == 0 && flag_verbose == 0) { flag_verbose = 1; } /* getting the path to the wordlist */ if (strcmp(argv[i], "--wordlist") == 0 && flag_worldlist == 0) { flag_worldlist = 1; if (argv[i+1] != NULL) { // if there is an argument present after that, read it as the wordlist path strcpy(wordlist_path, argv[i+1]); } else { fprintf(stderr, "Missing argument after %s\nUsage: %s \n", argv[i], argv[i]); flag_error = 1; } } else if (strcmp(argv[i], "--wordlist") != 0 && flag_worldlist == 0) { strcpy(wordlist_path, "lib/wordlist"); } } if (file_exists(wordlist_path) == 0) { fprintf(stderr, "File %s not found\n", wordlist_path); flag_error = 1; } if (flag_verbose == 1) printf("wordlist_path: %s\n", wordlist_path); return flag_error; } /* 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); } int main(int argc, char *argv[]) { // pass the arguments if (argparse(argc, argv) == 1) return 1; // prerequisite 1 get_random_word(word_to_guess, wordlist_path); // steps while (win == 0 && lose == 0) { game(); if (quit == 1) return 2; } // print winning message show_win_lose_message(); return 0; }