#### Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

# help with memory game (pairs)

Member Posts: 7
hi! i made this code that should run like the classic pairs game. the problem is, it isn't doing what it's supposed to do. when the user inputs the same coordinates consecutively it should display "invalid input" the ask for another input, instead, it leaves the "asterisk/card" open. help me please? i need to figure it out in 5 hours.. i'm a newbie. thanks

[code=c]

//this program runs on windows

#include
#include
#include
#include "generate.h"

int main(void){
int a, b, c, d;
int i, j, moves;
char board[6][6];
char incboard[6][6]={"******","******","******","******","******","******"};
char opencheck[6][6]={"000000", "000000", "000000", "000000", "000000", "000000",};
moves=0;
make_matrix(board);//connects the generated matrix/answer key to the program
for(i=0;i<6;i++)//prints the matrix
{
for(j=0;j<6;j++)
{
printf(" %c",incboard[i][j]);
}
printf("
");
}

for (i=0; i<6; i++){
for (j=0;j<6;j++)
{
if (incboard[i][j]!='*')
{
printf("
Congratulations! You were able to match all the pairs in %d moves", moves);
}
//checks if matrix and the answer key are the same
else
{
//lets the user enter the 1st set of coordinates
printf("
Enter coordinates in the form of row,column:");
getch();
scanf("%d,%d", &a, &b);

//locates the coordinates given by the user if the input is valid
if (a>0 && a<=6 && b>0 && b<=6 && opencheck[--a][--b]!='1')
{
system("cls");
processBoard(a, b, board, incboard, opencheck);
//lets the user enter the 2nd set of coordinates
printf("
Enter another set of coordinates in the form of row,column:");
getch();
scanf("%d,%d", &c, &d);

//locates the coordinates given by the user
if ((++a!=c && ++b!=d)||c>0 && c<=6 && d>0 && d<=6 && opencheck[--c][--d]!='1')
{
system ("cls");
c;
d;
moves++;//counts the number of moves the user made
processBoard(c, d, board, incboard, opencheck);
checkmatch(a, b, c, d, incboard, opencheck);

}

//checks if the 2nd set of coordinates given by the user is valid
else if((isdigit(c))==0||(isdigit(d))==0||c<=0||c>6||d<=0||d>6){
printf("Invalid input
");
do{
printf("
Enter another set of coordinates in the form of row,column:");
getch();
scanf("%d,%d", &c, &d);
}while((isdigit(c))==0||(isdigit(d))==0||c<=0||c>6||d<=0||d>6);
}
else
{
printf("Invalid input
");
}

}

//checks if the 1st set of coordinates given by the user is valid
else if((isdigit(a))==0||(isdigit(b))==0||a<=0||a>6||b<=0||b>6)
{
printf("Invalid input
");
}
}
}
}

}

//processes the board and locates the position using coordinates given by the user
int processBoard(int a, int b, char board[6][6], char incboard[6][6], char opencheck[6][6]){
int i,j;
incboard[a][b]=board[a][b];
opencheck[a][b]='1';
//displays the character value in the matrix of the given coordinate
for (i=0; i<6; i++)
{
for(j=0; j<6; j++)
{
printf(" %c", incboard[i][j]);
}
printf("
");
}
}

//checks if the elements of the coordinates given by the user are the same
int checkmatch(int a, int b, int c, int d, char incboard[6][6], char opencheck[6][6]){
int i, j;

if (incboard[a][b]!= incboard[c][d]){
sleep(3);
system("cls");
opencheck[a][b]='0';
opencheck[c][d]='0';
incboard[c][d]='*';
incboard[a][b]='*';

//prints the matrix
for(i=0;i<6;i++){
for(j=0;j<6;j++){
printf(" %c",incboard[i][j]);
}
printf("
");
}
}

else {
opencheck[a][b]='1';
opencheck[c][d]='1';
}

}
[code]

• Member Posts: 5
First off, too many side-effects. What I mean by this is demonstrated perfectly in the following bit of your code:

[code]
if (a>0 && a<=6 && b>0 && b<=6 && opencheck[--a][--b]!='1')
{
...
if ((++a!=c && ++b!=d)||c>0 && c<=6 && d>0 && d<=6 && opencheck[--c][--d]!='1')
{
...
}
}
[/code]

if you want to check an off by one value, either change it or don't, but don't constantly change it back and forth via the use of the increment and decrement operator. It makes for confusing code that is hard to follow since values are constantly being interpreted as two different things and constantly changed back and forth to fill these two roles.

Something that would be easier to follow would be something like:
[code]
scanf("%d,%d", &userInput_a, &userInput_b);
int arrayIndex_a = a-1;
int arrayIndex_b = b-1;

if (0 < userInput_a && userInput_a <= 6
&& 0 < userInput_b && userInput_b <= 6
&& opencheck[arrayIndex_a][arrayIndex_b] != '1')
{
...
if ((userInput_a != userInput_c && userInput_b != userInput_d)
|| 0 < c && c <= 6
&& 0 < d && d <= 6
&& opencheck[arrayIndex_c][arrayIndex_d] != '1')
{
...
}
}
[/code]

Here's an issue:

[code]
if (a>0 && a<=6
&& b>0 && b<=6
&& opencheck[--a][--b]!='1')
{
...

if ((++a!=c && ++b!=d)
|| c>0 && c<=6
&& d>0 && d<=6
&& opencheck[--c][--d]!='1')
{
...
}
}
[/code]

So lets say the user enters 1,1 for a,b and 1,1 for c,d
[code]
if ( 1 > 0 && 1 <= 6
&& 1 > 0 && 1 <= 6
&& opencheck[0][0] != '1')
{
...

if ((1 != 1 && 0 != 1)
|| 1 > 0 && 1 <= 6
&& 1 > 0 && 1 <= 6
opencheck[0][0] != '1')
{
...
checkmatch(1, 0, 0, 0, incboard, opencheck);
}
}
[/code]

That just seems wrong to me.

You need to realize the side-effects of your code. It is doing exactly what you are telling it to. So the issue isn't your code's fault. The issue is you don't understand the impact of operation side-effects on your code.

Now given that I don't know what the processBoard or checkmatch functions do per se, I do know that regardless of what they do the logic in main is flawed.

I suppose I'll be nice and cover the main side-effect you are facing here. It's called short-circuit evaluation. In the case where you are doing logical checks (ie. && or ||) the execution can chose to, depending on the implementation of the compiler, stop evaluation of the full statement at any given point where the result is known.

so in the case of:
[code]
if ((++a!=c && ++b!=d)||c>0 && c<=6 && d>0 && d<=6 && opencheck[--c][--d]!='1')
[/code]

if ++a != c == false then there is no reason to finish the check of the ++b != d. This means that ++b is never run and thus b's value is never turned back to what it potentially should be. But in the case of your code who knows what it is actually supposed to be.

Same thing goes for if (++a != c && ++b != d) == true. Execution can now chose to go into the for statement before ever executing opencheck[--c][--d] != '1'. This again causes an issue if those values don't get converted, is that the right behavior? My guess is probably not.

But what's even worse is that the && and || operators are left-to-right associative which means that ((++a != c && ++b != d)|| c < 0) will short-circuit given that (++a != c && ++b != d) == false and c < 0 == true.

Things to make SURE you know:
Precedence
Association
Side-effects

Otherwise you will run into bugs that you will never be able to make sense of.