I am trying to make a word search game in C, of which a user will guess/input a word and the program will check if the word is existing and valid.
How can I check if the word inputted by a user is already printed/inputted? I'm really confused if what variable/s to compare, or if I need to create a function for that.
char guessed[], is a global array.
bool isAdded(char *token){
int i = 0;
while(guessed[i] != NULL){
if(strcmp(guessed[i], token) == 0){
return true;
}
i++;
}
return false;
}
main
while (1) {
printf("\n[GM: Find a word]> ");
if (!fgets(word, sizeof word, stdin)) {
break;
}
word[strcspn(word, "\n")] = '\0';
if (isAdded(word)) {
printf("[GM: Word already guessed]");
} else {
if (ifExist(matrix, word) && checkDictionary(dictionary, dict_len, word)) {
printf("[GM: Found it]\n");
}
else if (ifExist(matrix, word)) {
printf("[GM: It's not in the dictionary]\n");
}
else if (strcmp(word, "quit") == 0) {
break;
} else {
printf("[GM: Not found, please try again]\n");
}
}
}
}
The most basic solution is to add an array where past words are stored, and then search through it every time a word is queried to see if it is a repeat word. I'll repost the entire code you posted first: in the future, when you update your post please don't nuke the full example. You did the right thing by pasting the entire code, because there's something I want to touch on. All the changes are made in main()
. The solution is a basic circular array that tramples past entries after it has reached its cap.
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <time.h>
#include <stdbool.h>
#define SIZE 10 // row and column size
#define MAX 40 // word size
// Function to check if a word exists in the board
// starting from the first match in the board
// index: index till which pattern is matched
// i, j: current position in 2D array
bool adjacentSearch(char matrix[SIZE][SIZE], const char *find, int i, int j, int index) {
// pattern matched
if (find[index] == '\0')
return true;
// out of bounds
if (i < 0 || j < 0 || i >= SIZE || j >= SIZE || matrix[i][j] != find[index])
return false;
// marking this cell as visited
matrix[i][j] = '*';
// finding subpattern in 4 directions
bool found = (adjacentSearch(matrix, find, i + 1, j, index + 1) ||
adjacentSearch(matrix, find, i - 1, j, index + 1) ||
adjacentSearch(matrix, find, i, j - 1, index + 1) ||
adjacentSearch(matrix, find, i, j + 1, index + 1));
// marking this cell
// as unvisited again
matrix[i][j] = find[index];
return found;
}
// Function to check if the word exists in the board or not
bool ifExist(char matrix[SIZE][SIZE], const char *find) {
int len = strlen(find);
// if total characters in matrix is
// less then pattern length
if (len > SIZE * SIZE)
return false;
// traverse in the board
for (int i = 0; i < SIZE; i++) {
for (int j = 0; j < SIZE; j++) {
if (adjacentSearch(matrix, find, i, j, 0)) {
return true;
}
}
}
return false;
}
// Function to check if the word is in the dictionary
int checkDictionary(char **arr, int len, char *target) {
for (int i = 0; i < len; i++) {
if (strncmp(arr[i], target, strlen(target)) == 0) {
return true;
}
}
return false;
}
// Prints the board
void printBoard(char matrix[SIZE][SIZE]) {
for (int i = 0; i < SIZE; i++) {
for (int j = 0; j < SIZE; j++) {
printf(" %c ", matrix[i][j]);
}
printf("\n");
}
}
void asdf(char* a) {
int k = 2;
return;
}
// Driver code
int main() {
char previous[SIZE][MAX];
int indexOfPrevious = 0;
char *dictionary[] = {"one", "two", "three", "four", "five", "six"};
int dict_len = sizeof dictionary / sizeof dictionary[0];
asdf(dictionary[0]);
char word[MAX], matrix[SIZE][SIZE] = {{'r', 'h', 'y', 't', 'h', 'm', 'y', 'o', 'n', 'e'},
{'j', 'e', 'p', 'u', 'o', 'o', 'f', 'u', 'o', 'l'},
{'r', 'e', 'n', 'd', 'e', 'o', 'i', 'e', 'l', 'c'},
{'o', 'p', 'e', 'e', 't', 'h', 'r', 'e', 'e', 'j'},
{'d', 'y', 'l', 'v', 'p', 'p', 'h', 'e', 't', 'p'},
{'h', 'e', 's', 'i', 'x', 'o', 'u', 'n', 'w', 'e'},
{'f', 'v', 'm', 'f', 'o', 'x', 'd', 'k', 'o', 'v'},
{'f', 'o', 'r', 'o', 's', 't', 'u', 'e', 'o', 'i'},
{'g', 'a', 'l', 'g', 'o', 'w', 'b', 'y', 'p', 'a'},
{'h', 'e', 'l', 'l', 'o', 'f', 'o', 'u', 'r', 'd'}};
printBoard(matrix);
while (1) {
Start:
printf("\n[GM: Find a word]> ");
if (!fgets(word, sizeof word, stdin)) {
break;
}
word[strcspn(word, "\n")] = '\0';
if (strcmp(word, "quit") == 0) {
break;
}
int repeatEntry = 0;
for (int i = 0; i < indexOfPrevious; i++) {
int Result = strncmp(previous[i], word, MAX);
if (!Result) {
repeatEntry |= 1;
// Insert what you want to do if a word is re-entered here
}
}
if (!repeatEntry) {
indexOfPrevious %= SIZE;
memcpy(previous[indexOfPrevious++], word, MAX);
}
if (ifExist(matrix, word) && checkDictionary(dictionary, dict_len, word)) {
printf("[GM: Found it]\n");
} else if (ifExist(matrix, word)) {
printf("[GM: It's not in the dictionary]\n");
}
else {
printf("[GM: Not found, please try again]\n");
}
}
return 0;
}
Now to talk about a mistake you've made that's unrelated to the question you've asked, but is very important in terms of code correctness. The offending code is
char *dictionary[] = {"one", "two", "three", "four", "five", "six"};
combined with
int checkDictionary(char **arr, int len, char *target) {
for (int i = 0; i < len; i++) {
if (strncmp(arr[i], target, strlen(target)) == 0) {
return true;
}
}
return false;
}
Simply explained, the variable dictionary
is originally declared as an array of pointers, and then cast to a pointer to pointer(s), but is initialized with string literals. This last point causes problems. I decided to go through the strings byte by byte, so to make the result more readable I've cleaned up the output by replacing null terminators with space so it can be seen as one string:
one two two three three four four five five six six
Wait, what? Why are the words repeated? This is when you know something just isn't right. To be honest I don't know exactly why this happens, but it's really fucked. The issue is that you are declaring an array of pointers, but initializing it with string literals. In my opinion, C should not allow that to compile at all, but it does. What seemingly happens is that it allocates the string literals somewhere else in memory and gives you a pointer there, meaning that the difference between the address of is huge. One example is 0x0059(...) versus 0x7fff(...). So each element of dictionary
is a pointer to one of these.
Now, what you are doing in checkDictionary()
with the for loop iterating over the pointer as an array is not advised, as you can't do that generally and have it be correct. What happens is that every increment of the index moves the memory access by 8 bytes (on 64-bit systems, which I'm assuming you're using. I don't even want to think about how this would work in 32-bit). IF dictionary
was initialized the way I think you wanted it to be with each word one after another in memory with no repeats this would not work, as words would be skipped. However, as "luck" would have it, the repeats are structured so that they don't interfere, and the way you iterate ends up working. But it is not right, and that sort of thing is guaranteed to blow up eventually with extremely annoying crashes and horrendous bugs.
The fix is to just make dictionary
a char**
or char[][]
like you did with the matrix. In the former case you'll have to malloc each and every word but also be able to dynamically add to it, whereas the latter you'll have to specify each character and you'll end up using more memory as each entry will have to be homogenized to the largest string literal.