Anglická verze
logolink

< Zpět na seznam lekcí

Hra pexeso III

AlgortimyObsah lekce:

  • Zamíchání kartiček
  • Zobrazení pexesa v prohlížeči
  • Skrytí neotočených kartiček
  • Otočení kartičky

Zamíchání kartiček

Na konci minulé lekce jsme měli za úkol vyřešit zamíchání kartiček. Nyní si shrneme realizaci tohoto úkolu.

Do pole pexesa máme načtené hodnoty obrázků. Ty jsou však seřazeny v pořadí, v jakém jsme pole plnili hodnotami (záleží na variantě, kterou jsme si vybrali v předchozí lekci). Tento stav ovšem není ideální jako počáteční stav hry pexeso. Potřebujeme, aby kartičky byly seřazeny náhodně.

Pro náhodné seřazení kartiček budeme potřebovat funkci, která nám vygeneruje náhodné číslo. V Pascalu pro tento účel souží funkce random, která má následující syntaxi.

Syntaxe funkce pro vygenerování náhodného čísla
random(max);

Výše uvedená funkce vygeneruje náhodné číslo v intervalu od 0 do max-1 včetně. Funkci můžeme jednoduše vyzkoušet například vypsáním její hodnoty.

Funkce pro vygenerování náhodného čísla
writeln(random(10));

Nyní je třeba generování náhodného čísla aplikovat na naše pole s pexesem. Budeme postupovat tak, že opět pomocí dvou vnořených cyklů projdeme celé pole pexesa a pro každou kartičku vygenerujeme novou pozici (dvě náhodné čísla udávající nový řádek a nový sloupec). Poté prohodíme hodnotu obrázku na aktuální pozici s hodnotou obrázku na pozici nové.

Celý postup, který jsme si nyní popsali si uložíme do procedury, kterou pojmenujeme zamichanipexesa.

Nyní k samotnému postupu. Nejprve si vytvoříme proceduru pro zamíchání pexesa s lokálními proměnnými radek, sloupec a r, s. První dvojice těchto proměnných nám bude sloužit pro vytvoření cyklu pro průchod pole s pexesem. Ta druhá bude sloužit pro vygenerování dvojice čísel, která nám bude udávat novou pozici kartičky.

Procedura pro zamíchání pexesa - 1. část
procedure zamichanipexesa;
var radek, sloupec : byte;
    r, s : byte;
begin
    
end;

Následně naši proceduru doplníme o již zmiňovaný cyklus, který nám projde postupně všechny kartičky pexesa. Jedná se o podobný cyklus, se kterým jsme se setkali u inicializace pexesa a u zobrazení hodnoty obrázku.

Procedura pro zamíchání pexesa - 2. část
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;

Do cyklu, který máme vytvořen, nyní doplníme 2 řádky, které nám umožní vygenerovat dvojici náhodných čísel od 1 do n. Ta nám bude sloužit pro určení nové pozice kartičky.

Protože nám funkce pro generování náhodného čísla vygeneruje číslo z intervalu od 0 do n-1, přičteme k výsledku tété funkce hodnotu 1. Pro ověření funkce našeho programu si vygenerovanou dvojici hodnot zatím pouze vypíšeme. (pozn. aby nám tato procedura fungovala, musíme její volání doplnit do hlavní části našeho programu, za volání inicializace pexesa.)

Procedura pro zamíchání pexesa - 3. část
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;

Nyní již zbývá jen prohodit aktuální obrázek s obrázkem na pozici, která byla vygenerována pomocí funkce random. Jakým způsobem zaměnit dvě hodnoty?

Pro záměnu dvou hodnot budeme potřebovat pomocnou proměnnou. Například záměna čísel a a b by vypadala následovně:

Záměna dvou hodnot
pom := a;
a := b;
b := pom;

Tento postup nyní implementujeme do naší procedury (tučně jsou zobrazeny doplněné řádky):

Výsledná procedura pro zamíchání pexesa
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;

Nyní se již kartičky pexesa zobrazí v náhodném uspořádání. Výstup programu může vypadat podobně jako na níže uvedeném obrázku.

Pexeso - zamíchané kartičky pexesa

Skrytí neotočených kartiček

Nyí již máme kartičky pexesa zamíchány a zobrazeny. Abychom si správně zobrazovali průběh hry, je třeba změnit způsob zobrazování kartiček pexesa dle toho, zda jsou otočené a zda jsou odebrané.

Nejprve ošetřeme stavy, zda je kartička otočená nebo ne. V případě, že je kartička otočená, je třeba zobrazit hodnotu obrazek, v opačném případě hodnotu 0.

Vytvoříme si novou proceduru pro zobrazení pexesa. Tato procedura bude obsahovat stejnou konstrukci kódu, jako zobrazení pexesa v hlavní části programu. Poté si ji upravíme, tak aby zobrazovala atuální situaci hry (původní kód zobrazení čísla obrázku však v hlavní části programu ponecháme, alespoň po dobu vývoje a testování našeho programu).

Úkol:

Vytvořte proceduru zobrazenipexesa, která zobrazí hodnotu obrazek z našeho pole a volání této procedury umístěte před konec programu (před řádek readln;)

Procedura pro zobrazení pexesa 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;

Nyní máme proceduru pro zobrazení pexesa, která vznikla osamostatněním zobrazení pexesa z hlavní části našeho programu. Dále tuto proceduru rozšíříme o podmínku, která bude zjišťovat zda je kartička viditelná nebo ne.

Procedura pro zobrazení pexesa 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;

Nyní nám v programu přibyla podmínka IF ... THEN ... ELSE, která porovnává hodnotu viditelna (IF p[radek, sloupec].viditelna THEN). V zápisu není nutné uvádět přímo IF p[radek, sloupec].viditelna = true THEN, protože hodnota viditelna vrací hodnotu true nebo false přímo - není tedy nutné doplňovat porovnání.

V případě, že viditelna obsahuje hodnotu true, vypíše se hodnota obrazek, jinak se vypíše hodnota 0.

Dále si program rozšíříme o nezobrazování odebraných kartiček. V případě, že byla kartička odebrána, zobrazí se znak X, jinak se provede podmínka, kterou jsme si definovali v předchozím kroku.

Procedura pro zobrazení pexesa 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].odebrana THEN

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

Výsledný výpis této procedury bude vypadat následovně:

Pexeso - skrytí kartiček pexesa

Otočení kartičky

Nyní již máme definované zobrazení pexesa tak, aby se správně zobrazily kartičky dle toho, zda jsou otočené nebo odebrané. Dále si vytvoříme proceduru, která bude vyžadovat vstup od uživatele, tj. otočení kartičky.

Narozdíl od předchozích procedur bude tato procedura mít vstupní paramatry. Vstupními parametry budou souřadnice kartičky (řádek a sloupec), která má být otočena.

Otočení kartičky
procedure otockarticku(var radek,sloupec:byte);
begin
    p[radek, sloupec].viditelna := true;
end;

Procedura pro otočení kartičky zatím vypadá celkem jednoduše. Pouze načteme dva parametry, které udávají číslo řádku a sloupce a následně odpovídající kartičce pexesa nastavíme hodnotu viditelna na true.

Abychom mohli tuto proceduru vyzkoušet, otočíme si dvě kartičky a znovu si zobrazíme naše pexeso. Pro provedení níže uvedeného kódu budeme potřebovat vytvořit 4 globální proměnné typu byte: radek1, sloupec1, radek2 a sloupec2.

Otočení dvojice kartiček a zobrazení pexesa
...

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;

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

Pro úplnost je vhodné ještě uvést kompletní kód, ke kterému jsme se dostali na konci dnešní lekce.

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.

Domácí úkol

Jakým způsobem je nutné ošetřit proceduru pro otočení kartičky, aby nedocházelo k chybovým stavům (podmínkou je otočit vždy dvě různé kartičky z našeho pexesa)?. Navrhněte úpravu této procedury.

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