Czech version
logolink

< Back to the list of lessons

Memory Game III

AlgortimyContent of the lesson:

  • Shuffling Cards
  • Viewing the Game Progress in Browser
  • Hiding Unturned Cards
  • Turning Cards

Shuffling Cards

At the end of the previous lesson you had to solve the problem of shuffling cards as your homework. Take a look at a possible solution.

The values of images are loaded into the array pexeso. However, they are ordered not as we wanted but as we filled it (according to the selected variant). This state is not ideal as the beginning state for the game. We need to sort the cards randomly.

To be able to sort the cards randomly we will need a function which can generate random number for us. In the C programming language you can use the function rand() for this purpose. This function is declared inside the header file stdlib.h so you have to add the line #include <stdlib.h> to be able to use it.

The generator will generate really random numbers once initialized. The function srand can be used to initialize it so you have to call it at the beginning of the main function - srand((unsigned int) time(NULL)) and because we use the time function for this purpose, we have to add one more header file - time.h.

Function for shuffling the array pexeso
#include "stdafx.h"
#include <stdlib.h>
#include <time.h>

int _tmain(int argc, _TCHAR* argv[])
{
  int i;
  srand((unsigned int) time(NULL));
  
  for (int i = 0; i < 10; i++)
  {
    printf("%d",rand());
  }
  
  fflush(stdin);
  getchar();
  return 0;
}

If you launch the program you can see that it generates numbers from the whole integer interval which is a prolem. We only want numbers from a particular interval. We will use the operator % for this purpose - it returns the rest after integer division.

Function for shuffling the array pexeso
#include "stdafx.h"
#include <stdlib.h>
#include <time.h>

int _tmain(int argc, _TCHAR* argv[])
{
  int i, cislo;
  srand((unsigned int) time(NULL));
  
  for (int i = 0; i < 10; i++)
  {
    cislo = rand()%10; // vygeneruje číslo od 0 do 9
    printf("%d", cislo);
  }
  
  fflush(stdin);
  getchar();
  return 0;
}

Now you have to apply the generating mechanism to our array pexeso. You can create two nested cycles to browse the array and let the position of every card be generated again (two random numbers for the row and the column). Then you can swap the value at the generated position with the current value.

The whole procedure which we described will be placed inside a new function called zamichanipexesa.

You should create a function for shuffling the array using local variables radek, sloupec, r, s at first. The first couple will be used to create the cycle to browse the array. The other one will be used for generating new numbers which will set the new position of the current card.

Procedure for shuffling the array pexeso - Part I
void zamichanipexesa()
{
  int radek, sloupec;
  int r, s;

}

Then we add the cycle which will browse all items of the array pexeso. It is a similar cycle to the one used for initializing the array and displaying the values of images.

Function for shuffling the array pexeso - Part II
void zamichanipexesa()
{
  int radek, sloupec;
  int r, s;
  
  for (radek = 0; radek < n; radek++)
  {
    for (sloupec = 0; sloupec < n; sloupec++)
    {
  
    } 
  }

}

Add two more lines to this cycle which will allow us to generate a couple of random numbers from 0 to n-1. This will be the new position of the current card. To check the function of our program you can just write the output to the console. (Note: to make our function functional you have to add a call to it inside the main program - after the call to the initialization function of the Memory Game.)

Function for shuffling the array pexeso - Part III
void zamichanipexesa()
{
  int radek, sloupec;
  int r, s;
  
  for (radek = 0; radek < n; radek++)
  {
    for (sloupec = 0; sloupec < n; sloupec++)
    {
      r = rand()%n;
      s = rand()%n;
      printf("%d %d\n", r, s);
    } 
  }

}

Now you only have to swap the actual image with the image at the generated position which will be generated using the random function. How can you swap two values?

To swap two values you need one extra variable. Swapping the values of a and b can look like this:

Swapping two values
pom = a;
a = b;
b = pom;

We can implement this inside our procedure (added lines are drawn in bold).

The final procedure to shuffle the array pexeso
void zamichanipexesa()
{
  int radek, sloupec;
  int r, s;
  int pom;
  
  for (radek = 0; radek < n; radek++)
  {
    for (sloupec = 0; sloupec < n; sloupec++)
    {
        r = rand()%n;
        s = rand()%n;
        pom = p[radek][sloupec].obrazek;
        p[radek][sloupec].obrazek = p[r][s].obrazek;
        p[r][s].obrazek = pom;
    } 
  }

}

Now you can see that the cards are arranged randomly. The output can look like the following one:

Pexeso - zamíchané kartičky pexesa

Hiding Unturned Cards

The cards are shuffled and displayed in this moment. To be able to display the game progress properly you have to change the way of displaying cards according to the fact whether they are turned or unturned.

At first we handle the state that a card is turned or unturned. In case that it is turned, you have to display the value of obrazek, otherwise 0 will be displayed.

Create a new function to display the array pexeso. This function will contain the same code construction as the mechanism to display the progress of game in the main part. Then we can adjust it to display the actual game situation (you can leave the previous code to display the image number in the main part to be able to debug the program).

Task:

Create the function zobrazenipexesa which displays the value of obrazek from our array and place a call to this function before the end of our program (before the line fflush(stdin);)

Function to display the array pexeso I
void zobrazenipexesa()
{
  int radek, sloupec;

  for (radek = 0; radek < n; radek++)
  {
    for (sloupec = 0; sloupec < n; sloupec++)
    {
            printf("%d ", p[radek][sloupec].obrazek);  
    }
    printf("\n");
  }
}

Now you have a function to display the array pexeso which was created by separating part of our main program. You should expand this function using a condition to check whether a card is visible of not.

Function to display the array pexeso II
void zobrazenipexesa()
{
  int radek, sloupec;

  for (radek = 0; radek < n; radek++)
  {
    for (sloupec = 0; sloupec < n; sloupec++)
    {
            if (p[radek][sloupec].viditelna == 1)
            {
              printf("%d ", p[radek][sloupec].obrazek);  
            }
            else
            {
              printf("0 ");  
            }            
    }
    printf("\n");
  }
}

A new condition IF ... THEN ... ELSE was added to the program. It compares the value viditelna (IF (p[radek][sloupec].viditelna == 1)).

In case that viditelna is 1 you have to write the real value of obrazek, otherwise write 0.

Then enrich the program to be able to hide removed cards. In case that a card was removed, the X char will be displayed, otherwise the previous condition will be executed.

Function to display the array pexeso III
void zobrazenipexesa()
{
  int radek, sloupec;

  for (radek = 0; radek < n; radek++)
  {
    for (sloupec = 0; sloupec < n; sloupec++)
    {
         if (p[radek][sloupec].odebrana == 1)
         {
            printf("X ");
         }
         else
         { 
            if (p[radek][sloupec].viditelna == 1)
            {
              printf("%d ", p[radek][sloupec].obrazek);  
            }
            else
            {
              printf("0 ");  
            }
         }            
    }
    printf("\n");
  }
}

The final output of this procedure should look like the following one:

Pexeso - skrytí kartiček pexesa

Turning Cards

You have defined the displaying mechanism to display the cards according to the fact they are turned or unturned. Now you should create a procedure to require input from a player which means turning cards.

Compared to the previous procedures, this one will have input parameters. Input parameters should be the coordinates of the card (row and column) which has to be turned.

Turning a card
void otockarticku(int radek, sloupec);
{
    p[radek][sloupec].viditelna = 1;
}

The function for turning cards is quite simple. We only load two parameters which set the number of row and column and then we set the value of viditelna for the appropriate card to 1. Then we call the function using the following command: otockarticku(r, s);

 

To be able to try our function, we will turn two cards and display our array pexeso. To execute the following code you will need 4 global variables using the byte data type: radek1, sloupec1, radek2 and sloupec2.

Turning a couple of cards and displaying the array pexeso
...

printf("Zadejte souradnice 1. karticky (radek): ");
scanf("%d", radek1);
printf("Zadejte souradnice 1. karticky (sloupec): ");
scanf("%d", sloupec1);

printf("Zadejte souradnice 2. karticky (radek): ");
scanf("%d", radek2);
printf("Zadejte souradnice 2. karticky (sloupec): ");
scanf("%d", sloupec2);

otockarticku(&p, radek1,sloupec1);
otockarticku(&p, radek2,sloupec2);

zobrazenipexesa();

...
Pexeso - otočení dvojice kartiček pexesa

The whole source code using all upgrades from this lesson is available below this text.

#include "stdafx.h"
#define n 6
#define maxhracu 4

typedef struct {
  int obrazek;
  int viditelna;
  int odebrana;
} karticka;              

typedef struct {
  char jmeno[255];
  int skore;
} hrac;

karticka p[n][n]; 
hrac ph[maxhracu];

void inicializacepexesa()
{
	int radek, sloupec, pocet;
    pocet = 1;
        
    for (radek = 0; radek < n; radek++)
    {
        for (sloupec = 0; sloupec < n; sloupec++)
        {
            pocet = pocet + 1;
            p[radek][sloupec].obrazek = pocet % 2;
            p[radek][sloupec].viditelna = 0;
            p[radek][sloupec].odebrana = 0;
        }
    }
}

void zamichanipexesa()
{
  int radek, sloupec;
  int r, s;
  int pom;
  
  for (radek = 0; radek < n; radek++)
  {
    for (sloupec = 0; sloupec < n; sloupec++)
    {
        r = rand()%n;
        s = rand()%n;
        pom = p[radek][sloupec].obrazek;
        p[radek][sloupec].obrazek = p[r][s].obrazek;
        p[r][s].obrazek = pom;
    } 
  }
}

void zobrazenipexesa()
{
  int radek, sloupec;

  for (radek = 0; radek < n; radek++)
  {
    for (sloupec = 0; sloupec < n; sloupec++)
    {
         if (p[radek][sloupec].odebrana == 1)
         {
            printf("X ");
         }
         else
         { 
            if (p[radek][sloupec].viditelna == 1)
            {
              printf("%d ", p[radek][sloupec].obrazek);  
            }
            else
            {
              printf("0 ");  
            }
         }            
    }
    printf("\n");
  }
}

void otockarticku(int radek, sloupec);
{
    p[radek][sloupec].viditelna = 1;
}

int _tmain(int argc, _TCHAR* argv[])
{

  int radek, sloupec, pocet;

  inicializacepexesa();
  zamichanipexesa()

  for (radek = 0; radek < n; radek++)
  {
    for (sloupec = 0; sloupec < n; sloupec++)
    {
        printf("%d ", p[radek][sloupec].obrazek);
    }
    printf("\n");
  }
  
  printf("Zadejte souradnice 1. karticky (radek): ");
  scanf("%d", radek1);
  printf("Zadejte souradnice 1. karticky (sloupec): ");
  scanf("%d", sloupec1);

  printf("Zadejte souradnice 2. karticky (radek): ");
  scanf("%d", radek2);
  printf("Zadejte souradnice 2. karticky (sloupec): ");
  scanf("%d", sloupec2);

  otockarticku(radek1,sloupec1);
  otockarticku(radek2,sloupec2);

  zobrazenipexesa();
  
  fflush(stdin);
  getchar();
  return 0;
 }

Homework

How can you change the procedure to turn a card to prevent error states (you should always turn two different cards)? Suggest an adjustment of this procedure.

webdesign, xhtml, css, php - Mgr. Michal Mikláš