rocnikovy_projekt_ny..
Transkript
rocnikovy_projekt_ny..
Gymnázium Praha 6, Arabská 16 Šachy Dokumentace Ročnı́kového Projektu Autor Třı́da Ondřej Nývlt 1. E Vyučujı́cı́ Tomáš Obdržálek Předmět Programovánı́ 18. května 2014 Obsah 1 Úvod 1.1 Anotace . . . . . . . . . . . . . 1.2 Prohlášenı́ . . . . . . . . . . . . 1.3 Poznámky . . . . . . . . . . . . 1.4 Zadánı́ . . . . . . . . . . . . . . 1.4.1 Základnı́ funkcionalita . 1.4.2 Bonusová funkcionalita . . . . . . 1 1 1 1 1 1 2 2 Hra 2.1 Historie hry . . . . . . . . . . . . . . . 2.2 Princip hry . . . . . . . . . . . . . . . 2 2 2 3 Aplikace 3.1 Použité technologie . . . 3.2 Ovládánı́ . . . . . . . . . 3.3 Návrh . . . . . . . . . . 3.4 Struktura projektu . . . 3.4.1 View . . . . . . . 3.4.2 Model . . . . . . 3.4.3 ViewModel . . . 3.5 Aplikačnı́ logika . . . . . 3.5.1 Kliknutı́ na pole 3.5.2 Zı́skánı́ tahů . . 3.5.3 Provedenı́ tahu . 3 3 3 4 5 5 6 6 7 7 8 9 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . phical user interface. App is designed for PCs and is capable of handling two-player game – player vs. computer game mode is not available. 1.2 Prohlašuji, že jsem jediným autorem tohoto projektu, všechny citace jsou řádně označené a všechna použitá literatura a dalšı́ zdroje jsou v práci uvedené. Tı́mto dle zákona 121/2000 Sb. (tzv. Autorský zákon) ve zněnı́ pozdějšı́ch předpisů uděluji bezúplatně škole Gymnázium, Praha 6, Arabská 14 oprávněnı́ k výkonu práva na rozmnožovánı́ dı́la (§ 13) a práva na sdělovánı́ dı́la veřejnosti (§ 18) Datum 1.3 4 Závěr 9 4.1 Vývoj návrhu, problémy . . . . . . . . 9 4.2 Splněnı́ zadánı́ . . . . . . . . . . . . . 10 1 1.1 Prohlášenı́ Mı́sto Autor Poznámky V tomto dokumentu docházı́ ke vzniku mnohoznačných pojmů. Aby nevznikala nedorozumněnı́, uvádı́m následujı́cı́ pokyny: Pojem pole v tomto dokumentu označuje oblast průniku řádku a sloupce na mřı́ži šachovnice nebo objekt typu Square či jeho grafickou interpretaci v uživatelském rozhranı́. Ve významu datové struktury array nenı́ použit. Úvod Anotace Pojmy aktivnı́ pole, vybrané pole, povolený tah, zakázaný tah atd. existujı́ pouze v rámci aplikace a nevyskytujı́ se ve hře šachy. Cı́lem projektu bylo vytvořit implementaci klasické strategické deskové hry šachy, kde dva hráči proti sobě soupeřı́ posouvánı́m figurek po šachovnici. Aplikace je postavena na .NET frameworku s využitı́m programovacı́ho jazyka C# a technologie WPF pro grafické uživatelské rozhranı́. Aplikace je navržena pro PC a umožňuje hru dvou hráčů – nedisponuje možnostı́ hry hráč proti počı́tači. 1.4 1.4.1 Zadánı́ Základnı́ funkcionalita • Aplikace s grafickým uživatelským rozhranı́m (GUI) Abstract The objective of the project was to create full-featured implementation of classic strategy board game chess where two player fight with each other by moving pieces around the chessboard. Application is built on .NET framework using C# programming language and WPF technology for gra- • Implementace hry šachy“ ” • Umožňuje hru dvou hráčů • Zprostředkuje pohyb figurek po šachovnici 1 • Rozpozná libovolnou možnost konce hry (šach, mat, pat) 1.4.2 Bonusová funkcionalita • Započı́tává body a zaznamenává průběh hry • Zobrazı́ statistiky na konci hry • Umožnı́ uloženı́ výsledků hry do textového souboru • Speciálnı́ tahy (rošáda, tah mimochodem) 2 Hra Obrázek 1: Výchozı́ rozloženı́ figurek na šachovnici. Šachy jsou klasická desková hra pro dva hráče. V soutěžnı́ podobě je považována za odvětvı́ sportu. Hráči spolu soupeřı́ prostřednictvı́m figurek posouvaných po šachovnici. Cı́lem je dostat protihráčovu figurku krále do situace, kdy je ohrožen a nelze toto ohroženı́ kterýmkoliv způsobem odvrátit. 2.1 Figurky Každý hráč má na začátku hry k dispozici sadu 16 figurek šesti různých typů, rozmı́stěných ve výchozı́m postavenı́. Figurky rozdı́lných hráčů se lišı́ barvou; světlé figurky náležı́ bı́lému hráči (zkráceně bı́lý) a tmavé černému hráči (černý). Každý typ figurky má zvláštnı́ možnosti pohybu po šachovnici (počet figurek na jednoho hráče v závorce). Historie hry Původ Jako mı́sto vzniku se kvůli jazykovým souvislostem nejčastěji označuje Indie. Prvnı́ zmı́nka o předchůdci hry se objevila v Persii kolem roku 600 n. l., kde je nyzývána jako Šatrandž. V 9. stoletı́ se dostala do Čı́ny a poté se začala postupně šı́řit i v Evropě. Kolem roku 1000 jsou v Evropě šachy všeobecně známou hrou. • Pěšec (8): Pohyb o jedno pole vpřed, je-li volné; v prvnı́m tahu konkrétnı́ho pěšce je možné ho posunout o dvě pole vpřed. Brát může pohybem o jedno pole vpřed a jedno stranou. • Věž (2): Přı́mý pohyb po řadách a sloupcı́ch o libovolný počet polı́. • Jezdec – též Kůň (2): Pohyb o dvě pole rovně a jedno stranou (ve tvaru pı́smene L“). ” • Střelec (2): Pohyb po diagonálách o libovolný počet polı́. Střelec se pohybuje vždy na polı́ch stejné barvy. Modernı́ hra Ve 13. stoletı́ se začala pravidla rozšiřovat a ustálila se kolem 15. stoletı́. Oproti relativně omezenému Šatrandži se lišı́ mimo jiné rozšı́řenými tahy – zejména u královny, která měla původně velmi omezené možnosti pohybu. Finálnı́ podobu hra zı́skala v 19. stoletı́. 2.2 • Dáma – též Královna (1): Kombinuje možnosti pohybu střelce a věže. Princip hry • Král (1): Pohyb o jedno pole libovolným směrem. Šachovnice Hra probı́há na šachovnici. Šachovnice je čtvercová deska s mřı́žı́ o velikosti 8 sloupců (značeny pı́smeny a až h) a 8 řad (značených čı́sly 1 až 8). Buňka v mřı́ži se nazývá pole. Pole majı́ střı́davě tmavou (černá pole) a světlou barvu (bı́lá pole). Na každém poli může stát maximálně jedna figurka. Tahy Figurky jsou na šachovnici přesouvány prostřednictvı́m tahů. Hráči se v tazı́ch pravidelně střı́dajı́; bı́lý zahajuje hru prvnı́m tahem. Tah se sestává z přesunutı́ figurky táhnoucı́ho hráče podle pravidel pohybu přemist’ované figurky. Po2 3 kud přemist’ované figurce stojı́ v cestě“ jiná fi” gurka, nelze ji přeskočit (výjimku tvořı́ jezdec). Figurku nelze přemı́stit na pole, kde se nacházı́ jiná figurka stejné barvy. Pokud se na cı́lovém poli nacházı́ figurka rozdı́lné barvy, je odebrána ze šachovnice a dále se hry nezúčastňuje; takový tah se nazývá branı́. Existujı́ tahy, pro které platı́ speciálnı́ pravidla: 3.1 Aplikace Použité technologie .NET Framework mou Microsoft. C# • Tah mimochodem (en passant): Pěšcem je možné sebrat pěšce protihráče, který se posunul o dvě pole, jako by se posunul pouze o jedno. Lze vykonat pouze v tahu bezprostředně následujı́cı́m po dvojitém tahu sebraného pěšce. Běhové rozhranı́ vyvı́jené fir- Programovacı́ jazyk Windows Presentation Foundation (WPF) Technologie pro tvorbu GUI, která využı́vá značkovacı́ jazyk XAML (Extensible application markup language). • Rošáda Posunutı́ krále o dvě pole směrem k věži a přesunutı́ věže na pole přeskočené králem. Rošáda je jediný tah, kdy se pohybujı́ dvě figurky současně, ale je považována jako tah krále. Aby bylo možné rošádu vykonat, musı́ být splněny podmı́nky: Mezi králem a věžı́ se nenacházı́ žádná figurka; králem ani věžı́ nebylo taženo; král nesmı́ být v šachu a nesmı́ přejı́t přes pole, které je ohrožené soupeřovou figurkou. Microsoft Visual Studio 2013 Express for Desktop Vývojové prostředı́, které umožňuje vyvı́jet aplikace pro Windows na klasickou plochu (tj. nikoliv modernı́ aplikace Windows 8 a vyššı́). 3.2 Ovládánı́ Instalace Hráč zı́ská složku, ve které se nacházı́ spustitelný soubor setup.exe. Když jej uživatel spustı́, aplikace se nainstaluje a poté ji může najı́t v nabı́dce start. Aplikace lze nainstalovat pouze na operačnı́ systém Windows. Šach Situace, kdy je král ohrožen figurkou (figurkami) soupeře, se nazývá šach. Kdyby nebyl šach odvrácen hráčem, jehož král je ohrožen, soupeř by mohl krále v následujı́cı́m tahu sebrat – taková situace nesmı́ nastat. Hráč proto musı́ šach odvrátit: Ovládánı́ Po spuštěnı́ aplikace se otevře hlavnı́ okno, které obsahuje tři základnı́ prvky: menu, šachovnici a panel hráčů. • Ustoupı́ s králem na neohrožené pole. Šachovnice umožňuje samotnou hru. Panel hráčů, který se nacházı́ na pravé straně od šachovnice, poskytuje základnı́ informace a statistiky o jednotlivých hráčı́ch (jméno, barva, počet figurek). Nad panelem hráčů je zobrazen počet vykonaných tahů a doba uplynulá od začátku hry. Nad šachovnicı́ se nacházı́ menu. • Postavı́ před krále figurku a ochránı́“ ho. ” • Sebere figurku ohrožujı́cı́ krále. Situace, kdy nelze šach odvrátit žádným tahem, se nazývá mat (resp. šachmat). V takovém přı́padě hra končı́ a hráč, který soupeři způsobil mat, se stává vı́tězem. Šachovnice Šachovnice se ovládá kliknutı́m na zvolené pole. Pokud se na něm nacházı́ figurka aktuálnı́ho hráče, vybrané pole se stává aktivnı́m a je červeně zvýrazněno. Pole, na které je možné vykonat tah, jsou zvýrazněna barevným ohraničenı́m. Speciálnı́ tahy jsou zvýrazněny podobně, lišı́ se Kromě matu může nastat pat. V takové situaci hráč, který je na tahu, nenı́ v šachu, ale nemůže vykonat žádný tah. Hra končı́cı́ patem nemá vı́těze; nastává remı́za. 3 (a) Historie tahů (b) Statistika Obrázek 4: Speciálnı́ okna dostupná přes menu. zobrazuje odlišným způsobem. Tahy jsou vykresleny jako graf závislosti počtu figurek na počtu vykonaných tahů. Graficky tak zobrazuje bilanci počtu figurek obou hráčů v průběhu hry. Obrázek 2: Hlavnı́ okno. Na aktivnı́m poli (červeně) stojı́ bı́lá dáma a šedomodře ohraničené pole značı́ možné tahy. • About Otevře okno About. Toto okno zobrazuje informace o aplikaci. Obrázek 3: Zvýrazněnı́ speciálnı́ho tahu – rošády (fialově ohraničené pole) před a po přejetı́ myšı́. Konec hry Po skončenı́ hry se objevı́ okno Results (Výsledky). Okno oznámı́ vı́těze a prostřednictvı́m tlačı́tek odkáže uživatele do historie tahů či statistik. Zbývajı́cı́ tlačı́tka nabı́zı́ uloženı́ průběhu hry do textového souboru nebo spuštěnı́ nové hry. pouze barvou ohraničenı́. Po přejetı́ myši na takovým polem se zobrazı́ popisek s typem tahu. Kliknutı́m je vykonán přı́slušný tah; figurka je přesunuta na cı́lové pole a veškerá zvýrazněnı́ zmizı́. Klikneli uživatel přı́mo na aktivnı́ pole, zvýrazněnı́ zmizı́ a žádný tah nenı́ vykonán. 3.3 Návrh Aplikace byla navržena podle vzoru Model View ViewModel (MVVM). Schéma je založeno na striktnı́m oddělenı́ grafického uživatelského rozhranı́ (GUI) od logiky aplikace (bussines logic). To umožňuje měnit GUI nezávisle na kódu aplikace a naopak. MVVM dělı́ aplikaci na tři vrstvy: Menu Nad šachovnicı́, tj. v levém hornı́m rohu okna, se nacházı́ menu – horizontálnı́ pás tlačı́tek, které uživateli umožňujı́ vykonat přı́kazy: • New Spustı́ novou hru. • Save Uložı́ průběh hry do textového souboru ve formátu YAML. Po kliknutı́ na toto tlačı́tko se otevře dialog pro uloženı́ souboru. View Reprezentuje uživatelské rozhranı́, které je navrženo ve značkovacı́m jazyce XAML. Určuje vzhled oken, stránek, ovládacı́ch prvků atd. Převádı́ data do vizálnı́ podoby. • History Otevře okno History (historie tahů). Historie tahů zobrazuje veškeré provedené tahy od začátku hry a přı́slušné informace (táhnoucı́ figurka, výchozı́ a cı́lové pole, sebraná figurka, čas, stav hráče, ...); data pro vykreslenı́ zı́skává od objektů HistoryRecord z uspořádané kolekce History ve třı́dě Chessboard. Model Popisuje data, se kterými pracuje aplikace, obvykle ve formě objektů. ViewModel Třı́da, která držı́ stav aplikace. ViewModel poskytuje data pro View, který je převádı́ do vizuálnı́ podoby a zobrazuje je v UI. • Stats Otevře okno Statistics (Statistika). Okno je funkčně podobné oknu History, ale informace 4 • Converters Převodnı́ky hodnot mezi View a ViewModelem – třı́dy implementujı́cı́ IValueConverter. • Model Obsahuje vnořené jmenné prostory: – Moves Tahy – třı́dy implementujı́cı́ IMove. Obrázek 5: Schéma MVVM (zdroj: msdn.microsoft.com) – Pieces Figurky – třı́dy rozšı́řujı́cı́ třı́du Piece. Svázánı́ View a ViewModelu je realizováno pomocı́ bindingu – View je navázán na vlastnosti třı́dy ViewModel. Data mohou být mezi Viewem a ViewModelem synchronizována oběma směry. Změnı́-li uživatel data v UI pomocı́ ovládacı́ch prvků, automaticky se změnı́ i vlastnosti přı́slušné ViewModelu. Opačným směrem: jsou-li změněny vlastnosti ViewModelu, aktualizujı́ se i navázané UI prvky. Aby aktualizace UI fungovala, musı́ ViewModel implementovat INotifyPropertyChanged interface. (V přı́padě kolekce musı́ jı́t o typ ObservableCollection). Dojde-li ke změně hodnoty vlastnosti ViewModel, je vyvolána událost PropertyChanged, která informuje View a ten překreslı́ UI na základě nových dat. • ViewModel Obsahuje hlavnı́ třı́du Chessboard a vlastnı́ typy kolekcı́ • View Návrh UI. Obsahuje XAML soubory – windows (okna) a resource dictionaries (slovnı́ky zdrojů) 3.4.1 Ve jmenném prostoru View se nacházı́ veškerý návrh uživatelského rozhranı́. Protože některé úseky XAML kódu jsou přı́liš dlouhé nebo se opakujı́, je výhodné je umı́stit do tzv. resource dictionary (slovnı́k zdrojů), kde se mohou vyskytovat statické konstantnı́ hodnoty, řetězce, barvy, styly, šablony, uživatelské ovládacı́ prvky atd. (ekvivalent CSS s rozšı́řenými možnostmi) K hodnotám v resource dictionary lze následně přistupovat pomocı́ klı́čů. Resource dictionary se může vyskytovat bud’ lokálně nebo v samostatném souboru, na který je potřeba odkázat. Pro převod dat (např. převod řetězců na čı́sla, matematická operace, ...) mezi View a ViewModelem sloužı́ konvertory, tj. objekty třı́d implementujı́cı́ interface IValueConverter ViewModel vystavuje přı́kazy, tj. objekty třı́d implementujı́cı́ch ICommand interface. Představujı́ akce vykonané při určité události spojené s UI prvkem, který je na něj navázán (např. stisknutı́ tlačı́tka). Mimo jiné podle stavu ViewModelu určujı́, zda je možné akci vykonat, a podle toho změnı́ stav přı́slušného UI prvku (zneaktivněnı́ tlačı́tka). 3.4 Každý XAML soubor v projektu představuje resource dictionary nebo okno (window). Soubor App.xaml se nacházı́ na nejvyššı́ úrovni a obsah resource dictionaries zahrnutých v tomto souboru je dostupný globálně. Struktura projektu Kód hlavnı́ho okna (MainWindow) je kvůli své délce rozdělen do dı́lčı́ch resource dictionaries: ChessboardDictionary.xaml (šachovnice), PlayerPaneDictionary.xaml & .cs (panel hráčů). Obsah slovnı́ku BasicDictionary.xaml je obecný, nevztahujı́cı́ se pouze k hlavnı́mu oknu. Soubory projektu jsou roztřı́děny do logických celků – jmenných prostorů (namespaces). Na nejvyššı́ úrovni je namespace Chess. Jmenné prostory Model, View a ViewModel odpovı́dajı́ vrstvám MVVM schématu. Každá složka v projektu představuje právě jeden jmenný prostor. K některým souborům obsahujı́cı́m XAML kód (nejčastěji okna) je připojen soubor se stejným názvem a přı́ponou .cs, které obsahujı́ C# kód – tzv. code-behind (např. k souboru MainWindow.xaml je připojen code-behind soubor MainWindow.xaml.cs). Zde je možné např. odchytávat události z View apod. Chess Namespace na nejvyššı́ úrovni. • Commands ICommand. View Přı́kazy – třı́dy implementujı́cı́ 5 3.4.2 Move Představuje tah. Seskupuje informace o tahu a metody k jeho ovládánı́. Jedná se o základnı́ implementaci rozhranı́ IMove. Model Model popisuje data, se kterými aplikace pracuje. Vyjmenovány jsou pouze důležité třı́dy, vlastnosti a metody. Všechny třı́dy modelu rozšiřujı́ třı́du ModelBase, která implementuje INotifyPropertyChanged interface. Dı́ky tomu se změny hodnot vlastnostı́ projevı́ v UI. Square • Piece Piece: Figurka, přemist’ována. která • Square StartingSquare, FinalSquare: a cı́lové pole přesunu figurky. je tahem startovnı́ • Piece Captive: Figurka, která je tı́mto tahem sebrána. Obvykle je sebrána figurka nacházejı́cı́ se na cı́lovém poli, výjimku tvořı́ tah mimochodem. Představuje pole na šachovnici. • int X, Y: Sloupec a řádek na šachovnici. • bool IsRestricted: Pravdivé, pokud by takový tah způsobil šach vlastnı́mu hráči. • Piece Piece: Figurka, která se na poli nacházı́. • bool IsActive: Pravdivé, pokud je pole aktivnı́. • string Type: Typ tahu. Poskytuje bližšı́ informace o tahu, např. dvojitý tah pěšce má v této vlastnosti uloženo "Pawn Double Move". Základnı́m typem je "Common". Piece Představuje figurku. Každý typ figurky má vlastnı́ třı́du, která rozšiřuje třı́du Piece. • void Do(Chessboard chessboard): Vykoná tah, tj. přesune figurku Piece na pole FinalSquare, sebere figurku Captive: a vyvolá akci Action. • char Sign: Unicode znak, který představuje šachovou figurku (např. symbol U+2658 N jezdec). • void TryDo(): Vykoná tah zkušebně, tj. je možné ho anulovat vyvolánı́m metody Undo(). • Move Move: Tah, který je možné na pole vykonat. • void Undo(): Anuluje zkušebnı́ tah. • bool HasMoved: Pravdivé, pokud byl s figurkou vykonán alespoň jeden tah. Výchozı́ hodnota je false. Speciálnı́ tahy (tah mimochodem, rošáda) majı́ vlastnı́ implementace IMove. Tahy, které se od základnı́ho tahu přı́liš nelišı́ (povýšenı́ pěšce), využı́vajı́ základnı́ Move a ve vlastnosti Action je uložena přı́davná akce, která je vyvolána při vykonánı́ tahu. • bool ThreatensKing: Pravdivé, pokud ohrožuje krále protihráče. • Player Player: Hráč, jemuž figurka náležı́. • HashSet<IMove> GetMoves(): Zı́ská tahy. HistoryRecord Představuje záznam o vykonaném tahu. V uspořádané kolekci pak objekty této třı́dy tvořı́ historii tahů. • HashSet<IMove> GetEvaluatedMoves(): Zı́ská vyhodnocené tahy. Tahy, jejichž vykonánı́ by způsobilo ohroženı́ vlastnı́ho krále, majı́ vlastnost IsRestricted pravdivou, ostatnı́ nepravdivou (výchozı́ hodnota). • int Order: Pořadı́ záznamu. • IMove Move: Vykonaný tah. • TimeSpan Time: Doba uplynulá od začátku hry do okamžiku vykonánı́ tahu. Player Představuje hráče. • PlayerState State: Stav hráče, který tento tah způsobil protivnı́kovi. • string Name: Jméno hráče • PlayerColor Color: Barva hráče (výčet obsahuje hodnoty Black a White. 3.4.3 • PlayerState State: Stav hráče (šach, šachmat, pat, ...) Chessboard Představuje šachovnici, která je ViewModelem aplikace. V celé aplikaci se nacházı́ 6 ViewModel jediná instance této třı́dy, ze které View čerpá data. vystavena přes přı́kaz SaveFileCommand. • SquareSet Squares: Kolekce polı́ na šachovnici. Typ kolekce SquareSet rozšiřuje třı́du HashSet< Square> o metodu Square Get(int x, int y) pro zı́skánı́ pole z kolekce. 3.5 3.5.1 • HashSet<Piece> Pieces: Kolekce všech figurek (vč. sebraných). Aplikace s touto kolekcı́ téměř nemanipuluje; kolekce zaručuje, že nikdy nenastane situace, kdy by na určitý objekt figurky neexistovala reference a byl by tak vymazán. Aplikačnı́ logika Kliknutı́ na pole Chessboard obsahuje kolekce objektů Square (pole), Piece (figurka), Player (hráč). Každý objekt Square má vlastnost Piece, která značı́ figurku stojı́cı́ na daném poli. View je navázán kolekci objektů Squares a vykresluje je do šachovnice. Square implementuje INotifyPropertyChanged, proto se změny vlast- • PropertyDictionary<PlayerColor, Player> Players: Kolekce hráčů. Typ PropertyDictionary <K, V> je vlastnı́ implementace kolekce objektů, která jako klı́č k zı́skánı́ objektu využı́vá jeho vybranou vlastnost. nostı́ objektu projevı́ v UI. V okně jsou pole reprezentována do mřı́že uspořádanými tlačı́tky, na které je navázán přı́kaz SetSquaresCommand (nastav pole). Pole je možné vybrat pouze v přı́padě, že je na něj možné vykonat tah nebo se na něm nacházı́ figurka táhnoucı́ho hráče; tato podmı́nka je vložena do metody CanExecute() na objektu SetSquaresCommand a pokud ji pole nesplňuje, tlačı́tko je neaktivnı́ (nenı́ možné na něj kliknout). • ObservableCollection<HistoryRecord> History: Kolekce objektů HistoryRecord, která tvořı́ záznam o průběhu hry. • event MovePerformed: Událost vyvolaná při vykonánı́ tahu • event GameEnded: Událost vyvolaná při skončenı́ hry. Je-li však podmı́nka splněna, tlačı́tko je aktivnı́ a klikne-li na něj uživatel, spustı́ se přı́kaz; jako parametr je přı́kazu předán navázaný objekt Square . Přı́kaz vyvolá metodu SetSquares(Square square), která vyhodnotı́ ostatnı́ pole na šachovnici podle pole přı́slušejı́ho tlačı́tku, na které uživatel klikl (tj. vybrané pole). Mohou nastat následujı́cı́ situace: • event PropertyChanged: Událost vyvolaná při změně vlastnosti třı́d. Jejı́ vyvolánı́ aktualizuje UI. • void SetSquares(Square square): Metoda je vyvolána přı́kazem SetSquaresCommand a jejı́m parametrem je vybrané pole. Na základě vybraného pole nastavı́ stavy ostatnı́ch polı́ (nastavı́ aktivnı́ pole a tahy, zneaktivnı́ pole, vykoná tah, atd.) 1. Na vybraném poli se nacházı́ figurka táhnoucı́ho hráče. Nejprve je zavolána metoda ResetSquares(), která odstranı́ přı́padné jiné aktivnı́ pole. Poté je vybrané pole nastaveno jako aktivnı́ (IsActive = true). Na celé šachovnici se může nacházet pouze jediné nebo žádné aktivnı́ pole. Tahy jsou zı́skány od figurky, která stojı́ na aktivnı́m poli, pomocı́ metody GetEvaluatedMoves() a následně jsou zobrazeny v UI. • void ResetSquares(): Uvede šachovnici do stavu bez žádného aktivnı́ho pole a tahů. • void PerformMove(Square square): Spustı́ metodu square.Move.Do(this), která vykoná tah. Poté nastavı́ následujı́cı́ho hráče jako aktuálnı́ho a naopak. Zkontroluje šach, mat i pat. Přidá nový záznam o tahu do historie tahů. Nakonec vyvolá metodu ResetSquares() a událost MovePerformed. • void CheckEnd(): Zkontroluje mat a pat. 2. Vybrané pole je aktivnı́, tj. uživatel na něj klikl dřı́ve. Je zneaktivněno zavolánı́m ResetSquares(). Metoda nastavı́ Square.IsActive = false (zneaktivněnı́ pole) a Square.Move = null (odstraněnı́ tahů) u každého pole v kolekci Squares. • void SaveFile(): Uložı́ textový soubor se záznamem hry ve formátu YAML. Metoda 3. Na vybrané pole je možné vykonat tah. Platı́: Square.Move != null. To znamená, že • bool CheckCheck(): Zkontroluje šach. 7 uživatel dřı́ve vybral pole, které se stalo aktivnı́m a nynı́ chce provést tah s figurkou stojı́cı́m na aktivnı́m poli na právě vybrané pole. Tento tah je vykonán zavolánı́m metody PerformMove(Square square), kde je parametrem vybrané pole. 3.5.2 Zkušebnı́ tah je vykonán zavolánı́m metody TryDo() na objektu tahu. Zkušebnı́ vykonánı́ se od opravdového vykonánı́ tahu lišı́ tak, že má omezenějšı́ vliv a proto je možné ho vrátit zpět pomocı́ metody Undo (). Přestože iterace cyklu probı́hajı́ tak rychle, že View většinou nestı́há zobrazovat změny poloh figurek v UI, původně při vykonávánı́ zkušebnı́ch tahů figurka poblikávala na šachovnici. Tento problém byl vyřešen dočasným vypnutı́m volánı́ události PropertyChanged na objektech Square, což bránı́ aktualizacı́m UI. Zı́skánı́ tahů K zı́skánı́ tahů docházı́ v přı́padě 1 pomocı́ metody GetEvaluatedMoves() na objektů figurky, která stojı́ na aktivnı́m poli. Každý typ figurky má speciálnı́ algoritmus pro zı́skánı́ tahů; všechny figurky majı́ metody GetMoves() a GetEvaluatedMoves(), které vracı́ množinu objektů IMove. Figurka vrátı́ množinu tahů, které je možné vykonat. Program uložı́ všem objektům Square do vlastnosti Move takový tah, jehož cı́lové pole je právě ten objekt Square. Protože vlastnost Move je navázána na View, zobrazı́ se tahy v okně. Surové tahy Metoda GetMoves() vracı́ surové tahy, u kterých nenı́ zaručeno, že vykonánı́ žádného z nich nezpůsobı́ ohroženı́ vlastnı́ho krále. Pokud by byl takový tah vykonán, protivnı́k by mohl v následujı́cı́m tahu sebrat krále, což se nesmı́ stát. HashSet<IMove> moves = GetMoves(); // Vypne notifikace pro UI chessboard.Squares.IsNotifying = false; foreach (IMove m in moves) { // Zkušebně vykoná tah m.TryDo(); Vyhodnocené tahy GetEvaluatedMoves() vracı́ vyhodnocené tahy, které majı́ nastavenou vlastnost IsRestricted na true nebo false. Pakliže je IsRestricted = true, je tah zakázaný a jeho vykonánı́ by způsobilo ohroženı́ vlastnı́ho krále. V opačném přı́padě se jedná o povolený tah, v jehož vykonánı́ hráči nic nebránı́. // Zkontroluje, jestli v takovém rozloženı́ // figurek nenı́ ohrožen král Piece king = chessboard.KingOf(this.Player); if (chessboard.Squares.Any(sq => sq.Piece != null && sq.Piece.Player != this.Player && sq.Piece.GetMoves().Any( move => move.Captive == king))) { // Existuje soupeřova figurka, která by // po vykonánı́ toho tahu mohla // zajmout krále aktuálnı́ho hráče. // -> Tah je zakázán. m.IsRestricted = true; } // Vrátı́ tah zpět m.Undo(); Zajı́mavý je algoritmus pro zı́skánı́ vyhodnocených tahů. Metoda GetEvaluatedMoves() nejprve zı́ská surové tahy od metody GetMoves(). Následně je proveden foreach cyklus na kolekci tahů; každá iterace náležı́ jednomu surovému tahu a vykoná následujı́cı́: 1. Zkušebnı́ přesunutı́ figurky na cı́lové pole tahu 2. Zı́skánı́ tahů všech figurek soupeře; pokud se mezi nimi nacházı́ alespoň jeden tah, jehož vykonánı́m by byl sebrán král aktuálnı́ho hráče, je tah (nikoliv soupeřův) označen jako zakázaný nastavenı́m vlastnosti IsRestricted = true. V opačném přı́padě je tah povolený. } chessboard.Squares.IsNotifying = true; return moves; Kód 1: Úryvek kódu z metody pro zı́skánı́ vyhodnocených tahů ve třı́dě Piece 3. Přesunutı́ figurky zpět na výchozı́ polohu a uvedenı́ šachovnice do původnı́ho stavu 8 3.5.3 hráč může vykonat nějaký tah. Zı́ská tahy všech figurek aktuálnı́ho hráče a pokud mezi nimi nenı́ žádný povolený tah, podmı́nka je splněna. Tehdy se vyhodnocuje vnořená podmı́nka. Mohou nastat situace: Provedenı́ tahu K provedenı́ tahu docházı́ v přı́padě 3. Vybrané pole má ve vlastnosti Moove uložen tah, který je vykonán zavolánı́m metody IMove.Do(): Metoda vykoná následujı́cı́: 1. Hráč je v šachu. Ze situace vyplývá, že král hráče je ohrožen a nelze tuto situaci nelze zvrátit žádným tahem → Nastává šachmat. 1. Odstranı́ figurku Piece IMove.Captive (sebraná figurka) ze šachovnice, pokud nenı́ hodnotou této vlastnosti null 2. Hráč nenı́ v šachu. Ze situace vyplývá, že král hráče nenı́ ohrožen a hráč nemůže vykonat žádný povolený tah → Nastává pat. 2. Odstranı́ stojı́cı́ figurku na aktivnı́m poli a tutéž figurku nastavı́ jako stojı́cı́ na vybraném poli. Metoda v obou přı́padech nastavı́ přı́slušným hráčům odpovı́dajı́cı́ stav, nastavı́ vlastnost šachovnice IsGameOver = true a vyvolá událost GameEnded s argumenty popisujı́cı́mi konec hry. View na vyvolanou událost reaguje otevřenı́m okna, které oznamuje konec hry a dodatečné informace (data čerpá z argumentů události – objektu GameEndedEventArgs). Po samotném tahu je aktuálnı́mu hráči nastavena vlastnost Turns = false a následujı́cı́mu true. Tı́m se následujı́cı́ hráč stává aktuálnı́m a naopak. Následuje ověřenı́, zda tah nezpůsobil šach, mat či pat aktuálnı́mu hráči. Vyhodnocenı́ šachu Nejprve je vyhodnocen šach zavolánı́m metody CheckCheck(). Metoda zı́ská tahy všech figurek soupeře a je-li mezi nimi takový tah, jehož vykonánı́m by byl sebrán král, je nastaven stav hráče na PlayerState.Check. // Podmı́nka je splněna, existuje-li figurka // aktuálnı́ho hráče, která má alespoň // jeden povolený tah. if (!Squares.Any(p => sq.Piece != null && sq.Piece.Player == CurrentPlayer && sq.Piece.GetEvaluatedMoves().Any( m => !m.IsRestricted))) { bool check = false; // Najde všechna pole s figurkou soupeře, // která má alespoň jeden tah ohrožujı́cı́ krále foreach (Square sq in Squares.Where(sq => sq.Piece != null && sq.Piece.Player != CurrentPlayer && sq.Piece.GetMoves().Any(m => m.Captive == KingOf(CurrentPlayer)))) { // Všechny figurky stojı́cı́ na takových // polı́ch ohrožujı́ krále a způsobujı́ šach sq.Piece.ThreatensKing = true; check = true; } if (CurrentPlayer.State == PlayerState.Check) { /* Mat */ } else { /* Pat */ } } Kód 3: Podmı́nka oveřujı́cı́ mat a pat Dále je do kolekce ObservableCollection < HistoryRecord> History přidána nová instance třı́dy HistoryRecord, která shromažd’uje informace o vykonaném tahu. Kolekce History tvořı́ kompletnı́ if (check) { SetPlayerState(CurrentPlayer, PlayerState.Check); return true; } záznam průběhu hry. 4 return false; Závěr Kód 2: Kód metody oveřujı́cı́ šach 4.1 Vyhodnocenı́ matu a patu Dále je vyvolána metoda CheckEnd(), která vyhodnotı́ konec hry. Metoda obsahuje dvě podmı́nky, druhou vnořenou v prvnı́. Vnějšı́ podmı́nka vyhodnotı́, zda aktuálnı́ Vývoj návrhu, problémy Návrh aplikace se v průběhu vývoje značně měnil a při konfliktech s problémy bylo potřeba provést několik klı́čových přebudovánı́ projektu. Původnı́ myšlenka byla následujı́cı́. 9 • Hlavnı́ aplikačnı́ třı́da (šachovnice) bude obsahovat kolekci objektů figurek. možné přidat libovolný speciálnı́ tah a upřesnit akci při jeho vykonánı́. • Projekt obsahuje třı́du Position; každá figurka má vlastnost tohoto typu, která značı́, na jaké pozici se figurka nacházı́. Vyhodnocenı́ tahů Obtı́žné bylo poradit si s tahy, jejichž vykonánı́ by způsobilo ohroženı́ vlastnı́ho krále (zakázané tahy). Původnı́ řešenı́ zobrazovalo uživateli zakázaný tah jako povolený. Při vykonánı́ takového tahu však byl uživatel upozorněn a tah vrácen zpět. • Figurka vracı́ kolekci objektů Position jako pozice, na které je možné vykonat tah. Toto rozvrženı́ bylo základem aplikace a později se ukázalo jako nevýhodné. Vykreslenı́ uživatelského rozhranı́ podle tohoto modelu bylo obtı́žné a návrh neumožňoval zapamatovánı́ stavu polı́, na kterých se nenacházela figurka. Nabı́zely se dvě možnosti návrhu aplikace: Náhradnı́m řešenı́m bylo vyhodnocenı́ tahů, které spočı́valo v zabráněnı́ uživateli ve vykonánı́ zakázaného tahu. Každý tah zı́skaný od figurky je zkušebně vykonán a podle ohroženı́ vlastnı́ho krále je tah vyhodnocen jako povolený či zakázaný. Na základě této informace se takový tah na šachovnici zobrazı́ odlišně a uživateli nenı́ povoleno jej vykonat. 1. Kolekce figurek s vlastnostı́ pole, na kterém figurka stojı́. 2. Kolekce polı́ s vlastnostı́ figurky, která na poli stojı́. Problémem byla skutečnost, že zkušebnı́ vykonánı́ tahu se zobrazovalo i v UI, což bylo nežádoucı́. Původnı́m konceptem řešenı́ bylo vytvořenı́ kopie šachovnice, na které budou tahy vykonány nezávisle na UI. Jednoduššı́m a finálnı́m řešenı́m bylo vypnutı́ volánı́ události PropertyChanged při změně vlastnosti Square během vykonávánı́ zkušebnı́ch tahů, což zabránilo aktualizacı́m UI. Zkušebnı́ tah mimo jiné neobnášı́ všechny akce jako tah na ostro“. ” Zvı́tězil návrh #2 (kvůli jednoduššı́mu bindingu) a projekt prošel prvnı́ přestavbou. Třı́da Position se vyvinula ve třı́du Square, nynı́ představujı́cı́ samotné pole spı́še než jen pozici; kromě souřadnic obsahuje informace jako figurku, která na poli stojı́, barvu a stav (tj. jestli je aktivnı́, jestli je na toto pole možné vykonat tah atd.). Hlavnı́ aplikačnı́ třı́da Chessboard obsahuje kolekci objektů figurek (Piece) a polı́ (Square), přičemž figurky nevı́, na kterém poli stojı́. Figurky ovšem obsahujı́ referenci na Chessboard instanci a proto mohou jednoduše vrátit pozici vyhledánı́m přı́slušného pole v kolekci. Figurky zároveň potřebujı́ mı́t referenci na šachovnici pro zı́skánı́ tahů. 4.2 Splněnı́ zadánı́ V průběhu vývoje aplikace Šachy se mi podařilo naplnit všechny body zadánı́, vč. základnı́ i bonusové funkcionality. Výjimkou je započı́távánı́ bodů, nebot’ pravidla hry šachy žádné body nepopisujı́. Mı́sto toho aplikace umožňuje v okně Statistics zobrazit vývoj počtu figurek v průběhu hry, což může být považováno za alternativu k bodovému hodnocenı́. Nejprve byly tahy zı́skávány ve formě vracenı́ kolekce polı́ či pozic, na které je možné vykonat tah. Poté bylo použito zapisovánı́ stavů přı́mo do objektů Square bez vracenı́ kolekce, což se později ukázalo být neefektivnı́ ze dvou důvodů: bylo obtı́žné realizovat speciálnı́ tahy (např. tah mimochodem, kdy se sebraná figurka neshoduje s figurkou, jež stojı́ na cı́lovém poli) a také nebylo možné tahy před zobrazenı́m na šachovnici zpracovat (vyhodnocenı́ tahů). Jako řešenı́ se jevilo vracenı́ kolekce objektů představujı́cı́ch tahy (s vlastnostmi jako startovnı́ a cı́lové pole, přemist’ovaná figurka, sebraná figurka, ...). Pro tento účel bylo vytvořeno interface IMove, specifikujı́cı́ vlastnosti tahu, a kterýkoliv druh tahu implementuje toto rozhranı́. Dı́ky tomuto systému je 10
Podobné dokumenty
popis programu - Javascript games
je určena pro 4 hráče. První 3
jsou virtuální hráči, za které
hraje počítač. Hráč má
k dispozici 7 dominových
kostek. Hráč, který má
domino s logem Apple Safari
začíná a ostatní hráči hrají po
něm....
velké
• Společnou silou vytvořit 4 nezávislé překlady celkem 515 anglických vět do
češtiny.
Pokuste se o dobrý překlad, hledejte ve slovnı́cı́ch, hledejte na webu.
• Změřit 4x BLEU jednoho p...
Binding - vjj root page
binding with DataContext