Content of the lesson:
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:
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:
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 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 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 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:
pom := a; a := b; b := pom;
We can implement this inside our procedure (added lines are drawn in bold).
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:
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).
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 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 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 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:
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.
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.
... 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; ...
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.
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.