Nacházíte se zde: Radek Klein » Blog »

Karetní hra Prší v Pascalu

Karetní hra Prší v Pascalu

Známá česká karetní hra Prší v textovém provedení, k jejímuž ovládání Vám stačí pouze klávesnice. Jedná se o mou první aplikaci naprogramovanou v jazyce Pascal, třeba Vám tak poslouží při poznávání tohoto programovacího jazyka. Odkaz ke stažení hry a zdrojového kódu naleznete na konci článku.

Pravidla hry

Každému hráči jsou vylosovány čtyři karty a jedna karta doprostřed stolu. Zbytek balíku tvoří talón, ze kterého hráči dobírají karty. Hráč, který je na tahu, smí odhodit buď kartu vyložené barvy nebo kartu stejné číselné hodnoty. Nemůže-li nebo nechce-li hráč odhodit kartu, musí vzít kartu z talónu. Filka lze odhodit na kteroukoliv barvu a hráč určí, jakou barvu představuje pro dalšího hráče. Odhodí-li hráč sedmu, následující hráč musí odhodit také sedmu. Pokud nemá, musí si z talónu vzít 2 karty násobené počtem sedmiček odhozených po sobě. Odhodí-li hráč eso, následující hráč stojí, tj. vynechá jeden tah. Vítězem je ten, kdo se jako první zbaví všech karet.

Ovládání

Hra se ovládá přes klávesnici. Na začátku hry si hráč zvolí, kolik dostane každý hráč do začátku karet do ruky. Na vstupu musí být zadáno kladné celé číslo v rozmezí 1 až 8. Program poté rozdá hráči a počítači zvolený počet karet a vypíše karty, které má hráč v ruce, kolik karet má v ruce protihráč a zároveň kartu, která je na vrchu zahraných karet. Poté se zeptá, jakou kartu chce hráč zahrát. Karty jsou ve formátu barva-hodnota např. kule-8 nebo zaludy-spodek. Zahrání karty se provádí napsáním čísla karty a stisknutím ENTERu. V případě, že by se hráč pokusil zahrát kartu, kterou nemá nebo podle pravidel nemůžete zahrát, program ho upozorní, aby nepodváděl a znovu vyzve k zapsání karty.

Program

Následující část pojednává o samotném programu z hlediska programátorského a obsahuje vysvětlení jeho funkčnosti, popisy procedur atd. Hra byla vytvořena ve vývojovém prostředí Bloodshed Dev-Pascal 1.9.2, kde byl jako kompilátor nastaven Freepascal.

Reprezentace dat

Z celého programu je asi nejobtížnější částí vymyslet, jak budou jednotlivé karty, balíčky i karty v rukách obou hráčů reprezentovány. Nakonec jsem se rozhodl pro typ záznam, který jsem v pascalu nadefinoval následujícím způsobem:

type Tkarta = record
               barva:array[1..32] of string;
               hodnota:array[1..32] of string;
               obsahuje:array[1..32] of boolean;
              end;

Všechny položky záznamu jsou typu pole o 32 prvcích, což odpovídá počtu karet. Pro představu se v podstatě jedná o tabulku o 32 řádkách a sloupcích ID (jasné identifikační číslo karty), barva, hodnota a obsahuje. Tato „tabulka“ se pak různými způsoby prochází. V poli obsahuje se nachází vždy informace, zda se karta nachází v určené proměnné.

Proměnné tohoto typu jsem nadefinoval celkem čtyři:

  • Hrac – představuje karty, které má v ruce hráč
  • Pc – karty, které má v ruce počítač
  • Balik – talón prozatím nezahraných karet, ze kterých se líže
  • Zahrane – karty, které již byly zahrány

Tyto proměnné pak byly naplněny podobným způsobem během procedury inicializace:

barva[5]:='Cervena';  hodnota[5]:='8';       obsahuje[5]:=FALSE;
barva[6]:='Cervena';  hodnota[6]:='9';       obsahuje[6]:=FALSE;
barva[7]:='Cervena';  hodnota[7]:='10';      obsahuje[7]:=FALSE;
barva[8]:='Cervena';  hodnota[8]:='Spodek';  obsahuje[8]:=FALSE;

Program si nikde nepamatuje, v jakém jsou karty pořadí. Místo toho se vždy ze zbývajících karet vybírá jedna náhodná, což není nejefektivnější způsob, ale vzhledem k výkonu dnešních PC a tomu, že se jedná jen o 32 karet, považuji ztráty za zanedbatelné. Ukládá se ovšem poslední zahraná karta, a to do dvou proměnných typu záznam. V proměnné PosledniKarta je karta, s kterou se právě manipuluje, AktivniKarta je už karta zahraná a nehybná.

PosledniKarta: record         {karta, s kterou se pracuje - prave se hraje}
               barva:string;
               hodnota:string;
              end;
AktivniKarta: record          {karta, ktera je jiz zahrana na vrchu baliku}
               barva:string;
               hodnota:string;
              end;

Zvolená reprezentace dat však nebyla příliš vhodná a špatně se s ní v programu dále pracovalo, lepším řešením by bývalo karty reprezentovat jen čísly 0..31 kde

  • K div 8 je barva
  • K mod 8 je hodnota
  • V poli [0..3] by byly uloženy názvy barev
  • V poli [0..7] by byly uloženy názvy hodnot
  • Karty hráčů i talonů by šly reprezentovat polem [1..maxpocet] of 0..31

Vývojový diagram

Následující vývojový diagram znázorňuje průběh programu, pro zjednodušení se v něm nenacházejí ověřovací podmínky a kontroly zahrání speciálních karet.

Popis hlavního programu

Na počátku zavoláme proceduru inicializace, která slouží zejména k načtení proměnných a zobrazení ovládání a pravidel. Zjistíme počet karet, které budou do začátku rozdány každému hráči, rozdáme je a smažeme obrazovku. Následuje vyložení první karty, její vypsání a zjištění, zda se nejedná o eso nebo sedmičku. Následující část se opakuje až do doby než má některý z hráčů na ruce 0 karet.

Voláním procedury vypsatkarty se vypíšou na obrazovku informace o kartách v ruce hráče, poslední zahrané kartě atd. Pokud bylo v tahu protihráče zahráno eso, nabývá proměnná ZahranoEsoPC hodnoty TRUE, vypíše se, že hráč stojí a na tahu je opět protihráč. Pokud eso nebylo zahráno, zeptá se program hráče, jakou chce zahrát kartu. Pokud hráč vloží nulu, žádná karta se nezahraje a místo toho si lízne počet karet určených proměnnou PocetLiznuti. V případě jiného čísla program zavolá proceduru ZahratKartu která zkontroluje, zda je možno kartu zahrát a pokud ano, tak ji přesune z hráčovy ruky na balík zahraných karet. Pokud vše proběhlo v pořádku, následuje protihráčův tah. Nakonec se ještě zjistí, zda některý z hráčů nemá na ruce žádné karty a pokud tato situace nastane, program vypíše vítěze a hra skončí, jinak se celý děj opakuje.

Popis jednotlivých procedur

Inicializace

Na počátku se vymaže obrazovka a inicializuje se generátor náhodných čísel, který bude zapotřebí pro pozdější lízání karet. Do proměnné Hrac se dosadí jednotlivé karty. Karty jsou v pořadí, ve kterém budou i později prohledávány a v případě tahu počítače zahrány. Proto jsou na prvních čtyřech místech esa, aby se jich počítač snažil zbavit jako prvních a až na úplném konci filkové pro změnu barvy v případech, kdy není žádná jiná vhodná karta nalezena. Bližší popis je možné nalézt v části Reprezentace dat. Stejné hodnoty jsou pak vloženy do proměnných pc, balik a zahrane jen s tím rozdílem, že na počátku jsou všechny karty v balíku (talónu) a tedy pro všechny i Balik.Obsahuje[i] hodnotu true. Poslední částí je vypsání pravidel v případě kladné odpovědi hráče.

ZamichatBalik

Procedura slouží k zamíchání zahraných karet do balíku v případě, že z něj byly odebrány všechny karty. Nejprve se zjistí, zda je v něm ještě nějaká karta. Pokud ano, tak se nic nestane. V opačném případě zamíchá zahrané karty do nového balíku, z kterého se opět mohou lízat karty. Zamíchání se provede tím, že se prochází cyklem mezi všemi kartami a u všech karet obsažených v zahraných kartach se nastaví proměnná zahrane.obsahuje[k] na hodnotu FALSE a balik.obsahuje[k] na hodnotu TRUE. K je index právě procházené karty (hodnota řídící proměnné).

LiznoutKartu(kdo)

Procedura slouží k tomu, aby si podle parametru procedury hráč (pro kdo=‘hrac‘) nebo počítač (kdo=‘pc‘) líznuli kartu z balíku. Líznutí proběhne tím způsobem, že se vybere náhodná karta z balíku a ta se z balíku přesune do hráčovy/počítačovo ruky. Tato akce je realizována opakovaným generováním náhodného čísla a zjišťováním, zda se karta s tímto indexem nachází v balíku. Děj se opakuje do doby než se takováto karta najde. Jakmile se najde, tak je přesunuta do ruky hráče/počítače (např. pro hráče vypadá kód: hrac.obsahuje[j]:=TRUE; balik.obsahuje[j]:=FALSE) a přes logickou proměnnou VPoradku je cyklus ukončen. Protože by v případě, že by už nebyla v balíku žádná karta, probíhalo hledání karty do nekonečna, je ještě před prohledáváním zavolána procedura ZamichatBalik. Pokud kdo=‘hrac‘, je ještě vypsána líznutá karta.

Důležitou proměnnou je PocetLiznuti udávající, kolik karet si má hráč líznout. Standardně je v ní hodnota 1, ale může se zvýšit po zahrání sedmiček. Pakliže je v ní hodnota větší než jedna, zmenší se její hodnota o jedničku a procedura zavolá sebe samu. To se provádí až do doby, než je její hodnota rovna jedné, tím pádem si hráč lízne odpovídající počet karet.

VypsatKarty

Procedura složí k podání informací o současném stavu hry, tedy vypsání karet na ruce hráče, počtu protihráčových karet a též informace o poslední zahrané kartě. Všechny karty jsou očíslované, líznutí další karty je označeno nulou.

ZahratKartu

Procedura, která slouží k zahrání karty hráče.

Na počátku nastavíme logické proměnné, které hlídají zahrání esa a zda vše proběhlo v pořádku na hodnotu FALSE, poté určíme, která karta odpovídá zadanému číslu. Opět procházíme všech 32 karet a zjišťujeme nejprve, zda se karta, kterou hrajeme (PosledniKarta), rovná kartě v hráčově balíku. Tím vyloučíme nesmyslné zadání a zároveň zjistíme, s jakým indexem karty budeme dále pracovat. Ověříme, zda hráč danou kartu vlastní a poté, zda se dá zahrat na současnou kartu.

To je možné jen ve třech případech:

  1. Barvy zahrané (PosledniKarta.Barva) a aktivni karty (AktivniKarta.Barva) jsou totožné
  2. Hodnoty obou karet jsou shodné
  3. Zahraná karta je filek

Pokud je alespoň jedna z těchto podmínek splněna, cyklus pokračuje a ověří se, zda se nepokoušíme zahrát jinou kartu než sedmičku, pokud byla zahrána v minulém kole sedmička (PocetLiznuti>1). Pokud je vše v pořádku, nastaví se proměnná VPoradku do hodnoty TRUE, karta z ruky je zahrána do balílu a stane se aktivní kartou.

Dále je zapotřebí ošetřit speciální karty. Pokud byla poslední zahraná karta sedmička, zvýší se hodnota proměnné PocetLiznuti, v případě zahraného esa se nastaví proměnná ZahranoEso na TRUE a počítač bude v příštím kole stát. Pokud byl zahrán filek, vypíšou se možnosti, na jakou je možno změnit barvu, a proměnná aktivnikarta.barva se podle výběru hráče změní.

Pokud neproběhlo něco v pořádku a proměnná VPoradku zůstala na hodnotě FALSE, program napomene hráče, aby nepodváděl, neboť chtěl zahrát kartu, kterou nevlastní nebo podle pravidel nemůže zahrát.

ProtihracuvTah

Nejprve se nastaví pomocné logické proměnné na hodnotu FALSE, hodnot TRUE se dosáhne až při splnění určitých podmínek.

Pakliže bylo v minulém tahu zahráno eso (ZahranoEso=TRUE), počítač jen oznámí, že stojí a ukončí svůj tah. Pokud byla v minulém tahu zahrána sedmička, budou se hledat karty jen mezi sedmičkami, v obráceném případě mezi všemi kartami kromě filků. Poté probíhá hledání a zahrání karty obdobně jako v proceduře ZahratKartu. Pakliže žádná z karet nevyhovuje, zjistí se, zda má počítač filka a pokud ano, tak ho zahraje. Barvu změní podle počtu zbývajících karet na ruce. V případě, že nemůže zahrát žádnou kartu, lízne si odpovídající počet karet z talónu.

Přílohy

  1. Prsi.zip (16.7 KiB)
    Zkompilovaný exe soubor se hrou

  2. Source.zip (4.7 KiB)
    Zabalený soubor se zdrojovým kódem

  3. Dokumentace.pdf (825.8 KiB)
    Dokumentace k zápočtovému programu

Diskuze

Buďte první, kdo napíše komentář