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.

For random order of cards we need a function which generates a random number for us. You can use the function random in Pascal - its syntax is:

Syntax of the function for creating a random number.
random(max);

This function generates a random number in interval from 0 to max-1 included. You can try the function by writing its result to console:

Function for creating a random number.
writeln(random(10));

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 procedure called zamichanipexesa.

You should create a procedure 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
procedure zamichanipexesa;
var radek, sloupec : byte;
    r, s : byte;
begin
    
end;

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.

Procedure for shuffling the array pexeso - Part II
procedure zamichanipexesa;
var radek, sloupec : byte;
    r, s : byte;
    begin
    for radek := 1 to n do
    begin
        for sloupec := 1 to n do

        begin
     
        end;
    end;
end;

Add two more lines to this cycle which will allow us to generate a couple of random numbers from 1 to n. This will be the new position of the current card.

Because the random function generates a number from interval 0 to n-1, you have to increase the result by one. 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.)

Procedure for shuffling the array pexeso - Part III
procedure zamichanipexesa;
var radek, sloupec : byte;
    r, s : byte;
    pom : byte;
begin
    for radek := 1 to n do
    begin
        for sloupec := 1 to n do
        begin
            r := random(n) + 1;
            s := random(n) + 1;
            writeln(r, ' ', s);
        end;
    end;
end;

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
procedure zamichanipexesa;
var radek, sloupec : byte;
    r, s : byte;
    pom : byte;
begin
    for radek := 1 to n do
    begin
        for sloupec := 1 to n do
        begin
            r := random(n) + 1;
            s := random(n) + 1;
            pom := p[radek, sloupec].obrazek;
            p[radek, sloupec].obrazek := p[r, s].obrazek;
            p[r, s].obrazek := pom;

        end;
    end;
end;

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 procedure to display the array pexeso. This procedure 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 procedure zobrazenipexesa which displays the value of obrazek from our array and place a call to this procedure before the end of our program (before the line readln;)

Procedure to display the array pexeso I
procedure zobrazenipexesa;

var radek, sloupec : byte;
begin
    for radek := 1 to n do
    begin
        for sloupec := 1 to n do
        begin
            write(p[radek, sloupec].obrazek,' ');  
        end;
        writeln;
    end;
end;

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

Procedure to display the array pexeso II
procedure zobrazenipexesa;
var radek, sloupec : byte;
begin
    for radek := 1 to n do
    begin
        for sloupec := 1 to n do
        begin
            IF p[radek, sloupec].viditelna THEN
                write(p[radek, sloupec].obrazek,' ')
            ELSE

                write('0 ');  
        end;
        writeln;
    end;
end;

A new condition IF ... THEN ... ELSE was added to the program. It compares the value viditelna (IF p[radek, sloupec].viditelna THEN). There is no need to write IF p[radek, sloupec].viditelna = true THEN because the value of viditelna is already a boolean value.

In case that viditelna is true 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.

Procedure to display the array pexeso III
procedure zobrazenipexesa;
var radek, sloupec : byte;
begin
    for radek := 1 to n do
    begin
        for sloupec := 1 to n do
        begin
            IF p[radek, sloupec].odebrana THEN

                write('X ')
            ELSE
                IF p[radek, sloupec].viditelna THEN
                    write(p[radek, sloupec].obrazek,' ')
                ELSE
                    write('0 ');  
        end;
        writeln;
    end;
end;

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
procedure otockarticku(var radek,sloupec:byte);
begin
    p[radek, sloupec].viditelna := true;
end;

The procedure appears to be simple. It loads two parameters which set the row and column positions and then it sets the value of viditelna to true.

To be able to try our procedure, 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
...

writeln('Enter first card coordinates (row): ');
readln(radek1);
writeln('Enter first card coordinates (column): ');
readln(sloupec1);

writeln('Enter second card coordinates (row): ');
readln(radek2);
writeln('Enter second card coordinates (column): ');
readln(sloupec2);

otockarticku(radek1,sloupec1);
otockarticku(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.

program pexeso1;
{$APPTYPE CONSOLE}
uses
SysUtils;
const
n=6;
maxhracu=4;
type
karticka = record
obrazek:byte;
viditelna:boolean;
odebrana:boolean;
end;
hrac = record
jmeno:string;
skore:byte;
end;
hraci=array[1..maxhracu]of hrac;
pexeso=array[1..n,1..n]of karticka;
var p:pexeso;
ph:hraci;
radek, sloupec : byte;
radek1, sloupec1, radek2, sloupec2 : byte;


procedure inicializacepexesa;
var radek, sloupec : byte;
    pocet : byte;
begin
    pocet := 1;

    for radek := 1 to n do
    begin
        for sloupec := 1 to n do
        begin
            pocet := pocet + 1;
            p[radek, sloupec].obrazek := pocet div 2;
            p[radek, sloupec].viditelna := false;
            p[radek, sloupec].odebrana := false;
        end;
    end;
end;

procedure zamichanipexesa;
var radek, sloupec : byte;
    r, s : byte;
    pom : byte;
begin
	for radek := 1 to n do
    begin
        for sloupec := 1 to n do
        begin
        		r := random(n) + 1;
        		s := random(n) + 1;
        		pom := p[radek, sloupec].obrazek;
        		p[radek, sloupec].obrazek := p[r, s].obrazek;
        		p[r, s].obrazek := pom;
        end;
    end;
end;

procedure zobrazenipexesa;
var radek, sloupec : byte;
begin
    for radek := 1 to n do
    begin
        for sloupec := 1 to n do
        begin
            IF p[radek, sloupec].odebrana THEN
                write('X ')
            ELSE
                IF p[radek, sloupec].viditelna THEN
                    write(p[radek, sloupec].obrazek,' ')
                ELSE
                    write('0 ');
        end;
        writeln;
    end;
    writeln;
end;

procedure otockarticku(var radek, sloupec :byte);
begin
    p[radek, sloupec].viditelna := true;
end;




begin
{ TODO -oUser -cConsole Main : Insert code here }

inicializacepexesa;
zamichanipexesa;

for radek := 1 to n do
begin
  for sloupec := 1 to n do
  begin
      write(p[radek, sloupec].obrazek,' ');
  end;
      writeln;
end;
writeln;
zobrazenipexesa;

writeln('Zadejte souradnice 1. karticky (radek): ');
readln(radek1);
writeln('Zadejte souradnice 1. karticky (sloupec): ');
readln(sloupec1);

writeln('Zadejte souradnice 2. karticky (radek): ');
readln(radek2);
writeln('Zadejte souradnice 2. karticky (sloupec): ');
readln(sloupec2);

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

zobrazenipexesa;

readln;
end.

Individual Task

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áš