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

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....

Více

NOVINKY 2016 - Kesseböhmer

NOVINKY 2016 - Kesseböhmer 1 230 mm (1 600 – 1 700 mm) 1 530 mm (1 900 – 2 000 mm)

Více

velké

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...

Více

Binding - vjj root page

Binding - vjj root page binding with DataContext Více