Síťový mariáš - Programátorská dokumentace

Specifikace

Aplikace umožňující společnou hru mariáše třem hráčům. Hraje se podle pravidel voleného mariáše

Hlavní součásti aplikace

Aplikace se skládá ze dvou hlavních částí - klienta a serveru

Server

Třídy

Moduly

Logická hierarchie serveru

Síťová komunikace

Síťová komunikace je zapouzdřena třídou MessageDispatcher. Tato třída zpřístupňuje tradiční C-API BSD socketů prostřednictvím rozhraní objektů. V konstruktoru je vytvořen socket (pomocí volání socket()), socket je pojmenován (bind()) a poté je vytvořena fronta požadavků pomocí listen(). Výchozím portem, na kterém server vyřizuje požadavky, je port 2902, toto lze změnit volbou -p <číslo portu> při spuštění serveru. Třída MessageDispatcher pracuje se sockety v blokovacím režimu. Odpovědi od klientů jsou ukládány do fronty; pokaždé při požadavku na odpověď od klienta (metoda readCmd()) jsou, pokud je fronta prázdná, přečtena všechna data od klientů (pomocí select() vybere sockety, na kterých jsou data k přijetí). Pokud se objeví požadavek na nové spojení s klientem, a dosud nejsou připojeni více než 2 klienti, je požadavek přijat, a nový socket (vytvořený pomocí connect()) je zařazen do pole aktivních (hráčských) socketů.

Při odesílání zprávy klientovi (metoda sendCmd()) je klient identifikován svým pořadím v poli socketů (čísla 0..2).

Udržování informací o sezení

Informace o aktuálním sezení jsou udržovány pomocí instance třídy Session. Ta se stará zároveň řízení spouštění hry, a přechod mezi jednotlivými faázemi hry. Třída Session v prvé řadě uchovává informace o připojených hráčích a o jejich skóre v kontejneru players, který obsahuje strukturu Player. Dále obsluhuje některé požadavky od klientů, především informační a servisní příkazy (pro seznam příkazů viz dodatek A). Metoda sendCmd (v několika přetížených variantách) složí k odeslání zprávy klientovi. Klienti jsou identifikováni svým pořadím v seznamu hráčů (toto pořadí je stejné, jako pořadí aktivních socketů v MessageDispatcher).

Průběh sezení je následující:

Sezení zpracovává zprávy od klientů pomocí několika (privátních) metod - handleServCmd, handleInfoCmd. Tyto metody slouží k provedení patřičné akce při přijetí zprávy příslušného typu (serv, respektive info). Ke zpracování zpráv dochází na základě volání z jiných metod, především z potomků třídy Game při vlastní hře. Při hře je typicky očekávána zpráva typu game, a to od určitého klienta (hráče); proto zpracování příkazu (readCmd()) čeká, dokud nedostane zprávu typu game od zadaného klienta - neherní zprávy jsou zpracovány, herní zprávy od ostatních klientů jsou zahazovány.

Sezení rovněž obsahuje objekt třídy MessageDispatcher (viz popis výše), pomocí kterého je realizována vlastní síťová komunikace.

Hra

Vlastní hra je implementována hierarchií tříd, s abstaktní třídou Game na jejím vrcholu. Od této třídy jsou pak odvozeny třídy pro jednotlivé typy mariášové hry (normální hra, betl a durch).

Třída Game poskytuje kromě abstraktního rozhraní, jehož implementace pak závisí na hrané hře, také metody používané v hrách všech typů. Jsou to metody pro rozdávání karet (distCards, sendCards), a metoda pro sehrání štychu. Abstraktní rozhraní třídy Game pak obsahuje metody pro řízení průběhu jednotlivých částí hry, tj. výběr hry (contract()), flekování (flek()), sehrávku (play()) a výpočet skóre hry (scoring()). Tyto metody jsou pak volány z metody runGame() třídy Session.

Při výběru hry se nejprve začíná s normální hrou (GameBasic). Pokud některý z hráčů požádá o vyšší hru, vrací metoda contract() číslo tohoto hráče (jinak vrací -1), a poté je v metodě Session::runGame() naalokován nový objekt třídy GameBetl, do kterého se okopírují důležité informace z původní hry (karty, předák...); původní hra je pak destruována. Podobně následuje výběr hry pro betla a durcha.

Vlastní hra funguje na podobném principu u všech typů her. Využívá se abstraktní třídy Trick (= štych), která obsahuje virtuální metodu pro přidávání karet do štychu. Proto je samotná fáze sehrání štychu implementována už ve třídě Game (metodou playTrick()), ostatní odvozené metody play() pouze obalují tuto metodu o rozhodování. zda hrát ještě dál.

Výpočet skóre je specifický především u normální hry. Pro základní hry se totiž může hrát ještě stovka (co se hraje určuje proměnná gType_), a některý z hráčů může nahlásit sedmu (proměnná hracSedmy). Všechny tyto možnosti jsou při výpočtu zohledněny. Pro betla a durcha se pouze základní hodnota hry (určená konstantami GAME_BETL_VALUE a GAME_DURCH_VALUE) násobí stupněm flekování (proměnná flekStep). U normální hry je cena hry určena konstantami GAME_BASE_VALUE, GAME_BASE_7_VALUE a GAME_BASE_100_VALUE.

Interakce s klienty v průběhu hry probíhá takto: Pokaždé, když server očekává nějakou odpověď od hráče, který je zrovna na tahu, zavolá metodu Session::readCmd(unsigned int) prostřednictvím ukazatele na "rodičovský" objekt třídy Session. Tato metoda (viz popis výše) zpracovává příkazy od klientů, a dál "propustí" pouze zprávy typu game od zadaného hráče.

Zpracování štychu je starostí potomků třídy Trick, tříd BasicTrick a BetlTrick (pro normální hru, respektive betla/durcha). Tyto třídy implementují každá po svém přidávání karet do štychu, určování vítěze štychu a testování, zda lze vůbec (vzhledem k atuálnímu stavu hráčova balíčku) kartu do štychu odhodit. Pro rozhodování jsou uplatňována klasická mariášová kritéria - hráč musí hrát výš, ctít barvu, trumfy,...

Karty

Pro uchování informací o kartách se používají dvě základní třídy: Card a CardPack. Třída Card je vlastně obyčejnou strukturou obsahující hodnoty výčtových typů Card::colorType a Card::sizeType pro uložení informace o kartě. Navíc obsahuje konverzní konstruktor z typu std::string a několik statických metod pro převod řetězce na barvu karty a její výšku, a naopak.

Třída CardPack pak "zapouzdřuje" objekt třídy std::vector<Card>, přičemž chování metody addCard(Card) jej spíše přibližuje množině karet.


Jednoduchý klient

Jednoduchý klient obsahuje pouze grafickou příkazovou řádku pro komunikaci se serverem. Využívá grafickou knihovnu GTK+ prostřednictvím jejího C++ rozraní, knihovny GTK--.

Třídy