Projekt Szachów

0

Próbuję napisać szachy, ale mam ogromny kłopot z projektem.
Szukałem na forum, ale nie zauważyłem niczego co by mi pomogło.

Czy pozycję poszczególnych bierek powinna trzymać plansza, czy same bierki?
Czy bierki powinny trzymać swoją ikonę, czy grafikę trzymać jakoś osobno i trzymać ikony(linki) w jakimś xmlu?
Możliwe ruchy powinny być określane w klasie planszy, zawodnika, czy samych bierek?
Ocena sytuacji powinna być w klasie zawodnika?

Jak Wy byście rozdzielili zadania, zrobili komunikację między klasami, i z grafiką?
Z góry dziękuję za wszelką pomoc.

Na razie mam klasy:
GUI z wczytanym obrazkiem planszy.
Checker abstrakcyjną która trzyma kolor bierki, jej pozycję, typ(kończy coś innego), ilość wykonanych przez nią ruchów, możliwe ruchy, wartość, ikonę i inne rzeczy nie istotne w pytaniu.
Dziedziczą po niej wszystkie bierki i implementują(na razie w zamierzeniu) metodę wyznaczenia możliwych ruchów.
Field zawierającą kolor, bierkę i pozycję.
Position zawiera 2 inty: file i rank.
Board zawiera statyczną tablicę Field[8][8].
Color enum z biały, czarny.
Player zawiera color, i ocenę tempa, materiału i pozycji.
Ale to jest cienkie, bo bicia w przelocie przy tym rozkładzie klas nie uda się zrobić.

0
  1. MVC - logika gry powinna być oderwana calkowicie od tego jak to jest potem wizualizowane
  2. Raczej nie ma jednego poprawnego rozwiązania, ale skoro pionek zna swoją pozycję to ta tablica Field[][] jest już zbędna w planszy. Poza tym legalność ruchów może sprawdzać tylko plansza bo nikt inny nie ma dostępu do pozostałych pionków.
0

Dzięki.
Field[][] właśnie po to było żeby znać położenie pozostałych, ale Twoje rozwiązanie jest lepsze.

Kontroler mam zrobić tak, że jak użytkownik zrobi ruch ro mam sprawdzić czy jest możliwy, zmienić w GUI i obserwatora ustawić w klasie Board do zmiany w ustawieniu bierek?

0

W sumie, to lepiej wywalić pozycję z bierki i trzymać to w Board?

1

@DużaTajemnicaWiedzy tak może być trochę łatwiej, ale pamiętaj o SRP ;) Bo zaraz się okaże że Board to jest taki God-object który zajmuje się wszystkim.

2

Postaram się nie programować faraonowo :)

2

Plansza przechowująca pozycje (i tylko pozycje) wszystkich bierek nie jest w pełni kompetentnym sędzią. Nie potrafi rozstrzygnąć czy dopuszczalna jest roszada, czy można bić w przelocie.

1

Bo zaraz się okaże że Board to jest taki God-object który zajmuje się wszystkim.

I to wcale nie byłoby złe.
„Wszystkim” w sensie logiki gry, bo już rysowanie powinno być całkowicie wydzielone.

Field zawierającą kolor, bierkę i pozycję.
Koloru pola nie musisz trzymać, raz że jest zdeterminowany to dwa że jest zupełnie nieistotny z punktu widzenia zasad gry. Tym niech się przejmuje funkcja rysująca.
Pozycji pola też nie musisz trzymać, bo tę określają indeksy do tablicy [8][8].
Unikaj powielania tych samych danych.

Plansza przechowująca pozycje (i tylko pozycje) wszystkich bierek nie jest w pełni kompetentnym sędzią.
No parę dodatkowych flag określających stan gry będzie potrzebne.

czy grafikę trzymać jakoś osobno i trzymać ikony(linki) w jakimś xmlu?
To nieistotne. Na razie zajmij się odzwierciedleniem mechaniki gry, ładna wizualizacja poczeka...

PS. Przydadzą się oficjalne zasady, żeby uniknąć wersji „szachy pana Tadzia”.

2
Azarien napisał(a):

Bo zaraz się okaże że Board to jest taki God-object który zajmuje się wszystkim.

I to wcale nie byłoby złe.

Byłoby.

Na mój gust, to mniej więcej tak:
Board ma kolekcję Fields i Pieces.
Field umie określić swoją pozycję i ma referencję do Piece, która na nim stoi.
Piece jest abstrakcyjna ma Name, MovesCounter i kolekcję StandardMoveRules, która jest nadpisywana w klasach potomnych.
StandardMoveRules składa się z obiektów StandardRule, które określają: MoveDirection (z enuma), MoveFieldsLimit (liczba), AttackDirection, AttackFieldsLimit (każde z tych czterech, to na koński wypadek kolekcja. ;)) oraz CanJumpOver.
Do tego Board ma History, które składa się z Move.
Move ma referencje do dwóch Field, dwóch Piece i określa swój Type (ruch, bicie, promocja).
Potrzebny jest jeszcze CustomRulesProvider opisujący możliwość wykonania niestandardowego ruchu, czyli: pierwszy ruch piona, bicie w przelocie i roszadę.

A do tego MoveValidator, który na podstawie Board, History, CustomRulesProvider, i danych żądanego ruchu określi, czy jest on możliwy. W tym celu zweryfikuje:
1) czy ruch jest w ogóle poprawny dla bierki (najpierw przez CustomRulesProvider, a potem korzystając ze StandardMoveRules);
2) czy nie występuje jakaś ograniczająca sytuacja na planszy (np. szach, albo próba roszady przez pole szachowane - to wszystko bazując na Board);
3) i czy nie ma jakichś zaszłości historycznych zabraniających tego ruchu (chyba dotyczy to tylko roszady i ruchu królem).

Jeżeli ruch można wykonać to następnie ResultCalculator na podstawie obecnego Board i History stwierdza, czy jest mat, pat, remis, czy jeszcze coś innego.
MoveValidator i ResultCalculator to na wszelki wypadek powinny być strategie (np. po to, żeby łatwo można było podmienić zasady na turniejowe).
History i Move to chyba przypadkiem wyjdzie jakaś prosta realizacja Event Sourcingu, którym niektórzy się strasznie ostatnio podniecają. ;P

0

Dla uproszczenia planszę będę numerował od 0 do 63 (nie jako [8][8]). Położenie na planszy bardzo łatwo policzyć w postaci 8x8. Ale to już kwestia jak komu wygodniej.

Podszedłbym nieco inaczej. Pion posiada stan i hostorię, którą dziedziczy po jakimś abstract pionie (na tej podstawie można łatwo określać czy pion może wyknać startowe ruchy, roszadę etc). Każdy pion dostaje Strategię ruchu. Czyli pion używając strategii wie gdzie i czy może sie ruszyć.
Board posiada tablicę AbstractPion[64]. Idea board jest po to, aby można było łatwo określać czy jakieś pole jest puste czy zajęte, dostać kolekcję wszystkich pionów białych czarnych etc. Sam board to tylko "worek" na dane
Strategia ruchu potrafi powiedzieć gdzie pion może się poruszyć(lista pól), oraz potrafi wykonać ruch.
Dodatkowo wygodny będzie obiekt Move(from,to,ref do piona) który jest konstruowany w fazie sprawdzania ruchów

Całość opakowana jest w obiekt np GameState który pośredniczy między interfejsem a grą. GameState posiada takie ifno jak akutalna tura, obiekt board, historię etc. Ten obiekt potrafi określać całkowity stan planszy (tj szach, mat, pat)

Na początku każdej tury interfejs odpytuje GS o możliwe ruchy do wykonania -> iterowanie po wszystkich pionach danego koloru w celu zebrania pionków które w ogóle mogą się ruszyć, oraz gdzie mogą się ruszyć, czyli zbudowanie kolekcji Move[].

czyli:
AbstractPion{
historia;
stan(kolor,zbuty,aktywny);
aktualnaPozycja;
moveStrategy; <- to zależy od sposobu w jaki pion używa stratergii, czy przez repozytorium czy dostaje w trakcie konstrukcji, ewentualnie czy board rusza pionami

Move[] getPossibleMoves(Board board);
void move(Board board);
void afterMove();  <- metoda wykonywana przez strategię po wykonaniu ruchy w celu określania np. promocji

}

Board{
AbstractPion[64]

AbstractPion[] getWhitePawns();
AbstractPion[] getBlackPawns();
Move[] getPossibleMove(Color);  

}
GameState{
turn;
hitedPawns;
Board;
doneMoves;

Move[]  getPossibleMove();
void move(int from, int to);
void changeTurn();
State checkState();

}
MoveStrategy<t extend="extend" abstractpawns="AbstractPawns">{
Move[] getPossibleMoves(T pawn, GameBoard board);
move(t pawn, GameBoard board);
}
(Same strategie ruchów są bezstanowe i mogą być przekazywane pionom w trakcie konsstrukcji bądź piony będą się odwoływać do jakiegoś repozytorium strategi, co wygodniej). Sam interfejs strategi w takiej postaci jest o tyle wygodny, że bardzo łatwo pisać testy jednostkowe dla poszczególnych rodzajów pionów. Interfejs strategii może być generyczny aby ustszec się sytuacji kiedy Stretegię piona poda się wieży. Innym rozwiązaniemm jest iterowanie przez piony w klasie board i to board wykonuje metody strategii, tak że pion nie będzie wiedział o istnieniu strategii. W sumie do przemyślenia.

Metoda checkState może się przeiterować po pionach i na bazie ich strategii określać czy ktoś nie atakuje króla.
Każdy wykonany ruch (Move) odkładamy do listy done moves - aby określić ewentualny remis.


odpowiadając na pytanie Somekind:
coś w rodzaju:
board:
for(Pawn p : pawns){
p.getPossibleMove(this);
}

pawn:
getPossibleMove(Board){
strategy.getPossibleMove(this, board);
}

inne rozwiązanie:
board:
for(Pawn p : pawns){
RepozytoriumStrategii.getStrategyForPawn(p).move(p, this)
}

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0