Memory game using OOP

Hey,
i want to make a memory game where you have to find the couples of numbers in the board but i have some questions.

i don't know if every card should be an object (from the same class) or not. for instance i'd like to do something like this:

card.GetValue(2,3);

this function goes trough all the cards and finds the one with xCoord=2 and yCoord=3 and gives me the respective value.

but with classes i can't make a single object (card) and access all the cards from that. i would have to make many cards (card1, card2, ...) but then i can't call that function anymore. (card1.GetValue(2,3); is only checking if card1 is at the position 2,3 and i want it to check ALL the cards)
(sorry i can't explain it better)

this is a pseudo code to make you understand a little better my problem, it would be great if you guys can point me in the right direction on what to use / what is best to use in this situation.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include <iostream>

using namespace std;

class CCard{
  int xCor;
  int yCor;
  int value; // This is a number from 1 to 8
  bool isFaceUp;
public:
  CCard(int x, int y, int val){ // Constructor
    xCor = x;
    yCor = y;
    value = val;
    isFaceUp = false;
  }
};

void MakeCards(){
  // I can't make many cards like this...(it's also ugly)
  CCard card1(1,1,2);
  CCard card2(2,1,3);
  CCard card3(3,1,7);
  CCard card4(4,1,5);
  CCard card5(1,2,1);
  CCard card6(2,2,4);
  CCard card7(3,2,8);
  CCard card8(4,2,2);
  CCard card9(1,3,7);
  CCard card10(2,3,6);
  CCard card11(3,3,8);
  CCard card12(4,3,1);
  CCard card13(1,4,6);
  CCard card14(2,4,3);
  CCard card15(3,4,4);
  CCard card16(4,4,5);
}

void ShowBoard(){
  for(int y=0;y<4;y++){
    for(int x=0;x<4;x++){
      cout << GetCardValue(x,y) << " "; //<- When i got the coord from the user
    }                                   //   i would put them in some function
    cout << endl;                       //   that returns the value of the card
  }                                     //   (the card that meets the coord)
}                                       //   in this case the coord are given by the loops BTW

int main(){
  MakeCards();
  ShowBoard();
}


The second question is how to fill the board with 8 PAIRS of numbers
(so i have {1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8} and i want to randomly give these values to the cards at each position in the board.)

the end result should look more or less like this:

5 8 4 7
2 1 8 3
6 3 4 7
2 5 1 6


thanks in advice for the help! and sorry if i made some mistakes ^^
Last edited on
Use an array for the cards. Set the values with loops. Here is a quite frankly lazy way of doing it, but it will give you the idea.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class card
{
    public:
    int posx, posy;
};

int main()
{
    int i, j, x = 0;
    card deck[52];
    for(i = 0; i < 13; ++i)
    {
        for(j = 0; j < 4; ++j)
        {
            deck[x].posx = i;
            deck[x].posy = j;
            ++x;
        }
    }
    return 0;
}


You can also use loops to set the values of the cards to whatever numbers and so forth.
Thanks a lot! that was the push i needed to get me started.
so now i have the deck[4][4] that holds all the cards, for now the only problem is how to put all the PAIRS in random positions of the board

the code so far:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include <iostream>
#include <cstdlib>
#include <ctime>

using namespace std;

class CCard{
  int xCor;
  int yCor;
  int value;
  bool faceUp;
public:
  CCard(){ // Constructor
    faceUp = false;
  }

  void SetValue(int v){
    value = v;
  }

  int GetValue(){
    return value;
  }
} deck[4][4];

void SetCards(){
  for(int y=0;y<4;y++){
    for(int x=0;x<4;x++){
      deck[x][y].SetValue(rand()%8+1);
    }
  }
}

void ShowBoard(){
  for(int y=0;y<4;y++){
    for(int x=0;x<4;x++){
      cout << deck[x][y].GetValue() << " ";
    }
    cout << endl;
  }
}

int main(){
  srand(time(NULL));
  SetCards();
  ShowBoard();
}


Now of curse i give random values at line 29, but i need to put only couples of numbers from 1 to 8, anyone has a good idea?

thanks again for the time ;)
You could just do a bunch of random swaps, something like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <iostream>
#include <ctime>
#include <cstdlib>

int main()
{
    srand(time(NULL));
    int n[16] = {1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8};
    int x = 0, y = 0, z = 0, swaps = 0, temp = 0;
    swaps = rand() % 10 + 10; //Number of random swaps we are going to do.
    while(x < swaps) //1 / 16 times no swap will happen (do you see why?)
    {
        y = rand() % 16; //Choose a random array element. 
        temp = n[y]; //Make a copy of the value in that element. 
        z = rand() % 16; //Choose a random array element. 
        n[y] = n[z]; //Put the second array element into the first. 
        n[z] = temp; //Put the copy of the first into the second. 
        ++x;
    }
    for(x = 0;x < 16;++x)
    {
        std::cout << n[x] << "\n";
    }
    return 0;
}


This is for a 1d array, but it's not much extra work to make it for 2d.

Edit: Commented code a bit.
Last edited on
1
2
3
4
void SetCards(){
  for(int y=0;y<4;y++){
    for(int x=0;x<4;x++){
      deck[x][y].SetValue(rand()%8+1);

your cards ARE randomized... however this doesn't guarentee that there will always be a pair

try something like this
1
2
3
4
5
6
7
8
9
10
11
12
13
14
void SetCards(){
  bool pair=1;
  int random;;
  for(int y=0;y<4;y++)
    for(int x=0;x<4;x++)
    {
        if (pair)
        {
              random=rand()%8+1;
              pair=!pair;
         }
         deck[x][y].SetValue(random);
    }
}
Last edited on
I'd suggest setting up 2 cards at a time (ensuring they have pairs) and then create a loop which swaps the values (or addresses) of the cards.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
int num = 8; //However many pairs you want
num *= 2; //Used as pairs to prevent odd cards
int cards = new int[num];
//This loop sets up pairs
for(int i=0; i<num; i+=2){
    cards[i] = cards[i+1] = (i/2)+1;
}

//This loop randomises the order
for(int i=0; i<num; i++){
    int temp = cards[i];
    int swap = rand() % num;
    cards[i] = cards[swap];
}


Assuming you've seeded the random algorithm with srand()
Last edited on
@threeright:
I like your idea but i believe it's not working as it should for this project, you are making pairs of random numbers but there can be pairs of the same number inside the deck (for example this may happen):
{1,1,3,3,5,5,1,1,7,7,8,8,6,6,4,4}

@SatsumaBenji:
I like your concept a lot, very nice and clean but if i'm not mistaking the code you provided sets Cards this way:
{0,0,2,2,4,4,6,6,8,8,10,10,12,12,14,14}
to have number from 1 to 8 you just have to modify slightly the code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
int num = 8; //However many pairs you want
num *= 2; //Used as pairs to prevent odd cards
int cards = new int[num];
//This loop sets up pairs
for(int i=0; i<num; i+=2){
    cards[i] = cards[i+1] = (i/2)+1;
}

//This loop randomises the order
for(int i=0; i<num; i++){
    int temp = cards[i];
    int swap = rand() % num;
    cards[i] = cards[swap];
}


right?

anyway i did it more or less like Mats said, by initializing an array with the pairs and then swapping them.

This is the final code if someone wants to try it, i appreciate if you have any suggestions to improve it!
I may make another version where you navigate trough the cards with WASD or the arrow keys instead of inserting the coordinates.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
#include <iostream>
#include <cstdlib>
#include <ctime>

using namespace std;

//Global variables
char coordX, coordY;

class CCard{
  int value;
  bool faceUp;
public:
  CCard(){ // Constructor
    faceUp = false;
  }

  void SetValue(int v){
    value = v;
  }
  
  void TurnCard(){
    faceUp = !faceUp;     
  }

  int GetValue(){
    return value;
  }
  
  bool GetFaceUp(){
    return faceUp;   
  }
} deck[4][4];

void ShowBoard(){ // Prints the board on screen
  system("cls");
  cout << "   1 2 3 4" << endl << endl;
  for(int y=0;y<4;y++){
    cout << y+1 << "  ";
    for(int x=0;x<4;x++){
      if(deck[x][y].GetFaceUp() == true){ // If the card is facing up show it
        cout << deck[x][y].GetValue() << " ";
      }
      else{ // If is facing down show an ASCII character (hidden card)
        cout << (char)177 << " ";     
      }
    }
    cout << endl << endl;
  }
  cout << endl;
}

void SetCards(){ // Set the cards in random order
  int pairs[16] = {1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8};
  int a, b, temp;
  for(int i=0;i<30;i++){ // Swap 30 times
    a = rand()%16;
    b = rand()%16;
    temp = pairs[a];
    pairs[a] = pairs[b];
    pairs[b] = temp;
  }     
  for(int y=0;y<4;y++){
    for(int x=0;x<4;x++){
      deck[x][y].SetValue(pairs[x +(y * 4)]); // Puts swapped cards in the deck 
    }
  }
}

void GetInput(){ // Gets the user input
  bool isAlreadyUp;
  do{
    do{ // Insert X
      cout << "Insert coordinate X: ";
      cin >> coordX;                          // coordX/Y are char to prevent the program from crashing!
      if(coordX < (1+48) || coordX > (4+48)){ // i have to check based on the ASCII table (48 = 0)
        cout << "Invalid selection!" << endl;          
      }
    }while(coordX < (1+48) || coordX > (4+48));
    do{ // Insert Y
      cout << "Insert coordinate Y: ";
      cin >> coordY;    
      if(coordY < (1+48) || coordY > (4+48)){
        cout << "Invalid selection!" << endl;          
      }
    }while(coordX < (1+48) || coordX > (4+48));
    if(deck[(int)(coordX-48-1)][(int)(coordY-48-1)].GetFaceUp() == true){ // If player inputs an already-matched card
      cout << "You already found the match for this card!" << endl << endl;   
      isAlreadyUp = true;                                                   
    }
    else{
      isAlreadyUp = false;     
    }
  }while(isAlreadyUp == true);
  // Adjust values (easier to work with arrays)
  coordX--; 
  coordY--;   
}

void Pause(){ // Ugly but works fine
  for(int i=0;i<2000;i++){
    for(int j=0;j<300000;j++);
  }   
}

int main(){
  int holderX, holderY, remaining = 16, tries = 0;
  char reply;
  bool secondTurn = false;
  srand(time(NULL));
  while(1){ // Infinite loop
    SetCards();
    do{ // Loop until player matched all cards
      ShowBoard();
      GetInput();
      deck[(int)(coordX-48)][(int)(coordY-48)].TurnCard(); // Turns the selected card  
      if(secondTurn == true){ // If player turned the second card we have to look if they match
        secondTurn = false; 
        tries++;
        if((((int)(coordX-48)) == holderX) && ((int)(coordY-48) == holderY)){ // The user selected the same card twice!
          tries--;
          cout << "You can't select the same card twice!" << endl;
          Pause();
          continue;
        }
        if(deck[(int)(coordX-48)][(int)(coordY-48)].GetValue() == deck[holderX][holderY].GetValue()){ // If cards match
          ShowBoard();   
          cout << "You matched 2 cards!" << endl;   
          remaining -= 2;                                
        }  
        else{ // If cards are different
          ShowBoard();
          cout << "The cards are different!" << endl;
          deck[(int)(coordX-48)][(int)(coordY-48)].TurnCard(); // Turn cards again
          deck[holderX][holderY].TurnCard();
        }
        Pause();
      }
      else{ // If this is the first card turned, we store the x,y coords for later use
        holderX = (int)(coordX-48);
        holderY = (int)(coordY-48);
        secondTurn = true;
      }
    }while(remaining > 0);
    
    cout << "Congratulation! you matched all the cards in " << tries << " tries!" << endl;
    
    do{ // Asks the user if he wants to play again
      cout << "Do you want to play again? (y/n): ";
      cin >> reply;
      if(reply == 'n' || reply == 'N'){
        return 0;
      }
      else if(reply != 'n' && reply != 'N' && reply != 'y' && reply != 'Y'){
        cout << "Invalid character, try again." << endl << endl;     
      }
    }while(reply != 'y' && reply != 'Y');
    
    // Reset varables if player wants to play again
    remaining = 16;
    tries = 0;
    for(int y=0;y<4;y++){
      for(int x=0;x<4;x++){
        deck[x][y].TurnCard(); // Turns all the cards face down
      }
    }
  }
} 


Thanks again to you all, this was a very fun project! ^^
Last edited on
Indeed it does... Sorry about that, my bad. (and I've corrected my above cods)

This is because I originally had it grouped in pairs and changed my mind (and forgot to change other bits)
Good spotting though XD
I made the V2, you move with arrow keys and turn the card with spacebar.
I have a little problem when the program asks me if i want to continue.

the first time i write 'y' and the game restarts.
the second time however, in the place where i'm supposed to write 'y' or 'n', there is already a 'y' and sometimes a bounch of spaces too! i think that this happens because i don't flush the memory/buffer/stream or whatever.

can someone help me with this problem?
everything else seems to work fine.

this is the code, it's a bit messy i know... not very easy to follow.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <windows.h>

using namespace std;

//Global variables
int coordX, coordY;
int selector[4][4] = {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};

class CCard{
  int value;
  bool faceUp;
public:
  CCard(){ // Constructor
    faceUp = false;
  }

  void SetValue(int v){
    value = v;
  }
  
  void TurnCard(){
    faceUp = !faceUp;     
  }

  int GetValue(){
    return value;
  }
  
  bool GetFaceUp(){
    return faceUp;   
  }
} deck[4][4];

void SetCards(){ // Set the cards in random order
  int pairs[16] = {1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8};
  int a, b, temp;
  for(int i=0;i<30;i++){ // Swap 30 times
    a = rand()%16;
    b = rand()%16;
    temp = pairs[a];
    pairs[a] = pairs[b];
    pairs[b] = temp;
  }     
  for(int y=0;y<4;y++){
    for(int x=0;x<4;x++){
      deck[x][y].SetValue(pairs[x +(y * 4)]); // Puts swapped cards in the deck 
    }
  }
}

void ShowBoard(){ // Print/update the board on screen
  system("cls");
  cout << "   1 2 3 4" << endl << endl;
  for(int y=0;y<4;y++){
    cout << y+1 << "  ";
    for(int x=0;x<4;x++){
      if(deck[x][y].GetFaceUp() == true){ // If the card is facing up show it's value
        cout << deck[x][y].GetValue() << " ";
      }
      else{ // If is facing down show an ASCII character (hidden card)
        cout << (char)177 << " ";     
      }
    }
    cout << endl;
    cout << "   ";
    for(int x=0;x<4;x++){
      if(selector[x][y] == 1){ // If selector is at x,y show arrow
        cout << (char)94 << " ";
      }
      else{ // Else show nothing (spaces)
        cout << "  ";     
      }
    }
    cout << endl;
  }
  cout << endl;
}

void GetInput(){ // Gets the user input
  while(1){
    while(1){
      if(GetAsyncKeyState(VK_UP) & 1){ // UP
        if((coordY-1) < 0){ // If out of boundaries
          coordY = 3;
        }
        else{
          coordY--;
        }
        break;                     
      } 
      if(GetAsyncKeyState(VK_DOWN) & 1){ // DOWN
        if((coordY+1) > 3){ // If out of boundaries
          coordY = 0;
        }
        else{
          coordY++;
        }
        break;                      
      } 
      if(GetAsyncKeyState(VK_LEFT) & 1){ // LEFT
        if((coordX-1) < 0){ // If out of boundaries
          coordX = 3;
        }
        else{
          coordX--;
        }
        break;                       
      } 
      if(GetAsyncKeyState(VK_RIGHT) & 1){ // RIGHT
        if((coordX+1) > 3){ // If out of boundaries
          coordX = 0;
        }
        else{
          coordX++;
        }
        break;                        
      }     
      if((GetAsyncKeyState(VK_SPACE) & 1)){ // SPACE = turns card pointed by selector
        if(deck[coordX][coordY].GetFaceUp() == true){ // If player selects an already-matched card
          cout << "You can't select this card again!" << endl << endl;                                     
          continue;               
        }
        else{
          deck[coordX][coordY].TurnCard();
          return; 
        }                        
      }  
    }
    // Everytime the user presses a key the following is executed
    for(int y=0;y<4;y++){
      for(int x=0;x<4;x++){
        selector[x][y] = 0; // Clear selector array
      }
    }
    selector[coordX][coordY] = 1; // Sets selector array at right position
    ShowBoard(); // Updates board
  }
}

int main(){
  int holderX, holderY, remaining = 16, tries = 0;
  char reply;
  bool secondTurn = false;
  srand(time(NULL));
  while(1){ // Infinite loop
    SetCards();
    do{ // Loop until player matched all cards
      ShowBoard();
      GetInput();
      if(secondTurn == true){ // If player turned the second card we have to look if they match
        secondTurn = false; 
        tries++;
        if((coordX == holderX) && (coordY == holderY)){ // The user selected the same card twice!
          tries--;
          cout << "You can't select the same card twice!" << endl;
          continue;
        }
        if(deck[coordX][coordY].GetValue() == deck[holderX][holderY].GetValue()){ // If cards match
          ShowBoard();   
          cout << "You matched 2 cards!" << endl;   
          remaining -= 2;                                
        }  
        else{ // If cards are different
          ShowBoard();
          cout << "The cards are different!" << endl;
          deck[coordX][coordY].TurnCard(); // Turn cards again
          deck[holderX][holderY].TurnCard();
        }
        while(1){ // This is a pause, the user can read the text until he presses an arrow key
          if(remaining == 0){ // Or if there aren't cards left
            break;             
          }
          if(GetAsyncKeyState(VK_UP) & 1){ // UP
            if((coordY-1) < 0){ // If out of boundaries
              coordY = 3;
            }
            else{
              coordY--;
            }
            break;                     
          } 
          if(GetAsyncKeyState(VK_DOWN) & 1){ // DOWN
            if((coordY+1) > 3){ // If out of boundaries
              coordY = 0;
            }
            else{
              coordY++;
            }
            break;                      
          } 
          if(GetAsyncKeyState(VK_LEFT) & 1){ // LEFT
            if((coordX-1) < 0){ // If out of boundaries
              coordX = 3;
            }
            else{
              coordX--;
            }
            break;                       
          } 
          if(GetAsyncKeyState(VK_RIGHT) & 1){ // RIGHT
            if((coordX+1) > 3){ // If out of boundaries
              coordX = 0;
            }
            else{
              coordX++;
            }
            break;                        
          }         
        }
        for(int y=0;y<4;y++){
          for(int x=0;x<4;x++){
            selector[x][y] = 0; // Clear selector array
          }
        }
        selector[coordX][coordY] = 1; // Sets selector array
        ShowBoard();
      }
      else{ // If this is the first card turned, we store the x,y coords for later use
        holderX = coordX;
        holderY = coordY;
        secondTurn = true;
      }
    }while(remaining > 0);
    
    cout << "Congratulation! you matched all the cards in " << tries << " tries!" << endl;
    
    do{ // Asks the user if he wants to play again
      cout << "Do you want to play again? (y/n): ";
      cin >> reply;
      if(reply == 'n' || reply == 'N'){
        return 0;
      }
      else if(reply != 'n' && reply != 'N' && reply != 'y' && reply != 'Y'){
        cout << "Invalid character, try again." << endl << endl;     
      }
    }while(reply != 'y' && reply != 'Y');
    
    // Reset varables if player wants to play again
    remaining = 16;
    tries = 0;
    coordX = 0;
    coordY = 0;
    for(int y=0;y<4;y++){
      for(int x=0;x<4;x++){
        deck[x][y].TurnCard(); // Turns all the cards face down
        selector[x][y] = 0; // Clear selector array
      }
    }
    selector[0][0] = 1; // Sets selector array
  }
} 
Topic archived. No new replies allowed.