Programowanie obiektowe zadanie 2

Zadanie zaliczeniowe z laboratorium programowania obiektowego

Laboratorium programowania obiektowego
Zadanie zaliczeniowe 2
termin oddawania rozwiazan: 9 czerwca 2008

Bezszachy sa wariantem gry w szachy. Gra prowadzona jest przez dwoch graczy,
nazywanych dalej bialym i czarnym, na szachownicy 8 na 8, za pomoca bierek
szachowych. Poczatkowe ustawienie figur na szachownicy jest takie samo, jak
w zwyklych szachach. Pionkow w bezszachach nie uzywa sie.

Gracze wykonuja na przemian po jednym ruchu, zaczynajac od gracza bialego.

Figury bezszachowe poruszaja sie po szachownicy tak samo, jak szachowe.
Jedynym wyjatkiem jest brak mozliwosci roszady.

W bezszachach, w odroznieniu od szachow, nie istnieja pojecia szachu i mata.
Zabicie krola nie powoduje zakonczenia gry.

Gra konczy sie zwyciestwem jednego z graczy, gdy uda mu sie zabic wszystkie
bierki przeciwnika. Gra konczy sie remisem, gdy gracz nie moze wykonac
zadnego legalnego ruchu, choc pozostaly mu bierki. Remis oglaszamy rowniez,
gdy gracze wykonaja 1000 ruchow (po 500 ruchow kazdego gracza).

Napisz w C++ program, ktory przeprowadzi partie bezszachow miedzy para
graczy:

* losowym, ktory za kazdym razem losowo wybiera jeden z dozwolonych w danej
chwili ruchow. Wybor kazdego z legalnych ruchow powinien byc rownie
prawdopodobny. Jesli np. gracz ma dwie bierki i jedna z nich moze wykonac
10 legalnych ruchow, a druga 5, to prawdopodobienstwo ruchu pierwsza bierka
powinno byc dwa razy wieksze, niz druga.

* leniwym, ktory sposrod bierek, ktorymi moze sie ruszyc wybiera ta, ktora
znajduje sie najblizej jego krawedzi szachownicy (wiersz pierwszy dla bialego,
osmy dla czarnego). Jesli wybrana bierka gracz moze wykonac bicie, robi to,
jesli nie, wykonuje nia losowy ruch.

Program powinien ruszac sie za obu graczy i, po kazdym ruchu, wypisywac
na wyjscie stan szachownicy. Na zakonczenie partii nalezy wypisac informacje
o wyniku - kto wygral, czy byl remis.

Informacje dla osob, ktore nie znaja zasad gry w szachy:

Poslugujemy sie piecioma rodzajami figur:

* wieza - moze sie przesuwac po wierszu lub kolumnie szachownicy
* goniec - moze sie przesuwac po przekatnych szachownicy
* hetman - moze wykonywac ruchy takie, jak wieza lub goniec
* krol - moze wykonac ruch na jedno z sasiednich pol, takze po przekatnej
* skoczek - moze wykonac ruch, zmieniajac numer wiersza o 2 a kolumny o 1,
  lub na odwrot. Jest jedyna bierka, ktora moze "przeskoczyc" nad innymi.

Jesli na polu, na ktore przestawiamy bierke, jest bierka przeciwnika, zabijamy
ja, czyli zdejmujemy z szachownicy.

Poczatkowo na szachownicy w pierwszym wierszu sa figury gracza bialego,
kolejno: wieza, skoczek, goniec, hetman, krol, goniec, skoczek, wieza.
W ostatnim wierszu znajduja sie figury gracza czarnego, w tej samej
kolejnosci.

Uwaga 1: zadanie trzeba rozwiazac obiektowo. Nalezy unikac powtarzania kodu
lub pisania wielokrotnie podobnych fragmentow.

Uwaga 2: hierarchia klas powinna umozliwiac latwe rozszerzenie o nowe
rodzaje bierek i graczy.

Pytania do tresci zadania prosze kierowac na adres:

zaroda@mimuw.edu.pl

A oto rozwiązanie:

#include 
#include 
#include 
#include 
#include 



using namespace std;

class Pionek;
class Gracz;


//struktura przechowujaca mozliwy ruch.
typedef struct Ruch{
	Pionek* pionek;
	int x; //Wiersz docelowy
	int y; //Kolumna docelowa
	int bicie; //Czy bicie.
} Ruch;

//dlugosc boku planszy
#define ROZMIAR_PLANSZY 8




//Nadklasa dla Gracza.
class Gracz {
	protected:
		char nawias_start;	//Poczatek nawiasu zaznaczajacego gracza
		char nawias_stop;	// Koniec tegoz.
	
	public:
		vector Pionki;	//Pionki gracza pozostajace na planszy
		string nazwa_gracza;	//Nazwa gracza.
		void Usun(Pionek*);		//Usuwa pionek z listy pionkow.
		void inicjuj(string nazwa_gracza,char nawias_start,char nawias_stop);
		virtual int Ruch(Pionek* plansza[ROZMIAR_PLANSZY][ROZMIAR_PLANSZY]);	//Rusza graczem
		string Wypisz(string pionek);									// Wypisuje pionek gracza
		int WykonajRuch(struct Ruch rusz,Pionek* plansza[ROZMIAR_PLANSZY][ROZMIAR_PLANSZY]);	// Fizycznie wykonuje ruch
};


//nadklasa dla pionka
class Pionek
{
	public:
		int x; //wiersz planszy
		int y;//kolumna planszy
		int WyprobujRuch(vector* ruchy,Pionek* plansza[ROZMIAR_PLANSZY][ROZMIAR_PLANSZY],int x,int y);
		Gracz* gracz;
		virtual vector MozliweRuchy(Pionek* plansza[ROZMIAR_PLANSZY][ROZMIAR_PLANSZY]);	//Mozliwe ruchy pionka
		void Zbij();	//Usuwa pionek
		void inicjuj(int i,int j,Gracz* gracz);
		string nazwa;
		virtual string Wypisz();
};

// klasa główna - gra
class Gra 
{

	private:
		int numer_ruchu;
		int ograniczenie;		//Ograniczenie na ilosc ruchow.
		Pionek* plansza[ROZMIAR_PLANSZY][ROZMIAR_PLANSZY];
		Gracz* gracz1;
		Gracz* gracz2;
	public:
		Gra(Gracz* gracz1,Gracz* gracz2,int ograniczenie)
		{
			this->gracz1=gracz1;
			this->gracz2=gracz2;
			this->ograniczenie=ograniczenie;

			for(int i=0;i<ROZMIAR_PLANSZY;i++)
			{
				for(int j=0;j<ROZMIAR_PLANSZY;j++)
				{
					plansza[i][j]=NULL;
				}
			}
			
			// umieszczanie pionkow na planszy.
			
			for(unsigned int i=0;i Pionki.size(); i++)
			{
				plansza[gracz1->Pionki.at(i)->x][gracz1->Pionki.at(i)->y]=gracz1->Pionki.at(i);
			}

			for(unsigned int i=0;i Pionki.size(); i++)
			{
				plansza[gracz2->Pionki.at(i)->x][gracz2->Pionki.at(i)->y]=gracz2->Pionki.at(i);
			}
			//pionki umieszczone.
			
		}
		int Ruch();
		void Wypisz(); //Wypisuje stan planszy
};



// Metody GRA

	int Gra::Ruch()
			{

				cout << "Ruch " << numer_ruchu << ": n";

				if((numer_ruchu Ruch(plansza) && gracz2->Ruch(plansza))
				{
					Wypisz();
					numer_ruchu++;

					if(gracz1->Pionki.size()==0)
					{
						//wygral gracz 2.
						cout << "Wygral gracz '" <nazwa_gracza <Pionki.size()==0)
					{
						//wygral gracz 1.
						cout << "Wygral gracz '" <nazwa_gracza << "' Gratulacje! n";
						return 0;
					}
					else
					{
						//Gramy dalej
						return 1;
					}
				}
				else
				{
					cout << "REMIS!! n";
					return 0;
				}
			}

			
	void Gra::Wypisz() //Wypisuje stan planszy
			{
				int i,j,k;
				
				cout << "nn";
				
				//gorna sciana planszy
				cout << "#";
				for(k=0;k<ROZMIAR_PLANSZY;k++)
				{
					cout <<"##"<< k+1 <<"###";
				}
				
				
				//kolejne wiersze planszy
				for (i=0;i<ROZMIAR_PLANSZY;i++)
				{
					cout << "n#";
					for(k=0;k<ROZMIAR_PLANSZY;k++)
					{
						cout <<"     #";
					}
					cout << "n"<< (char)('A'+i);
					
					for(j=0;j<ROZMIAR_PLANSZY;j++)
					{
						cout<<' ';
						
						if(plansza[i][j]!=NULL)
						{
							//jest tu jakis pionek.
							cout <Wypisz();
						}
						else
						{
							cout << "   ";
						}

						cout << " #";
					}
					
					cout << "n#";
					for(k=0;k<ROZMIAR_PLANSZY;k++)
					{
						cout <<"     #";
					}

					cout << 'n';
					
					for(k=0;k<ROZMIAR_PLANSZY;k++)
					{
						cout <<"######";
					}
					cout << "#";
				}
				
				cout <nazwa_gracza=nazwa_gracza;
			this->nawias_start=nawias_start;
			this->nawias_stop=nawias_stop;
		}

	int Gracz::WykonajRuch(struct Ruch rusz,Pionek* plansza[ROZMIAR_PLANSZY][ROZMIAR_PLANSZY])
			{	//przesuwa pionek, na razie bez bicia.
				
				string bicie="";

				if(plansza[rusz.x][rusz.y]!=NULL)
				{
					//Cos tu jest. Zakladam ze bicie.
					plansza[rusz.x][rusz.y]->Zbij();
					bicie=" (bicie)";
				}

				cout << "Gracz '"<nazwa_gracza <<"': "<nazwa <<"  z [" <x) <y+1 <<"] na [" << (char)('A'+rusz.x) << rusz.y+1 <<"]"<< bicie <x][rusz.pionek->y]=NULL;
				rusz.pionek->x=rusz.x;
				rusz.pionek->y=rusz.y;

				return 1;
			}

	void Gracz::Usun(Pionek* pionek)
			{	//Usuwa pionek z listy.
				unsigned int i=0;

				while((i Pionki.size())&&(this->Pionki.at(i)!=pionek))
				{
					i++;
				}

				if(i Pionki.size())
				{
					//znaleziono
					//usuwamy.
					this->Pionki.erase(this->Pionki.begin()+i,this->Pionki.begin()+i+1);
				}
			}


	string Gracz::Wypisz(string pionek)
			{
				string wynik="";
				wynik=nawias_start+pionek+nawias_stop;
				return wynik;
			}


//Koniec metod GRACZ
//METODY PIONEK
	vector Pionek::MozliweRuchy(Pionek* plansza[ROZMIAR_PLANSZY][ROZMIAR_PLANSZY])
	{
		vector zwroc;
		//Bez tego linker g++ się sypie.
		return zwroc;
	}

	void Pionek::inicjuj(int i,int j,Gracz* gracz)
		{
			this->x=i;
			this->y=j;
			this->gracz=gracz;
			gracz->Pionki.push_back(this);
		}
	string Pionek::Wypisz()
		{
			return gracz->Wypisz("|");
		}

	void Pionek::Zbij()
		{
			//Jak nietrudno się domyślić zbija pionek.
			this->gracz->Usun(this);
		}


	int Pionek::WyprobujRuch(vector* ruchy,Pionek* plansza[ROZMIAR_PLANSZY][ROZMIAR_PLANSZY],int i,int j)
	{

		Ruch gdzie;
 		if((i>=ROZMIAR_PLANSZY)||(i=ROZMIAR_PLANSZY)||(jpush_back(gdzie);
			return 1;
	
		}
		else if(plansza[i][j]->gracz!=this->gracz)
		{
			//Obcy gracz
			gdzie.pionek=this;
			gdzie.x=i;
			gdzie.y=j;
			gdzie.bicie=1;
			ruchy->push_back(gdzie);
			return 0;
		}
		else
		{
			return 0;
		}

	}

//Koniec metod pionek.
// Wszystkie nadklasy zostaly zadeklarowane. Teraz zrobimy podklasy.
// Najpierw gracze.

	class Losowy: public Gracz
	{
		public:
		int Ruch(Pionek* plansza[ROZMIAR_PLANSZY][ROZMIAR_PLANSZY]);
		Losowy(string nazwa_gracza,char nawias_start,char nawias_stop)
		{
			inicjuj(nazwa_gracza,nawias_start,nawias_stop);
		}
	};

	int Losowy::Ruch(Pionek* plansza[ROZMIAR_PLANSZY][ROZMIAR_PLANSZY])
	{
		vector tmp;
		vector mozliwe_ruchy;

		for(unsigned int i=0;i Pionki.size(); i++)
		{		
			tmp=this->Pionki.at(i)->MozliweRuchy(plansza);
			mozliwe_ruchy.insert(mozliwe_ruchy.end(),tmp.begin(),tmp.end());
			tmp.clear();
		}

		

		if(mozliwe_ruchy.size()>0)
		{
			//jesli sa ruchy do wykonania.
			int losowa = rand()%(int)mozliwe_ruchy.size();
			return WykonajRuch(mozliwe_ruchy[losowa],plansza);
		}
		else
		{
			return 0;
		}
	}




	class Leniwy: public Gracz
	{
		public:
		int krawedz ; // Krawedz okreslana jako 'nalezaca'  do gracza.
		int Ruch(Pionek* plansza[ROZMIAR_PLANSZY][ROZMIAR_PLANSZY]);
		Leniwy(string nazwa_gracza,char nawias_start,char nawias_stop,int krawedz)
		{
			this->krawedz=krawedz;
			inicjuj(nazwa_gracza,nawias_start,nawias_stop);
		}
	};

	int Leniwy::Ruch(Pionek* plansza[ROZMIAR_PLANSZY][ROZMIAR_PLANSZY])
	{
		int najblizej = ROZMIAR_PLANSZY+1;		//Odleglosc do najblizszej bierki.
		Pionek* najblizszy = NULL;				//Najblizsza bierka
		vector tmp;
		vector mozliwe_ruchy;
		int odleglosc;

		for(unsigned int i=0;i Pionki.size(); i++)
		{		
			tmp=this->Pionki.at(i)->MozliweRuchy(plansza);
			odleglosc=this->krawedz-(Pionki.at(i)->x);

			if(odleglosc0)&&(odlegloscMozliweRuchy(plansza); //Jego mozliwe ruchy.
			unsigned int i=0;
			while((i<tmp.size())&&(tmp.at(i).bicie==0))
			{
				i++;
			}

			if(i<tmp.size()) //Znalezlismy ruch z biciem.
			{
				return WykonajRuch(tmp.at(i),plansza);
			}
			else	// Nie ma bicia, ale losowy ruch.
			{
				int losowa = rand()%(int)tmp.size();
				return WykonajRuch(tmp[losowa],plansza);
			}
		}
		else
		{
			return 0;
		}
	}



// Teraz pionki.



	class Wieza:public Pionek
	{
		public:
		vector MozliweRuchy(Pionek* plansza[ROZMIAR_PLANSZY][ROZMIAR_PLANSZY]);
		string Wypisz();
		Wieza (int i,int j,Gracz* gracz)
		{
			inicjuj(i,j,gracz);
			this->nazwa="Wieża";
		}
	};

	vector Wieza::MozliweRuchy(Pionek* plansza[ROZMIAR_PLANSZY][ROZMIAR_PLANSZY])
	{
		vector ruchy;
		int i;

		//Skaczemy po wierszach
		i=y+1;
		while(WyprobujRuch(&ruchy,plansza,x,i)==1)
		{
			i++;
		}
		i=y-1;
		while(WyprobujRuch(&ruchy,plansza,x,i)==1)
		{
			i=i-1;
		}
		//Skaczemy po kolumnach
		i=x+1;
		while(WyprobujRuch(&ruchy,plansza,i,y)==1)
		{
			i++;
		}
		i=x-1;
		while(WyprobujRuch(&ruchy,plansza,i,y)==1)
		{
			i=i-1;
		}

		return ruchy;
	}

	string Wieza::Wypisz()
	{
		return gracz->Wypisz("W");
	}

	class Skoczek:public Pionek
	{
		public:
		vector MozliweRuchy(Pionek* plansza[ROZMIAR_PLANSZY][ROZMIAR_PLANSZY]);
		string Wypisz();
		Skoczek (int i,int j,Gracz* gracz)
		{
			inicjuj(i,j,gracz);
			this->nazwa="Skoczek";
		}
	};

	vector Skoczek::MozliweRuchy(Pionek* plansza[ROZMIAR_PLANSZY][ROZMIAR_PLANSZY])
	{
		vector ruchy;

		WyprobujRuch(&ruchy,plansza,x+2,y-1);
		WyprobujRuch(&ruchy,plansza,x+2,y+1);
		WyprobujRuch(&ruchy,plansza,x-2,y-1);
		WyprobujRuch(&ruchy,plansza,x-2,y+1);
		WyprobujRuch(&ruchy,plansza,x+1,y+2);
		WyprobujRuch(&ruchy,plansza,x+1,y-2);
		WyprobujRuch(&ruchy,plansza,x-1,y+2);
		WyprobujRuch(&ruchy,plansza,x-1,y-2);

		return ruchy;
	}

	string Skoczek::Wypisz()
	{
		return gracz->Wypisz("S");
	}



	class Krol:public Pionek
	{
		public:
		vector MozliweRuchy(Pionek* plansza[ROZMIAR_PLANSZY][ROZMIAR_PLANSZY]);
		string Wypisz();
		Krol (int i,int j,Gracz* gracz)
		{
			inicjuj(i,j,gracz);
			this->nazwa="Król";
		}
	};

	vector Krol::MozliweRuchy(Pionek* plansza[ROZMIAR_PLANSZY][ROZMIAR_PLANSZY])
	{
		vector ruchy;

		WyprobujRuch(&ruchy,plansza,x-1,y-1);
		WyprobujRuch(&ruchy,plansza,x,y-1);
		WyprobujRuch(&ruchy,plansza,x+1,y-1);
		WyprobujRuch(&ruchy,plansza,x-1,y);
		WyprobujRuch(&ruchy,plansza,x+1,y);
		WyprobujRuch(&ruchy,plansza,x-1,y+1);
		WyprobujRuch(&ruchy,plansza,x,y+1);
		WyprobujRuch(&ruchy,plansza,x+1,y+1);

		return ruchy;
	}

	string Krol::Wypisz()
	{
		return gracz->Wypisz("K");
	}



	class Goniec:public Pionek
	{
		public:
		vector MozliweRuchy(Pionek* plansza[ROZMIAR_PLANSZY][ROZMIAR_PLANSZY]);
		string Wypisz();
		Goniec (int i,int j,Gracz* gracz)
		{
			inicjuj(i,j,gracz);
			this->nazwa="Goniec";
		}
	};

	vector Goniec::MozliweRuchy(Pionek* plansza[ROZMIAR_PLANSZY][ROZMIAR_PLANSZY])
	{
		vector ruchy;
		int i;

		//W prawy gorny rog
		i=1;
		while(WyprobujRuch(&ruchy,plansza,x+i,y+i)==1)
		{
			i++;
		}
		i=1;
		// W lewy dolny
		while(WyprobujRuch(&ruchy,plansza,x-i,y-i)==1)
		{
			i++;
		}
		//W prawy dolny
		i=1;
		while(WyprobujRuch(&ruchy,plansza,x+i,y-i)==1)
		{
			i++;
		}
		i=1;
		// W lewy gorny
		while(WyprobujRuch(&ruchy,plansza,x-i,y+i)==1)
		{
			i++;
		}

		return ruchy;
	}

	string Goniec::Wypisz()
	{
		return gracz->Wypisz("G");
	}



	class Hetman:public Pionek
	{
		public:
		vector MozliweRuchy(Pionek* plansza[ROZMIAR_PLANSZY][ROZMIAR_PLANSZY]);
		string Wypisz();
		Hetman (int i,int j,Gracz* gracz)
		{
			inicjuj(i,j,gracz);
			this->nazwa="Hetman";
		}
	};

	vector Hetman::MozliweRuchy(Pionek* plansza[ROZMIAR_PLANSZY][ROZMIAR_PLANSZY])
	{
		vector ruchy;
		int i;

		//W prawy gorny rog
		i=1;
		while(WyprobujRuch(&ruchy,plansza,x+i,y+i)==1)
		{
			i++;
		}
		i=1;
		//W lewy dolny
		while(WyprobujRuch(&ruchy,plansza,x-i,y-i)==1)
		{
			i++;
		}
		//W lewy dolny
		i=1;
		while(WyprobujRuch(&ruchy,plansza,x+i,y-i)==1)
		{
			i++;
		}
		i=1;
		// W lewy gorny
		while(WyprobujRuch(&ruchy,plansza,x-i,y+i)==1)
		{
			i++;
		}

		//Skaczemy po wierszach
		i=y+1;
		while(WyprobujRuch(&ruchy,plansza,x,i)==1)
		{
			i++;
		}
		i=y-1;
		while(WyprobujRuch(&ruchy,plansza,x,i)==1)
		{
			i=i-1;
		}
		//Skaczemy po kolumnach
		i=x+1;
		while(WyprobujRuch(&ruchy,plansza,i,y)==1)
		{
			i++;
		}
		i=x-1;
		while(WyprobujRuch(&ruchy,plansza,i,y)==1)
		{
			i=i-1;
		}

		return ruchy;
	}

	string Hetman::Wypisz()
	{
		return gracz->Wypisz("H");
	}
/****************************************************************
*********************** --- MAIN --- ****************************
****************************************************************/

int main(int argc, char **argv) {

	Gracz* gracz1;
	Gracz* gracz2;
	Gra* gierka;

	//Inicjalizujemy generator liczb pseudolosowych.
	srand(time(NULL));

	//Tworzymy graczy
	gracz1 = new Losowy("Biały",'[',']');
	gracz2 = new Leniwy("Czarny",'{','}',7);

	//Rozmieszczamy pionki gracza 1
	new Wieza(0,0,gracz1);
	new Skoczek(0,1,gracz1);
	new Goniec(0,2,gracz1);
	new Hetman(0,3,gracz1);
	new Krol(0,4,gracz1);
	new Goniec(0,5,gracz1);
	new Skoczek(0,6,gracz1);
	new Wieza(0,7,gracz1);

	//Rozmieszczamy pionki gracza 2
	new Wieza(7,0,gracz2);
	new Skoczek(7,1,gracz2);
	new Goniec(7,2,gracz2);
	new Hetman(7,4,gracz2);
	new Krol(7,3,gracz2);
	new Goniec(7,5,gracz2);
	new Skoczek(7,6,gracz2);
	new Wieza(7,7,gracz2);
	//Tworzymy
	gierka=new Gra(gracz1,gracz2,500);
	//No i siup!
	while(gierka->Ruch())
	{
	}

return 0;
}


Leave a Reply