Get a problem when make a hangman game ? ( c language) - c

I'm still really new to the C language and I'm trying to make a hangman game but I keep failing to end the game when I win.
Here is the code:
const int true = 1;
const int false = 0;
char words[][20] = {
"hangman",
"computer",
"programming",
"microsoft",
"visual",
"studio",
"express",
"learning"
};
int isletterinword(char word[], char letter)
{
int i;
for (i = 0; i < strlen(word); i++) {
if (word[i] == letter) {
return true;
}
}
return false;
}
int iswordcomplete(char secretword[], char rights[])
{
int i;
for (i = 0; i < strlen(secretword); i++) {
if (rights[i] == secretword[i] ) {
return true;
}
}
return false;
}
void printhangman(int numofwrongs)
{
// Line 1
printf("\t ______\n");
// Line 2
printf("\t | |\n");
// Line 3
printf("\t | +\n");
// Line 4 - left arm, head and right arm
printf("\t |");
if (numofwrongs > 0) printf(" \\");
if (numofwrongs > 1) printf("O");
if (numofwrongs > 2) printf("/");
printf("\n");
// Line 5 - body
printf("\t |");
if (numofwrongs > 3) printf(" |");
printf("\n");
// Line 6 - left leg and right leg
printf("\t |");
if (numofwrongs > 4) printf(" /");
if (numofwrongs > 5) printf(" \\");
printf("\n");
// Line 7
printf("\t |\n");
// Line 8
printf("\t__|__\n");
}
void printletters(char letters[])
{
int i;
for (i = 0; i < strlen(letters); i++) {
printf("%c ", letters[i]);
}
}
void printscreen(char rights[], char wrongs[], char secretword[])
{
int i;
for (i = 0; i < 25; i++)
printf("\n");
printhangman(strlen(wrongs));
printf("\n");
printf("Correct guesses: ");
printletters(rights);
printf("\n");
printf("Wrong guesses: ");
printletters(wrongs);
printf("\n\n\n");
printf("\t");
for (i = 0; i < strlen(secretword); i++) {
if (isletterinword(rights, secretword[i])) {
printf("%c ", secretword[i]);
}
else {
printf("_ ");
}
}
printf("\n\n");
}
int main()
{
int i;
int secretwordindex;
char rights[20];
char wrongs[7];
char guess;
secretwordindex = 0;
srand(time(0));
secretwordindex = rand() % 8;
for (i = 0; i < 20; i++) {
rights[i] = '\0';
}
for (i = 0; i < 6; i++) {
wrongs[i] = '\0';
}
while (strlen(wrongs) < 6) {
printscreen(rights, wrongs, words[secretwordindex]);
printf("\nPlease enter your guess: ");
scanf(" %c", &guess);
if (isletterinword(words[secretwordindex],guess)) {
rights[strlen(rights)] = guess;
}
else {
wrongs[strlen(wrongs)] = guess;
}
}
printscreen(rights, wrongs, words[secretwordindex]);
if ( iswordcomplete(words[secretwordindex],rights[20])==true && strlen(wrongs) <= 6 ) { // The if condition here might be problematic.
printf("You have won!\n");
}
else {
printf("You have lost!\n");
}
}
Here is the error message:
main.c:197:48: warning: passing argument 2 of ‘iswordcomplete’ makes
pointer from integer without a cast [-Wint-conver sion]
main.c:55:5: note: expected ‘char *’ but argument is of type ‘char’

First things first: The compiler error is caused by the fact that you are passing a single character to your call to iswordcomplete(), rather than an array of characters. So, in the check near the end of your main function, you need to pass rights (unadorned) as the argument, in place of rights[20] (which, incidentally, is an out-of-bounds element of the array). Also, you don't – at that stage – need the second check (counting the number of wrongs – see later). Here's the fix for that part of the code:
// if (iswordcomplete(words[secretwordindex], rights[20]) == true && strlen(wrongs) <= 6) { // The if condition here might be problematic.
if (iswordcomplete(words[secretwordindex], rights)){// && strlen(wrongs) <= 6) { // Needs the whole string as an argument
printf("You have won!\n");
}
Now to address a couple of other issues that will stop your code from working properly ...
(1) Your main while loop won't stop running until you have entered 6 'wrong' letters – even if you do guess the word correctly. So, you need to add an iswordcomplete() check to the while condition (negating it with the !operator†), to keep running the loop only if the word isn't complete. Like this:
while (strlen(wrongs) < 6 && !iswordcomplete(words[secretwordindex], rights)) { // Need to break loop if we win!!
printscreen(rights, wrongs, words[secretwordindex]);
//...
(2) The logic of your iswordcomplete function is flawed, as it will return "true" as soon as it finds any match. Instead, you need two loops, returning false if any of the word's letters is not found in the list of 'rights'. Here's one possible version:
int iswordcomplete(char secretword[], char rights[])
{
int i, j;
for (i = 0; i < strlen(secretword); i++) {
for (j = 0; j < strlen(rights); j++) {
if (secretword[i] == rights[j]) break;
}
if (j >= strlen(rights)) return false; // Didn't find this letter
}
return true;
}
Please feel free for any further clarification and/or explanation.
† If you're not (yet) familiar with this use of the ! operator, then you can explicitly compare the function's return value to the false constant, if you are more comfortable with that, like so:
while (strlen(wrongs) < 6 && iswordcomplete(words[secretwordindex], rights) == false) { // Break loop if we win!

Related

C program to insert elements into an array until user inputs a 0 or less number

I'm trying to make a C program to insert elements into an array until user inputs a 0 or less number, as the title says. But when I print the array out, it doesn't show the numbers I inputted. I have tried using a while as well as do-while loops but without success.
#include <stdio.h>
int main() {
int data[100];
int i;
for (i = 0; i < 100; i++) {
printf("Input your number:\n");
scanf("%d", &data[i]);
if (data[i] <= 0) {
break;
}
}
printf("Your array:");
int n = sizeof(data[i]);
for (int i = 0; i < n; i++) {
printf("%d ", &data[i]);
}
}
Try this:
#include <stdio.h>
int main() {
int data[100];
int i;
int counter = 0;
for (i = 0; i < 100; i++) {
printf("Input your number:\n");
scanf("%d", &data[i]);
counter++;
if (data[i] <= 0) {
break;
}
}
printf("Your array:");
for (int j = 0; j < counter - 1; j++) {
printf("%d ", data[j]);
}
}
The problem was that you had printf("%d ", &data[i]); instead of printf("%d ", data[i]);.
And also you've trying to get the sizeof() of an element data[i], not the size of the whole array. That's why there's counter in my code.
int n = sizeof(data[i]);
this is wrong, you want
int n = i;
sizeof(data[i]) gives you the size of an int (4 on my machine)
On the other hand, you need to check the result of scanf, if a bad input is entered do not increment the counter, something like:
int i = 0;
while (i < 100)
{
int res = scanf("%d", &data[i]);
if (res == EOF)
{
break;
}
if (res == 1)
{
if (data[i] <= 0)
{
break;
}
i++;
}
else
{
// Sanitize stdin
int c;
while ((c = getchar()) != '\n');
}
}
Finally, scanf wants a pointer to the object, but this is not the case of printf:
printf("%d ", &data[i])
should be
printf("%d ", data[i])

Bug Histogram Display in C

i want to do a histogram vertical display of my "election".
My code work just it seems to display wrongly the vote for the 10,11,12,13 value because i think there is 2 numbers ...
thank you for your time ;)
int main() {
char character ;
int TAB[12] = {0} ;
int vote = 0;
int I;
printf("Please enter a character:\n"); //character for the display
scanf(" %c", &character); // character we want to display in the histogram
printf("Please enter votes\n");
while(1) {
scanf("%d", &vote);
if (vote == -1) {
break;
}
TAB[vote-1]++; //save the vote into the array
}
printf("Histogram :\n");
/* Search for the maximum value */
int MAX=0;
for (I=0; I<12; I++)
{
if(TAB[I]>TAB[MAX]) MAX=I;
}
int maximum = TAB[MAX]; // maximum value
while (maximum > 0) {
for (I = 0; I < 12; I++) {
if (TAB[I] == maximum) {
printf("%c ",character);
TAB[I] = (TAB[I] - 1) ;
}
else {
printf(" ");
}
}
maximum= maximum - 1;
printf("\n");
}
for (I = 0; I < 13; I++) {
printf("%d ",I+1); // display the number of each candidat
}
printf("\n"); // go to the line
return 0;
}
You shouldn't use magic number 12, use like #define VOTE_MAX 13
For the range of vote, use if (vote <= 0 || vote > VOTE_MAX)
Format output, like printf("%2c ", character);
The line for (I = 0; I < 13; I++) { should be for (I = 0; I < 12; I++) {
The following code could work:
#include <stdio.h>
#define VOTE_MAX 13
int main() {
char character;
int TAB[VOTE_MAX] = {0};
int vote = 0;
printf("Please enter a character:\n"); // character for the display
scanf(" %c", &character); // character we want to display in the histogram
printf("Please enter votes\n");
while (1) {
scanf("%d", &vote);
if (vote <= 0 || vote > VOTE_MAX) {
break;
}
TAB[vote - 1]++; // save the vote into the array
}
printf("Histogram :\n");
/* Search for the maximum value */
int MAX = 0;
for (int i = 0; i < VOTE_MAX; ++i) {
if (TAB[i] > TAB[MAX]) MAX = i;
}
int maximum = TAB[MAX]; // maximum value
while (maximum > 0) {
for (int i = 0; i < VOTE_MAX; ++i) {
if (TAB[i] == maximum) {
printf("%2c ", character);
--TAB[i];
} else {
printf("%2c ", ' ');
}
}
--maximum;
printf("\n");
}
for (int i = 0; i < VOTE_MAX; ++i) {
printf("%2d ", i + 1); // display the number of each candidat
}
printf("\n"); // go to the line
return 0;
}
You need to add an extra space for the cases where I is 10 or higher.
Like:
for (I = 0; I < 12; I++) {
if (TAB[I] == maximum) {
printf("%c ",character);
TAB[I] = (TAB[I] - 1) ;
}
else {
printf(" ");
}
if (I >= 9) printf(" "); // Add extra space for 10, 11 and 12
}
BTW: your input method should be improved. Currently the user can enter values that will make your write outside the array. At least do something like:
while(1) {
if (scanf("%d", &vote) != 1) break; // Catch illegal input
if (vote <= 0 || vote >= 13) { // Only allow vote to be 1, 2, …, 10, 11, 12
break;
}
TAB[vote-1]++; //save the vote into the array
}

Hangman in C. Questions regarding arrays and strings

Ok so this is my code. I'm supposed to make a program that asks from one player a word and requests from the other one to find it, guessing one letter at a time. So basically, Hangman. My questions are these:
The SCounter variable increases to random numbers when I try to increase it by one. I've tried thinking about it and I don't know why. For example, when the guess word is Kala(Greek for "Good/Fine"), SCounter equals to wrong amount of letters when I type guess any letter after the first.
My second question is in regards to guess. My program only works when I write char guess[2]. When I write char guess[0] it loops forever. I don't underestand why.
int main(int argc, char *argv[]) {
SetConsoleOutputCP(1253);
int i = 0;
start :printf("Enter the guess word: ");
char word[25], sword[25];
char guess[2];
char alphabet[28] = {"abcdefghijklmnopqrstuvwxyz "};
int Counter = 6;
int SCounter = 0;
gets(word);
for (i=0; i<strlen(word); i++){
sword[i]='-';
}
while(Counter != 0)
{
printf("So far: ");
for(i = 0; i < strlen(alphabet); i++)
{
printf("%c", alphabet[i]);
}
printf("\n");
printf("Guess a character: ");
gets(guess);
printf("\n");
for(i = 0; i < strlen(word); i++)
{
if(word[i] == guess[0])
{
sword[i] = guess[0];
}
/*else
{
Counter--;
printf("You only have %d wrong guesses left.\n", Counter);
}*/
}
for(i = 0; i < strlen(sword); i++)
{
if (word[i]==sword[i]){
SCounter++;
}
printf("%c", sword[i]);
}
printf("\n");
printf("%d letters found so far.", SCounter);
printf("\n");
for(i = 0; i < strlen(alphabet); i++)
{
if (strlen(guess)<2)
{
if(alphabet[i] == guess[0])
{
alphabet[i] = '-';
}
}
}
if (SCounter == strlen(word)){
Counter = 0;
}
if (strcmp(word, sword)==0){
printf("Congratulation Player 1! You win!\n");
goto start;
}
}
return 0;
}
It looks like the SCounter variable is not reset to zero between iterations, so it keeps growing.
Move the declaration / initialization of SCounter to the scope where it is used to fix this problem:
int SCounter = 0; // This is where the declaration should be
// Remove the declaration of SCounter at the outermost scope.
for(i = 0; i < strlen(sword); i++)
{
if (word[i]==sword[i]){
SCounter++;
}
printf("%c", sword[i]);
}
Here are a few notes on the rest of your program:
Using goto is not going to score extra points with your instructor. To many, this is a red flag; consider rewriting without goto.
The gets function is inherently unsafe. Please refrain from using it for new development. Use fgets(guess, 2, stdin); instead.

Program errors due to strcmp and strcpy in C

No matter how I edit my program there seems to be overflow errors and mismatching type errors. Can someone help me to make this run without errors.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
int choice;
int i;
int j;
char type;
int amount;
int don_count = 0;
int req_count = 0;
int flag;
char donations_inv_type[100][20];
int donations_amount[100];
char requests_inv_type[100][20];
int req_amount[100];
printf("Welcome to the Food Bank Program\n\n 1. Add a donation\n 2. Add a request\n 3. Fulfill a request\n 4. Print status report\n 5. Exit\n\nEnter your choice: ");
scanf("%d", &choice);
while (choice != 5) {
if (choice == 1) {
printf("\nEnter inventory type: ");
scanf("%s", &type);
printf("Enter the amount: ");
scanf("%d", &amount);
printf("\nDonation Added!\n\n");
flag = -99;
for (i = 0; i < don_count; i++) {
if (strcmp(donations_inv_type[i], type) == 0)
flag = i;
}
if (flag == -99) {
strcpy(donations_inv_type[i], type);
donations_amount[i] = amount;
don_count++;
}
else
donations_amount[flag] += amount;
printf("Donation Added!\n");
printf("Press any key to continue . . .\n\n");
}
else if (choice == 2) {
printf("\nEnter inventory type: ");
scanf("%s", &type);
printf("Enter the amount: ");
scanf("%d", &amount);
strcpy(requests_inv_type[req_count], type);
req_amount[req_count] = amount;
req_count++;
}
else if (choice == 3) {
printf("\n\n-------- Fulfilling Requests--------");
flag = -99;
for (i = 0; i < don_count; i++) {
if (strcmp(donations_inv_type[i], requests_inv_type[0]) == 0)
flag = i;
}
if (flag == -99)
printf("Cannot be Fulfilled\n\n");
else if (donations_amount[flag] > req_amount[0]) {
donations_amount[flag] -= req_amount[0];
printf("Request Fulfilled");
req_amount[0] = 0;
}
else if (donations_amount[flag] == req_amount[0]) {
printf("Request Fulfilled");
for (i = flag; i < don_count; i++) {
strcpy(donations_inv_type[i], donations_inv_type[i + 1]);
strcpy(donations_amount[i], donations_amount[i + 1]);
}
don_count--;
for (i = flag; i < req_count; i++) {
strcpy(requests_inv_type[i], requests_inv_type[i + 1]);
strcpy(req_amount[i], req_amount[i + 1]);
}
req_count--;
}
else if (donations_amount[flag] < req_amount[0]) {
printf("Partially Fulfilled");
req_amount[0] -= donations_amount[flag];
for (i = flag; i < don_count; i++) {
strcpy(donations_inv_type[i], donations_inv_type[i + 1]);
strcpy(donations_amount[i], donations_amount[i + 1]);
don_count--;
}
}
}
else if (choice == 4) {
printf("Printing the Donations Table\n\n");
for (i = 0; i < don_count; i++) {
printf("%s %d", donations_inv_type[i], donations_amount[i]);
}
printf("Printing the Requests Table\n\n");
for (i = 0; i < req_count; i++) {
printf("%s %d", requests_inv_type[i], req_amount[i]);
}
}
printf("Welcome to the Food Bank Program\n\n 1. Add a donation\n 2. Add a request\n 3. Fulfill a request\n 4. Print status report\n 5. Exit\n\nEnter your choice: ");
}
}
Any help is greatly appreciated and I would love an explanation as to what I did wrong so that I can learn and not make the same mistakes next time.
Declare type as character array.
char type[50];
Remove & in scanf(). You should not use & while reading string.
scanf("%s", &type); ==> scanf("%s", type);
^
Here you want to copy integers not strings
strcpy(donations_amount[i], donations_amount[i + 1]);
strcpy(req_amount[i], req_amount[i + 1]);
Modify like this
donations_amount[i]=donations_amount[i + 1];
req_amount[i]= req_amount[i + 1];
Instead of char type you need char type[100]
Error in your code:
if (strcmp(donations_inv_type[i], type) == 0)
// ^^^^ should be char*
Note: Functions strcmp() and strcpy() should be passed \0 nul-terminated array of char (or say string).
Your scanf should look like scanf("%s", type);

Comparison of strings for Mastermind game

I am writing a program that simulates the game Mastermind, but I am struggling with how to compare guessed pattern to key pattern.
The game conditions are a little bit changed:
patterns consist of letters.
if an element of guessed pattern is equal to element of key pattern, and also index is equal, then print b.
if an element of guessed pattern is equal to element of key pattern, but index is not, then print w.
if an element of guessed pattern is not equal to element of key pattern, print dot.
in feedback about guessed pattern, 'b's come first, 'w's second, '.'s last.
Original key vs guess pattern match code
for (i=0; i<patternlength; i++)
{
for (x=0; x<patternlength; x++)
{
if (guess[i]==key[x] && i==x)
printf("b");
if (guess[i]==key[x] && i!=x)
printf("w");
if (guess[i]!=key[x])
printf(".");
}
}
Revised code
This is using some of the answer provided by Jonathan Leffler. Unfotunately, it isn't working correctly yet; can you help me?
The functions length() and guessnum() are defined already.
#include<stdio.h>
#include<string.h>
int length()
{
int length;
printf("Enter the pattern length: ");
scanf("%d", &length);
return length;
}
int guessnum()
{
int guessnum;
printf("Enter the number of guesses: ");
scanf("%d", &guessnum);
return guessnum;
}
int main(void)
{
int patternlength = length();
char key[patternlength+1];
char keyc[patternlength+1];
int numguess = guessnum();
char guess[patternlength+1];
printf("Input the key pattern with no spaces: ");
scanf("%s", key);
int i,j,count = 1;
int bcount = 0, wcount = 0;
char guessc[patternlength+1];
guessc[0] = '\0';
int ind;
char output[patternlength];
for (ind=0; ind<(patternlength+1); ind++)
output[ind]='\0';
char outputc[patternlength+1];
char guessold[patternlength+1];
for (ind=0; ind<(patternlength+1); ind++)
guessold[ind]='\0';
while (strcmp(key, guess) !=0 && count<=numguess)
{
if(count>1)
strcpy(guessold, guess);
strcpy(keyc, key);
printf("Input a guess pattern with no spaces: ");
scanf("%s", guess);
if (count>1)
printf("%d: %s %s\n", count-1, output, guessold);
strcpy(guessc, guess);
wcount = 0;
bcount = 0;
printf("%d: ", count);
for (i = 0; i < patternlength; i++)
{
if (keyc[i] == guessc[i])
{
putchar('b');
keyc[i] = guessc[i] = '.';
bcount++;
for (ind=0; ind<patternlength; ind++)
output[ind]='b';
}
}
if (bcount != patternlength)
{
for (i = 0; i < patternlength; i++)
{
if (guessc[i] != '.')
{
for (j = 0; j < patternlength; j++)
{
if (guessc[i] == keyc[j])
{
wcount++;
putchar('w');
for (ind=0; ind<patternlength; ind++)
if (output[ind]!='b')
output[ind]='w';
keyc[j] = guessc[i] = '.';
break;
}
}
}
}
for (i = bcount + wcount; i < patternlength; i++)
putchar('.');
for (ind=bcount+wcount; ind<patternlength; ind++)
output[ind]='.';
}
count++;
printf(" %s\n", guess);
strcpy(outputc, output);
}
if (strcmp(key, guess) != 0)
{
printf("You did not guess the pattern!\n");
}
else
{
printf("You guessed the pattern!\n");
}
return 0;
}
output of code above:
Enter the pattern length: 3
Enter the number of guesses: 3
Input the key pattern with no spaces: abc
Input a guess pattern with no spaces: acb
1: bww acb
Input a guess pattern with no spaces: abb
1: bbb acb
2: bb. abb
Input a guess pattern with no spaces: abc
2: bb. abb
3: bbb abc
You guessed the pattern!
required output:
Enter the pattern length: 3
Enter the number of guesses: 3
Input the key pattern with no spaces: abc
Input a guess pattern with no spaces: acb
1: bww acb
Input a guess pattern with no spaces: abb
1: bww acb
2: bb. abb
Input a guess pattern with no spaces: abc
1: bww acb
2: bb. abb
3: bbb abc
You guessed the pattern!
I tried to use one more string, which will store in it feedback of the guess, but when there are several guesses, i think i should use some kind of loop to print feedback of all previous guesses each time new guess is made. but it is difficult to me figure out how should i write this loop with the structure suggested by Jonathan Leffler.
I added my last correction to the code, so I almost reached the desired output. does anyone have an idea what is possible to do here?
I assume that there is a structure (for easy copying of the array contained within it), and that the input validation ensures that the key and the guess are the same length, and that the key and the guess only contain alphabetic characters.
typedef struct pattern
{
char pattern[8];
} pattern;
size_t print_scoring(pattern key, pattern guess)
{
size_t n = strlen(key.pattern);
assert(n == strlen(guess.pattern));
size_t bcount = 0;
for (size_t i = 0; i < n; i++)
{
if (key.pattern[i] == guess.pattern[i])
{
putchar('b');
key.pattern[i] = guess.pattern[i] = '.';
bcount++;
}
}
if (bcount != n)
{
size_t wcount = 0;
for (size_t i = 0; i < n; i++)
{
if (guess.pattern[i] != '.')
{
for (size_t j = 0; j < n; j++)
{
if (guess.pattern[i] == key.pattern[j])
{
wcount++;
putchar('w');
guess.pattern[i] = key.pattern[j] = '.';
break;
}
}
}
}
for (size_t i = bcount + wcount; i < n; i++)
putchar('.');
}
return bcount;
}
The function works on copies of the key and the pattern (the structures are passed by value, not by pointer). It returns the number of correct guesses in the correct position; it assumes the calling code knows how long the pattern is, so the calling code can tell when the pattern is correct. It marks guess and key characters as 'used' by replacing them with a '.'. This is important to prevent a key of "aba" and a guess of "aaa" being incorrectly marked as bbw rather than correctly as bb.. This would be more important in keys/guesses of length 4 or more.
Test Harness
#include <assert.h>
#include <string.h>
#include <stdio.h>
int main(void)
{
enum { NUM_KEYS = 3, NUM_GUESSES = 5 };
pattern k[] = { { "abc" }, { "aba" }, { "aaa" } };
pattern g[] = { { "aaa" }, { "aab" }, { "abc" }, { "cba" }, { "bab" } };
for (int i = 0; i < NUM_KEYS; i++)
{
for (int j = 0; j < NUM_GUESSES; j++)
{
printf("Key: %s; Guess %s; Score: ", k[i].pattern, g[j].pattern);
size_t n = print_scoring(k[i], g[j]);
if (n == 3)
printf(" -- Correct!");
putchar('\n');
}
}
return(0);
}
Test Output
Key: abc; Guess aaa; Score: b..
Key: abc; Guess aab; Score: bw.
Key: abc; Guess abc; Score: bbb -- Correct!
Key: abc; Guess cba; Score: bww
Key: abc; Guess bab; Score: ww.
Key: aba; Guess aaa; Score: bb.
Key: aba; Guess aab; Score: bww
Key: aba; Guess abc; Score: bb.
Key: aba; Guess cba; Score: bb.
Key: aba; Guess bab; Score: ww.
Key: aaa; Guess aaa; Score: bbb -- Correct!
Key: aaa; Guess aab; Score: bb.
Key: aaa; Guess abc; Score: b..
Key: aaa; Guess cba; Score: b..
Key: aaa; Guess bab; Score: b..
From the comments
Why is my code not working? Can you have a look at it please?
The problem is that I cannot go the next step after entering a guess pattern. Maybe I don't see some mistakes in my code.
Instant response:
One of the key points in my answer is that the comparison code is working on copies of the data entered. It is a destructive comparison algorithm, writing dots over the data. Your attempt to merge my code into your program did not retain the separate function working on separate copies of the data which were a crucial part of this answer. The use of a structure was there to make it easy to pass copies of the data around (it's the one time C copies arrays for you automatically). The comparison code should be in a function of its own, not inline in main().
However, we can get the code given to work. There were some transcription errors (marked BUG below), and some other problems (also identified below).
Working version of revised code in question
This is a working version of your program annotated with the crucial changes. Non-crucial changes include spacing around operators and using an indent level of 4 spaces.
#include <string.h>
#include <stdio.h>
static int length(void) { return 3; } // Dummy function
static int guessnum(void) { return 5; } // Dummy function
int main(void)
{
int patternlength = length();
char key[patternlength+1]; // Buffer overflow
char keyc[patternlength+1]; // Copy of key
int numguess = guessnum();
char guess[patternlength+1]; // Buffer overflow
printf("Input the key pattern with no spaces: ");
scanf("%s", key);
int i,j,count = 1;
int bcount = 0, wcount = 0;
char guessc[patternlength+1]; // Buffer overflow
guessc[0] = '\0'; // Initialize!
while (strcmp(key, guess) != 0 && count <= numguess)
{
strcpy(keyc, key); // Copy key too
printf("Input a guess pattern with no spaces: ");
scanf("%s", guess);
strcpy(guessc, guess);
wcount = 0; // Reinitialize
bcount = 0; // Reinitialize
printf("%d: ", count);
for (i = 0; i < patternlength; i++)
{
if (keyc[i] == guessc[i])
{
putchar('b');
keyc[i] = guessc[i] = '.';
bcount++;
}
}
if (bcount != patternlength) // Extraneous semi-colon excised! ;
{
for (i = 0; i < patternlength; i++)
{
if (guessc[i] != '.')
{
//for (j = 0; i < patternlength; j++) BUG
for (j = 0; j < patternlength; j++)
{
//if (guessc[i] == keyc[i]) BUG
if (guessc[i] == keyc[j])
{
wcount++;
putchar('w');
//guessc[i] = keyc[i]; BUG
keyc[j] = guessc[i] = '.';
break;
}
}
}
}
for (i = bcount + wcount; i < patternlength; i++)
putchar('.');
}
count++;
printf(" %s\n", guess);
}
if (strcmp(key, guess) != 0)
{
printf("You did not guess the pattern!\n");
}
else
{
printf("You guessed the pattern!\n");
}
return 0;
}
The compiler told me about the stray semi-colon:
ss2.c: In function ‘main’:
ss2.c:36:37: warning: suggest braces around empty body in an ‘if’ statement [-Wempty-body]
If your compiler didn't tell you about that, you aren't using enough warnings (or you need a better compiler). I routinely use:
gcc -O3 -g -std=c99 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes \
-Wold-style-definition ss2.c -o ss2
The working code passes that without a whimper.
Sample output
Input the key pattern with no spaces: abc
Input a guess pattern with no spaces: aaa
1: b.. aaa
Input a guess pattern with no spaces: bbb
2: b.. bbb
Input a guess pattern with no spaces: ccc
3: b.. ccc
Input a guess pattern with no spaces: cab
4: www cab
Input a guess pattern with no spaces: abc
5: bbb abc
You guessed the pattern!
Final debug-laden code
This is mainly to show the level of printing that I used to see what was going wrong. Using stderr for the diagnostic output meant the diagnostics did not interfere with the buffering of stdout as the output line was built up. That and the use of no indentation on the debug code also meant it was easy to strip the debug code out.
#include <string.h>
#include <stdio.h>
static int length(void) { return 3; }
static int guessnum(void) { return 5; }
int main(void)
{
int patternlength = length();
char key[patternlength+1]; // Buffer overflow
char keyc[patternlength+1]; // Copy of key
int numguess = guessnum();
char guess[patternlength+1]; // Buffer overflow
printf("Input the key pattern with no spaces: ");
scanf("%s", key);
int i,j,count = 1;
int bcount = 0, wcount = 0;
char guessc[patternlength+1]; // Buffer overflow
guessc[0] = '\0'; // Initialize!
while (strcmp(key, guess) != 0 && count <= numguess)
{
strcpy(keyc, key); // Copy key too
printf("Input a guess pattern with no spaces: ");
scanf("%s", guess);
strcpy(guessc, guess);
fprintf(stderr, "B1: (%s) vs (%s)\n", key, guess);
fprintf(stderr, "B2: (%s) vs (%s)\n", keyc, guessc);
wcount = 0; // Reinitialize
bcount = 0; // Reinitialize
printf("%d: ", count);
for (i = 0; i < patternlength; i++)
{
fprintf(stderr, "L1a: %d\n", i);
if (keyc[i] == guessc[i])
{
fprintf(stderr, "L1b: B (%c = %c)\n", keyc[i], guessc[i]);
putchar('b');
keyc[i] = guessc[i] = '.';
bcount++;
}
}
fprintf(stderr, "M1: (%s) vs (%s)\n", keyc, guessc);
if (bcount != patternlength) // Extraneous semi-colon excised! ;
{
fprintf(stderr, "L2a: b = %d (%s) vs (%s)\n", bcount, keyc, guessc);
for (i = 0; i < patternlength; i++)
{
fprintf(stderr, "L2b: %d (%c)\n", i, guessc[i]);
if (guessc[i] != '.')
{
fprintf(stderr, "L2c: %d (%c)\n", i, guessc[i]);
//for (j = 0; i < patternlength; j++) BUG
for (j = 0; j < patternlength; j++)
{
fprintf(stderr, "L2d: %d (%c) vs %d (%c)\n", i, guessc[i], j, keyc[j]);
//if (guessc[i] == keyc[i]) BUG
if (guessc[i] == keyc[j])
{
fprintf(stderr, "L2e: W %d (%c) vs %d (%c)\n", i, guessc[i], j, keyc[j]);
wcount++;
putchar('w');
keyc[j] = guessc[i] = '.';
//guessc[i] = keyc[i]; BUG
break;
}
}
}
}
fprintf(stderr, "L3a: %d + %d vs %d\n", bcount, wcount, patternlength);
for (i = bcount + wcount; i < patternlength; i++)
fprintf(stderr, "L3b: D %d\n", i),
putchar('.');
}
count++;
printf(" %s\n", guess);
}
if (strcmp(key, guess) != 0)
{
printf("You did not guess the pattern!\n");
}
else
{
printf("You guessed the pattern!\n");
}
return 0;
}
Note the trick with the comma operator after the last fprintf() function call.
Keeping a record of previous guesses and marks
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static void err_exit(const char *msg, ...);
static void prompt_str(const char *prompt, int bufsiz, char *buffer);
static int prompt_int(const char *prompt);
int main(void)
{
int patternlength = prompt_int("Length of key");
int numguess = prompt_int("Number of guesses");
char key[patternlength+1];
char guesses[numguess][patternlength+1];
char marks[numguess][patternlength+1];
int count = 0;
prompt_str("Input the key pattern with no spaces", patternlength, key);
while (count < numguess)
{
char guess[patternlength+1];
char keyc[patternlength+1];
char mark[patternlength+1];
char *marker = mark;
int wcount = 0;
int bcount = 0;
strcpy(keyc, key);
prompt_str("Input a guess pattern with no spaces", patternlength, guess);
strcpy(guesses[count], guess);
for (int i = 0; i < patternlength; i++)
{
if (keyc[i] == guess[i])
{
*marker++ = 'b';
keyc[i] = guess[i] = '.';
bcount++;
}
}
if (bcount == patternlength)
break;
for (int i = 0; i < patternlength; i++)
{
if (guess[i] == '.')
continue;
for (int j = 0; j < patternlength; j++)
{
if (guess[i] == keyc[j])
{
wcount++;
*marker++ = 'w';
keyc[j] = guess[i] = '.';
break;
}
}
}
for (int i = bcount + wcount; i < patternlength; i++)
*marker++ = '.';
*marker = '\0';
strcpy(marks[count], mark);
count++;
for (int i = 0; i < count; i++)
printf("Guess: %d [%s] marks [%s]\n", i, guesses[i], marks[i]);
}
if (count >= numguess)
printf("You did not guess the pattern (which was [%s])!\n", key);
else
printf("You guessed the pattern!\n");
return 0;
}
static void prompt_str(const char *prompt, int bufsiz, char *buffer)
{
char fmt[8];
int c;
sprintf(fmt, "%%%ds", bufsiz);
printf("%s: ", prompt);
if (scanf(fmt, buffer) != 1)
err_exit("Unexpected input failure\n");
while ((c = getchar()) != EOF && c != '\n')
;
}
static int prompt_int(const char *prompt)
{
int number;
printf("%s: ", prompt);
if (scanf("%d", &number) != 1)
err_exit("Unexpected input failure\n");
if (number <= 0 || number > 9)
err_exit("Number should be in the range 1..9 (not %d)\n", number);
return(number);
}
static void err_exit(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
vfprintf(stderr, fmt, args);
va_end(args);
exit(1);
}
Introduced functions prompt_int() and prompt_str() to get data. The prompt_str() function is reasonably resilient against overflows. There's an error reporting function. The dummy functions are replaced. Here is some sample output. From here on, you're on your own!
Length of key: 4
Number of guesses: 8
Input the key pattern with no spaces: abcd
Input a guess pattern with no spaces: aaaa
Guess: 0 [aaaa] marks [b...]
Input a guess pattern with no spaces: dcba
Guess: 0 [aaaa] marks [b...]
Guess: 1 [dcba] marks [wwww]
Input a guess pattern with no spaces: cdba
Guess: 0 [aaaa] marks [b...]
Guess: 1 [dcba] marks [wwww]
Guess: 2 [cdba] marks [wwww]
Input a guess pattern with no spaces: abcd
You guessed the pattern!
You are basically matching all the elements of key with all elements of guess, which is not what you want.
You need to iterate on guess and differentiate the three cases
Element guessed correctly
Element not guessed correctly but present in the key
Element not guessed correctly and not present in the key
int i,k;
bool found;
for (i=0; i<patternlength; i++)
{
if (key[i] == guess[i])
{
printf("b");
}
else
{
found = false;
for (k=0; k<patternlength && !found; k++)
{
if (key[k] == guess[i])
{
found = true;
printf("w");
}
}
if (!found)
{
printf(".");
}
}
}
Note that in the internal loop, I stop when I find an element with && !found. Otherwise, I'd fall into a problem similar to yours (It will print w for every element that matches my guess present in key)

Resources