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.
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 asbbwrather than correctly asbb.. This would be more important in keys/guesses of length 4 or more.Test Harness
Test Output
From the comments
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.
The compiler told me about the stray semi-colon:
If your compiler didn’t tell you about that, you aren’t using enough warnings (or you need a better compiler). I routinely use:
The working code passes that without a whimper.
Sample output
Final debug-laden code
This is mainly to show the level of printing that I used to see what was going wrong. Using
stderrfor the diagnostic output meant the diagnostics did not interfere with the buffering ofstdoutas 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.Note the trick with the comma operator after the last
fprintf()function call.Keeping a record of previous guesses and marks
Introduced functions
prompt_int()andprompt_str()to get data. Theprompt_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!