Wielodziedziczenie - figury szachowe

0

Chcę aby królowa, do wygenerowania swoich możliwych ruchów, skorzystała z funkcji generacyjnej zawartej w Wieży oraz Gońcu. Jak to poprawnie zrobić ?

class Fig
{
        public:
        virtual bool gen() = 0;
};

class Rock: public Fig
{
        public:
        void genTemp() {}
        bool gen()
        {
        }
};

class Bishop: public Fig
{
        public:
        void genTemp() {}
        bool gen()
        {
        }
};

class Queen: public Rock, public Bishop
{
        public:
        bool gen()
        {
                Rock::genTemp();
                Bishop::genTemp();
        }
};

int main()
{
        Fig* a = new Queen;
        a->gen();

        return 0;
}
0

W tym wypadku musisz zmienić:

class Rock: public Fig
...
class Bishop: public Fig
...

na

class Rock: public virtual Fig
...
class Bishop: public virtual Fig
...

Dlaczego tak nie będę tłumaczył, bo jestem zbyt zmęczony, a post byłby długi. Info w necie znajdziesz bez problemu - szukaj pod hasłem "dziedziczenie wirtualne".

0

Dziękówa, działa.
Może jutro jak odpoczniesz, podsuniesz dobre rozwiązanie takiegoż problemu:

żeby ruszyć jakąś figurą, figura ta musi mieć dostęp do wszystkich innych pozostałych figur na planszy (aby ocenić możliwość ruchów i zbić) i teraz:

  1. w konstruktorze figury przekazywać referencję do kontenera, który przetrzymuje wskaźniki figur (klasa board by miała taki kontener, i w niej bym tworzył figury i przekazywał referencję do tegoż kontenera)
  2. utworzyć statyczny wektor wskaźników figur w klasie figura.

Tak czy owak, brzydko to "pachnie" i mam duży mętlik jak to rozwiązać elegancko !

0

Ja zrobiłbym całkiem innaczej-większość wpakował w klasę Szachownica,i to ona wiedziałaby,jakie ruchy są dozwolone dla danego typu figury,a także zawierałaby listę położeń wszystkich figur i na tej podstawie określałaby,jake ruchy która figura może zrobić.
Klasa Figura byłaby wtedy bardzo prosta,jeśli wręcz nie zbędna-zawierałaby tylko pole type,najlepiej typu enum.(tak rozmyślając na szybko)

0

No wiem, bardzo dużo by to uprościło takie podejście i zapewne byłoby szybsze. Początkowo tak zamierzałem zrobić, ale chciałem wybrać ambitniejszą drogę - czyli polimorfizmu :-D

Na razie pozostaje aktualne pytanie co do tamtego problemu....

0

Co do dziedziczenia to tak - działa.
Pozostaje kwestia dostępu do innych figur wewnątrz figury. Nie ma na to jakiegoś wzorca czy coś ? Chyba nie jestem pierwszy z takim problemem :>

0

Ja bym proponował trochę inaczej MasterBLB. To jakie ruchy są dozwolone dla danej figury powinna znać tylko figura, poruszać figurą powinien gracz, szachownica wystarczy, ze będzie wiedziała czy pole ma wolne czy zajęte.
W skrócie: obiekt klasy gracz każe figurze się poruszyć->obiekt klasa odpowiadający za logikę pyta daną figurę czy w ogóle może się tak przemieścić, następnie sprawdza czy na szachownicy jest wolne pole, czy coś się tam znajduje->w zależności od tych sprawdzeń wykonuje akcje(np. zbicie figury przeciwnika, zaakceptowanie przesunięcia, czy odrzucenie ruchu ze względu na złamanie zasad).
Wymyślone na szybko, bez przemyślenia, i nie na trzeźwo więc może coś być nie do końca sensowne. ;)

0

Czyli szachownica posiada pionki, ale każdy pionek powinien mieć dostęp do szachownicy (w kwestii implementacyjnej).
Więc chyba najrozsądniej w konstruktorze figury, przekazać referencję do szachownicy.... ?

0

Pionek nie ma dostępu do szachownicy - pionek co najwyżej może podać gdzie może się przemieścić biorąc pod uwagę położenie. Szachownica nie ma dostępu do figury, wie tylko że coś się tam w danym miejscu znajduje(ewentualnie trzyma wskaźnik do figury). Gracz ma dostęp do pionków i szachownicy, on widzi całość gry. Logika gry mu zezwala lub odmawia wykonania danego ruchu.

Zaznaczam, że to jest moja koncepcja(tak to widzę intuicyjnie). Fajnie by było jakby wypowiedział się na ten temat jeszcze ktoś(najlepiej z doświadczeniem).

0

Hmm, czyli w kwestii samych klas figur:
figura nic nie wie o innych figurach. Wirtualne metody odpowiednich typów figur, zwrócą wszystkie możliwe współrzędne przesunięć figury i warstwa wyższa zadecyduje co z tym zrobić. Więc odpadałaby kwestia przekazywania do nich wskaźnika kontenera innych figur.

Co do "właścicielstwa" figur: Ja bym zaproponował tu jeszcze jedną klasę - "Stan gry". Bo z bieżącego stanu gry - tworzymy drzewo gry (mówię o tu IQ komputera), więc chyba relacja byłaby taka klas: Figura<-StanGry<-Szachownica<-Gracz

No ale może ktoś ma jeszcze jakieś uwagi....

0

Podumałem,i nim pójdę spać i zapomnę to zapodam,jakbym to widział.
Klasa Szachownica zawierać będzie Figura *plansza[8][8]; zainicjowaną zerami-będzie odpowiadać za przechowywanie układu figur.Zmiana położenia będzie uzyskiwana przez przepisanie wskaźnika na poruszaną figurę pod nowy indeks,a pod stary będzie przypisywane 0.Usuwanie figury z planszy zaś po prostu uzyska się poprzez delete plansza[a][b],po czym plansza[a][b]=0.Tak chyba będzie najprościej i najszybciej.

Klasa figura będzie zawierać:

class Figura
{
public:
   enum KierunekRuchu
   {
       ZłyRuch,Poziomo,Pionowo,NaSkos,LiteraL itd...
   }
   int x,y;//położenie figury na planszy,czyli indeksy tablicy plansza siedzącej w klasie Szachownica
   bool kolor;//true to biały,false to czarny.Jak ktoś bardzo chce,to może dać tutaj enuma
   virtual KierunekRuchu sprawdźLegalnośćRuchu(int indexX,int indexY)=0;
   virtual List<Pair<x,y> > * bicie(bool &czyMaInneBicieNiżDozwolonyRuch)//to potrzebne z uwagi na bijące po skosie pionki
   {
      czy...=false;
   }
}

Teraz jak to ma pomykać:
1.Coś chce przesunąć daną figurę na pole x,y.Nie widzę konieczności wprowadzania klasy Gracz,ja wstępnie dałbym to do klasy Szachownica
2.Szachownica wywołuje plansza[a][b]->sprawdźRuch(x,y) i dostaje kierunek ruchu
3.Szachownica sprawdza,czy aby nie dostała Figura::ZłyRuch.Jak tak,to nie wiem,pokazuje stosowny komunikat "A SPRDLJ z takim ruchem" i dalsza część algorytmu nie wykonuje się.
4.Teraz czas sprawdzić,czy na drodze do docelowej lokacji aby coś nie stoi.Łatwo to uzyskać badając tablicę plansza[x+offset][y+offset],gdzie x i y to położenie ruszanej figury,a offset jest liczony w zależności od wyniku jaki da funkcja sprawdźRuch.Jeśli nic nie znajdzie się pomiędzy lokacją startową a docelową figury,to można figurę przesunąć.
5.Rozpatrzenie zbicia figury,opisane przy szachownicy wyżej (czyli delete i ustawienie wskaźnika w planszy na 0)
6.Przesunięcie figury jest wykonywane poprzez przepisanie wskaźnika w tablicy plansza pod nowy indeks,a w stary wstawiane jest 0

EDIT:
Po namyśle jednak przychylę się do swej 1 koncepcji,tj że za sprawdzenie legalnościu ruchu opowiada szachownica-a to przez nietypowe poruszanie się i bicie pionków,które rozwalają pomysł z tego posta.Klasa figura uprości się więc do:

class Figura
{
public:
   enum RodzajFigury
   {
       Pionek,Goniec,Wieża,Konik itd...
   };

   RodzajFigury rodzaj;
   int x,y;//położenie figury na planszy,czyli indeksy tablicy plansza siedzącej w klasie Szachownica
   bool kolor;//true to biały,false to czarny.Jak ktoś bardzo chce,to może dać tutaj enuma

   Figura(const RodzajFigury &jaka):rodzaj(jaka)
   {};
}

Szachownica zaś wzbogaci się o funkcję:

bool sprawdźRuch(Figura *figura,int x,int y);//co do zwrotu,może być lepszy jakiś enum określający,czy ruch będzie poza planszę,czy jest blokowany przez figurę,czy też nastąpi zbicie
0

co do komentarza Byku_Guzio

wystarczyłoby, żeby figura sprawdzała czy przesunięcie się na dane pole jest dozwolonym ruchem - byku_guzio dzisiaj, 01:20

  1. Przy tworzeniu drzewa gry, generujemy możliwe posunięcia, więc tak czy owak, figura musi zwrócić wszystkie możliwości (albo coś w ten deseń).
  2. MasterBLB, na razie dogłębnie nie analizuje - stanęliśmy na tym że wykorzystujemy polimorfizm :D
  3. Co do bicia w przelocie, to będzie istniał mechanizm, który po każdym ruchu zaanalizuje stan gry (szach, bicie w przelocie, wygrana, remis i inne)
0

Mała łamigłówka dla znudzonych:
Jak elegancko wyznaczyć 4 wektory dla Gońca, mając jego współrzędne(x,y) na planszy(1,1)->(8,8) ?

Postanowiłem że każda figura będzie zwracać wektory, w których może podążać (z punktu widzenia figury, nie planszy)

0

Postanowiłem że każda figura będzie zwracać wektory, w których może podążać (z punktu widzenia figury, nie planszy)

Pionek, król i konik też?

0

Pionek po częsci tak (ruch o 2 pola do przodu).
Skoczek i król to ruch można by rzec jednostkowy ze zbiciem.

0

Mała łamigłówka dla znudzonych:
Jak elegancko wyznaczyć 4 wektory dla Gońca, mając jego współrzędne(x,y) na planszy(1,1)->(8,8) ?

#include <iostream>
#include <vector>
#include <utility>
using namespace std;

typedef pair<int,int> iipair;

vector<iipair> GetBishopsMoves(int x,int y)
{
   int i,j;
   vector<iipair> result;
   for (i=x-1, j=y-1; i>=1 && j>=1; i--,j--)
     result.push_back(iipair(i-x,j-y));
   for (i=x-1, j=y+1; i>=1 && j<=8; i--,j++)
     result.push_back(iipair(i-x,j-y));
   for (i=x+1, j=y+1; i<=8 && j<=8; i++,j++)
     result.push_back(iipair(i-x,j-y));
   for (i=x+1, j=y-1; i<=8 && j>=1; i++,j--)   
     result.push_back(iipair(i-x,j-y));
   return result;
}

int main()
{
   int x=2, y=3;
   vector<iipair> moves = GetBishopsMoves(x,y);
   cout << "Goniec na pozycji: ("<<x<<","<<y<<")\n\n";
   cout << "Dozwolone ruchy:\n";
   for (int i=0; i<moves.size(); i++)
     cout<<"("<<moves[i].first<<","<<moves[i].second<<") ";
   cout<<endl;
}
0

Znajomość położenia figur i pionków nie wystarcza by określić jakie ruchu są dozwolone. Problem jest z roszadą i z biciem w przelocie, trzeba uwzględnić dotychczasowy przebieg partii. Dodatkowa trudność: formalnie możliwe jest kilka ruchów gońcem, ale jednocześnie król jest szachowany, trzeba uwzględnić, które ruchy gońcem "usuwają" szacha.

0

Takich niuansów jest więcej, jak wyżej piszesz. Właściwie każdy ruch może powodować odkrycie króla, które wiadomo jest niedozwolone.

Mały kłopot - przeniosłem projekt z GCC na VS i jest mały problem przy wielodziedziczeniu wirtualnym:
*'Queen' : ambiguous inheritance of 'Bishop Figure::Clone(void) const'

class Figure
{
	protected:
		Point coord;
		bool player;
	public:
		Figure(Point& pt, bool p): coord(pt), player(p) {}
		virtual ~Figure() = 0;
		Point& GetCoord();
		bool GetPlayer();
		void Move(Point);
		virtual VectorList* GenMoves() = 0;
		virtual Figure* Clone() const = 0;
};

class Bishop: public virtual Figure
{
	private:
		static const int Track[4][2];
	protected:
		VectorList* GenDiagonal();
	public:
		VectorList* GenMoves();
		Bishop(Point pt, bool p): Figure(pt, p) {}
		Bishop* Clone() const;
};

class Rock: public virtual Figure
{
	private:
		static const int Track[4][2];
	protected:
		VectorList* GenHV();
	public:
		VectorList* GenMoves();
		Rock(Point pt, bool p): Figure(pt, p) {}
		Rock* Clone() const;
};

class Queen: public Bishop, public Rock
{
	public:
		VectorList* GenMoves();
		Queen(Point pt, bool p): Figure(pt, p), Rock(pt, p), Bishop(pt, p) {}
		Queen* Clone() const;
};
0

Problemem jest to, że tak się nie pisze metod wirtualnych ;) Metody wirtualne muszą zwracać zawsze ten sam typ, w przeciwnym wypadku zamiast metody wirtualnej masz zwykłe przesłonięcie nazw funkcji.

0

Mi się skompilowało po zmianach:
1.Dziedziczenie Figure przez Wieżę i Gońca jest zwykłe public
2.Funkcje Clone() wszędzie zwracają Figure*,tak jak mówi byku_guzio;innaczej jest C2555
3.Królówka dziedziczy Wieżę i Gońca public virtual
4.A,i wywalenie inicjalizacji obiektu Figure z klasy Queen

0
byku_guzio napisał(a)

Problemem jest to, że tak się nie pisze metod wirtualnych ;) Metody wirtualne muszą zwracać zawsze ten sam typ, w przeciwnym wypadku zamiast metody wirtualnej masz zwykłe przesłonięcie nazw funkcji.

Opieram się na Thinking in C++ i tam jest omówione, że tak można robić z racji takiej, że typ zwracany jest pochodny od typu bazowego.
Generalnie już coś ruszyło lepiej. Dzięki.

0

Taki następny problem, nad którym myślę. MinMax wiem jak działa, ale nie mogę zrozumieć, na jakiej podstawie został odcięty stan, który ma wartość 8 ? (to po prawej stronie).
Wartość heurystyczna tego węzła, wzięła się z jego potomków (no ale po to ma być odcięte, aby ich nie generować ?)

user image

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