Obsah lekce:
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.
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.
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.
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.
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.)
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ě:
pom := a; a := b; b := pom;
Tento postup nyní implementujeme do naší procedury (tučně jsou zobrazeny doplněné řádky):
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.
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).
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;)
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.
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.
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ě:
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.
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.
... 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; ...
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.
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.