Tablica 3- wymiarowa [wiersz][komórka][2], a zapisane dane w 3 wymiarze

0

Witam serdecznie!

Na wstępie pragnę poinformować, iż uczę się c++ z Symfonii C++ J. Grębosza oraz poradnika "Od zera do gier kodera" Xiona. Staram się czytać po działach, dlatego, że w poradniku Xiona na końcu są zadania ;)

Przerabilem teraz: http://xion.org.pl/files/texts/mgt/pdf/1_5.pdf

Jest tam zadanie: (Bardzo trudne) Ulepsz napisaną grę. Niech rozmiar planszy nie będzie zawsze
wynosił 3×3, lecz mógł być zdefiniowany jako stała w pliku game.h.
Wskazówka: ponieważ plansza pozostanie kwadratem, warunkiem zwycięstwa
będzie nadal ułożenie linii poziomej, pionowej lub ukośnej z własnych symboli.
Modyfikacji musi jednak ulec algorytm sprawdzania planszy (ten straszny :D) oraz
sposób numerowania i rysowania pól.

Wiem, że może nie mówi to dużo, ale nie jest to do końca ważne dla mojego problemu.

PROBLEM:

W pliku game.h mam zapisane między innymi:

const unsigned ile_pol = 3;

W game.cpp znajduje się przedstawienie linii tablicy(potrzebne mi to w dalszej części kodu do sprawdzenia linii w pionie, poziomie i na ukos w celu wyłapania wygranej/remisu), przy ile_pol = 3 wygląda to tak:

 const unsigned int LINIE[((ile_pol*2)+2)][ile_pol][2] = { { { 0,0 }, { 0,1 }, { 0,2 } }, //gorna pozioma
                                                           { { 1,0 }, { 1,1 }, { 1,2 } }, //srodkowa pozioma
                                                           { { 2,0 }, { 2,1 }, { 2,2 } }, //dolna pozioma
                                                           { { 0,0 }, { 1,0 }, { 2,0 } }, //lewa pionowa 
                                                           { { 0,1 }, { 1,1 }, { 2,1 } }, //srodkowa pionowa
                                                           { { 0,2 }, { 1,2 }, { 2,2 } }, //prawa pionowa
                                                           { { 0,0 }, { 1,1 }, { 2,2 } }, //ukosna lewa  
                                                           { { 2,0 }, { 1,1 }, { 0,2 } } }; //ukosna prawa

Wszystko działa jak należy przy ile_pol = 3.

  • Niestety nie mam pomysłu jak to powinno wyglądać (a co za tym idzie - jak zrobić), **aby 3 wymiarowa tablica LINIE [][][koordynaty] ** dostosowywała te kordynaty w odpowiednim miejscu odpowiednio do ile_pol;(
    (Jeżeli chodzi o "resztę" gry wszystko ulepszyłem tak, że dostosowuje się do ile_pol i odpowiednio wyświetla planszę gry)

  • Wiadomo, do

 const unsigned ile_pol = 4

wierszy powinno być 10, kolumn 4, a kordynaty z zakresu 0-3 odpowiednio ulozone... ale jak? :D

Domniemam, że może to być przypisywanie zmiennych poprzez pętlę lub zastosowanie 'vector' o których nie mam zbytnio pojęcia w tej chwili. Jeżeli to będzie pasowało z chęcią uzupełnię swoją wiedzę w trybie natychmiastowym ;) Tak czy inaczej, najpierw muszę uzyskać informacji jak powinienem uzyskać oczekiwany rezultat i zabiorę się do roboty!!

Z góry dziękuję, miłego dnia!

PS stała ile_pol jest określana w programie, nie na bieżąco, z czego stwierdziłem, że użycie 'vector' nie jest konieczne (oczywiście mogę się mylić, uczę się :) )

Nie wiem czy dobrze myślę, ale wymyśliłem takie coś:

 	for (unsigned a = 0; a < ((ile_pol*2)+2); a++);
		{
			for (unsigned i = 0; i < ile_pol; i++)
			{	
				for (unsigned j = 0; j < ile_pol; j++)
				{
					LINIE[a][i][j] = a, j;
				}
			}
		}

tylko muszę to jeszcze dobrze połączyć i sprawdzić czy działa.

 const unsigned int LINIE[((ile_pol*2)+2)][ile_pol][2] = 
                                                           //{ { { 0,0 }, { 0,1 }, { 0,2 } }, //gorna pozioma
                                                       //    { { 1,0 }, { 1,1 }, { 1,2 } }, //srodkowa pozioma
                                                       //    { { 2,0 }, { 2,1 }, { 2,2 } }, //dolna pozioma
                                                        //   { { 0,0 }, { 1,0 }, { 2,0 } }, //lewa pionowa 
                                                       //    { { 0,1 }, { 1,1 }, { 2,1 } }, //srodkowa pionowa
                                                        //   { { 0,2 }, { 1,2 }, { 2,2 } }, //prawa pionowa
                                                        //   { { 0,0 }, { 1,1 }, { 2,2 } }, //ukosna lewa  
                                                        //   { { 2,0 }, { 1,1 }, { 0,2 } } }; //ukosna prawa
	
		for (unsigned a = 0; a < ((ile_pol*2)+2); a++);
		{
			for (unsigned i = 0; i < ile_pol; i++)
			{	
				for (unsigned j = 0; j < ile_pol; j++)
				{
					LINIE[a][i][j] = a, j;
				}
			}
		}
0

Daruj sobie ten tutorial. To, co tu wypisujesz... dobrze się czujesz?
Do takiej gry wystarczy jednowymiarowa tablica, ale może być i dwuwymiarowa (łatwiej ogarnąć). No i jeden typ wyliczeniowy określający stan pola. Rozmiar planszy (zawsze kwadrat) nie ma znaczenia. Algorytm pozostanie taki sam.

0

Daruj sobie ten tutorial. To, co tu wypisujesz... dobrze się czujesz?

O co się rozchodzi? :)

Do takiej gry wystarczy jednowymiarowa tablica, ale może być i dwuwymiarowa (łatwiej ogarnąć). No i jeden typ wyliczeniowy określający stan pola. Rozmiar planszy (zawsze kwadrat) nie ma znaczenia. Algorytm pozostanie taki sam.

Cała plansza wygląda tak:

FIELD g_aPlansza[ile_pol][ile_pol];

standardowo zapisanych FLD_EMPTY

Zapis z game.h:

 enum SIGN { SGN_CIRCLE = 'O', SGN_CROSS = 'X' };
 enum FIELD { FLD_EMPTY, 
	      FLD_CIRCLE = SGN_CIRCLE,
	      FLD_CROSS = SGN_CROSS	 };
 enum GAMESTATE { GS_NOTSTARTED, GS_MOVE, GS_WON, GS_DRAW };
2

Zrezygnuj z tablicy LINIE i wyznaczaj współrzędne algorytmicznie.

Warto wyrazić linię w ogólny sposób np. współrzędne początku i kierunek:

struct Linia {
    int start_x;
    int start_y;
    int kierunek_x;
    int kierunek_y;
};

Za pomocą algorytmu wyznaczasz kolejne linie i podajesz je do funkcji sprawdzającej. Dla przykładu, wszystkie linie poziome:

Linia linia;
bool znaleziono = false;
/* linie poziome */
linia.kierunek_x = 1;
linia.kierunek_y = 0;
linia.start_x = 0;
for (int i = 0; i < ile_pol && !znaleziono; i++) {
    linia.start_y = i;
    znaleziono = SprawdzLinie(linia);
}
/* linie pionowe */
...
0

Dzięki za odpowiedź ;)

W tej chwili muszę wyjść, wrócę to od razu zabieram się za edycję :)

Cały czas chodził mi ten projekt po głowie :D
Nie robiłem tak jak mi podpowiedziałeś, przekształciłem to co miałem, tak jak to wymyśliłem w czasie nieobecności :P

 unsigned LINIE [((ile_pol*2)+2)] [ile_pol] [2];

	//poziome
				for (unsigned k = 0; k < ile_pol; k++) //0,1,2
				{
					for (unsigned x = 0; x < ile_pol; x++)
					{	
							LINIE[k][x][0] = k;
							LINIE[k][x][1] = x;
					}
				}
	//pionowe
				for (unsigned g = 0 + ile_pol; g < (ile_pol + ile_pol); g++) //3,4,5
				{
					for (unsigned h = 0; h < ile_pol; h++)
					{	
							LINIE[g][h][0] = h;
							LINIE[g][h][1] = g - ile_pol;
					}
				}
	//na ukos lewa
				for (unsigned u = (ile_pol + ile_pol) ; u == (ile_pol + ile_pol) ; u++) //6
				{
					for (unsigned r = 0; r < ile_pol; r++)
					{	
							LINIE[u][r][0] = r;
							LINIE[u][r][1] = r;
					}
				}
	//prawa	
			unsigned znak = ile_pol-1;  //zrobilem nowa zmienna, poniewaz wszystkie inne beda rosnac, a ta musi malec (idzie od gory - prawa do dol - lewa)
				for (unsigned u = ((ile_pol + ile_pol) +1) ; u == ((ile_pol + ile_pol) + 1) ; u++) //7
				{
					for (unsigned r = 0; r < ile_pol; r++)
					{	
							LINIE[u][r][0] = znak;
							LINIE[u][r][1] = r;
						znak--;
					}
				}

Wszystko działa jak należy, jestem z siebie dumny!!! :D

Zaraz tylko dodać muszę opcje wyjścia z gry podczas gry :P

Jeżeli ktoś zechciałby przetestować program podaję kod:

game.h

enum SIGN { SGN_CIRCLE = 'O', SGN_CROSS = 'X' };
enum FIELD { FLD_EMPTY, 
			 FLD_CIRCLE = SGN_CIRCLE,
			 FLD_CROSS = SGN_CROSS	 };
enum GAMESTATE { GS_NOTSTARTED, GS_MOVE, GS_WON, GS_DRAW };

extern GAMESTATE g_StanGry; 


bool StartGry();


bool Ruch(unsigned);


bool RysujPlansze();

//Ile Pol

//gra dobrze wyglada przy 1(3) do 10 pol
const unsigned ile_pol = 3; 

game.cpp

#include <iostream>
#include <ctime>
#include "game.h"

using namespace std;


FIELD g_aPlansza[ile_pol][ile_pol];

GAMESTATE g_StanGry = GS_NOTSTARTED;

SIGN g_AktualnyGracz;

bool StartGry()
{
	if (g_StanGry != GS_NOTSTARTED) return false;

	//Losujemy gracza, ktory bedzie zaczynal
	srand(static_cast<unsigned>(time(NULL)));
	g_AktualnyGracz = (rand() % 2 == 0 ? SGN_CIRCLE : SGN_CROSS);

	//Ustawiamy stan gry na ruch graczy
	g_StanGry = GS_MOVE;

	return true;
}



bool Ruch(unsigned uNumerPola)
{
	//a = zabezpieczenie przed ponownym wywolaniem funkcji petli do tworzenia pola
	
	unsigned l = 2;
	if (l == 1)
	{
		for (unsigned a = 0; a < (ile_pol*ile_pol); a++);
		{
			for (unsigned i = 0; i < ile_pol; i++)
			{	
				for (unsigned j = 0; j < ile_pol; j++)
				{
					g_aPlansza[i][j] = FLD_EMPTY;
				}
			}
			l = 1;
			return l;
		}
	}
	
		if(!(cin))  //jezeli podane cos, co nie pasuje do INT to reset i wycofanie podanego znaku
		{
			cin.clear();
			cin.ignore();
			return false;
		}
	if (g_StanGry != GS_MOVE) return false;
	if (! (uNumerPola >= 1 && uNumerPola <= (ile_pol*ile_pol))) return false;



	unsigned uY = (uNumerPola - 1) / ile_pol;
	unsigned uX = (uNumerPola - 1) % ile_pol;

	if (g_aPlansza[uY][uX] == FLD_EMPTY)
		g_aPlansza[uY][uX] = static_cast<FIELD>(g_AktualnyGracz);
	else
		return false;

	//linie tablicy
	unsigned LINIE [((ile_pol*2)+2)] [ile_pol] [2];
									
	//poziome
				for (unsigned k = 0; k < ile_pol; k++) 
				{
					for (unsigned x = 0; x < ile_pol; x++)
					{	
							LINIE[k][x][0] = k;
							LINIE[k][x][1] = x;
					}
				}
	//pionowe
				for (unsigned g = 0 + ile_pol; g < (ile_pol + ile_pol); g++) 
				{
					for (unsigned h = 0; h < ile_pol; h++)
					{	
							LINIE[g][h][0] = h;
							LINIE[g][h][1] = g - ile_pol;
					}
				}
	//na ukos lewa
				for (unsigned u = (ile_pol + ile_pol) ; u == (ile_pol + ile_pol) ; u++)
				{
					for (unsigned r = 0; r < ile_pol; r++)
					{	
							LINIE[u][r][0] = r;
							LINIE[u][r][1] = r;
					}
				}
	//prawa	
			unsigned znak = ile_pol-1;  //zrobilem nowa zmienna, poniewaz wszystkie inne beda rosnac, a ta musi malec (idzie od gory - prawa do dol - lewa)
				for (unsigned u = ((ile_pol + ile_pol) +1) ; u == ((ile_pol + ile_pol) + 1) ; u++) //7
				{
					for (unsigned r = 0; r < ile_pol; r++)
					{	
							LINIE[u][r][0] = znak;
							LINIE[u][r][1] = r;
						znak--;
					}
				}


	//szukanie lini wypelnionych tymi samymi znakami
	
	FIELD Pole, ZgodnePole;
	unsigned uLiczbaZgodnychPol;
	
for (int i = 0; i < ((ile_pol*2)+2); ++i) // ((ile_pol*2)+2)  pion poziom + 2 ukośne
{
		//i przebiega po kolejnych mozliwych liniach (jest ich 8)
		
		//zerujemy zmienne pomocnicze
		Pole = ZgodnePole = FLD_EMPTY; //obie zmienne == FLD_EMPTY
		uLiczbaZgodnychPol = 0;
		
		for (int j = 0; j < ile_pol; ++j)
		{
			//j przebiega po  polach w kazdej lini
			//pobieramy rzeczone pole
			//to zdecydowanie najbardziej wyrazenie
			Pole = g_aPlansza[LINIE[i][j][0]][LINIE[i][j][1]];
				
			if (!(Pole == ZgodnePole))
			{
				ZgodnePole = Pole;
				uLiczbaZgodnychPol = 1;
			}
			else
				//jesli natomiast oba pola sie zgadzaja 
				//to inkrementujemy licznik takich zgodnych pol
			++uLiczbaZgodnychPol;
		}		
		
		//teraz sprawdzamy, czy udalo nam sie zgodzic linie
		if (uLiczbaZgodnychPol == ile_pol && ZgodnePole != FLD_EMPTY)
		{
			g_StanGry = GS_WON;
	
			//przerywamy petle i funkcje
			return true;
		}
	}
	
	
	//wszystko zapelnione == remis
	
	unsigned uLiczbaZapelnionychPol = 0;
	
	for (int i = 0; i < ile_pol; ++i)
		for (int j = 0; j < ile_pol; ++j)
			if (g_aPlansza[i][j] != FLD_EMPTY)
				++uLiczbaZapelnionychPol;
	if (uLiczbaZapelnionychPol == ile_pol*ile_pol)
	{
		g_StanGry = GS_DRAW;
		return true;
	}
	
	
	//zmiana gracza
	
	g_AktualnyGracz = (g_AktualnyGracz == SGN_CIRCLE ? SGN_CROSS : SGN_CIRCLE);
	
	return true;
}

bool RysujPlansze()
{
	if (g_StanGry == GS_NOTSTARTED) return false;

	system ("cls");

	cout << "     KOLKO I KRZYZYK     " << endl;
	cout <<"-----------------------------" << endl;
	cout << endl;
	
	for (int i = 0; i < ile_pol; ++i)
	{
		//lewa czesc ramki
		cout << "        |";

		//wiersz
		for (int j = 0; j < ile_pol; ++j)
		{
			if (g_aPlansza[i][j] == FLD_EMPTY)
			
				//numer pola
				if(i * ile_pol + j + 1 > 99)
				{
					cout << i * ile_pol + j + 1;
				}
				else if(i * ile_pol + j + 1 < 10)
				{
					cout << i * ile_pol + j + 1 << "  ";
				}
				else
				{
					cout << i * ile_pol + j + 1 << " ";
				}
			else
				cout << static_cast<char>(g_aPlansza[i][j]) << "  ";
		}
	
	//prawa czesc ramki
		cout << "|" << endl;
	}
	cout << endl;

	//napisy pod plansza
	switch (g_StanGry)
	{
		case GS_MOVE:
			cout << "Podaj numer pola, w ktorym" << endl;
			cout << "chcesz postawic ";
			cout << (g_AktualnyGracz == SGN_CIRCLE ? "kolko" : "krzyzyk") << ": ";
			
			break;

			//wygrana
		case GS_WON: 
			cout << "Wygral gracz stawiajacy ";
			cout << (g_AktualnyGracz == SGN_CIRCLE ? "kolka" : "krzyzyki") << "!";

			break;


			//remis
		case GS_DRAW:
			cout << "Remis!";
			break;

	}
     return true;
} 

main.cpp

#include <iostream>
#include <conio.h>
#include "game.h"

using namespace std;

int main()
{
	cout << "     KOLKO I KRZYZYK     " << endl;
	cout <<"-----------------------------" << endl;
	cout <<"Gra dla 2-ch graczy. Podaj nr" << endl;
	cout <<"pola na ktorym chcesz postawic"<< endl;
	cout <<"KOLKO lub KRZYZYK." << endl << endl;
	cout <<"Podczas wybierania pola wybierz" << endl;
	cout <<"'0' aby wyjsc z gry. Powodzenia!" << endl;
	
	_getch();
	
	StartGry();
	
	for (;;)
	{
		RysujPlansze();

		if (g_StanGry == GS_MOVE)
		{
			unsigned uNumerPola;
			cin >> uNumerPola;
				if (uNumerPola == 0)
				{
					break;
				}
			
			Ruch (uNumerPola); 
		}
		else if (g_StanGry == GS_WON || g_StanGry == GS_DRAW)
			break;
	}
	cout << "\nNacisnij dowolny klawisz...";
	_getch();
	return 0;
} 

Ehh to skończone, problem rozwiązany. Dziękuję za pomysły rozwiązania problemu. Wracam do przerabiania Symfonii c++!! Hej! :D

0

Przede wszystkim chodzi mi o to, że patrząc na odpowiedzi które zaczynają się od "Chodziłeś do lekarza? Jeśli tak to go zmień, bo nic ci nie pomógl.", "To, co tu wypisujesz... dobrze się czujesz?", "A z Grębosza co konkretnie przeyczytałeś - tutuł? Bo sądząc po tym kodzie to na tym się skończyłeś." nie są zbytnio kulturalne zwłaszcza jeżeli ktoś jest nowy i nie wie wszystkiego dlatego potraktowałem je raczej jako posty hatera "nie umiesz, nie znasz się, idź stąd!". (stąd ta nagonka). Jeżeli źle to odebrałem - przepraszam, ale tak to odebrałem.

Ja stosowałem się do tutorialu i przerabiałem kod w miejscach, które miałem przerobić, a nie zastanawiałem się nad całością kodu. (Np. po to można obejrzeć tutorial i wtedy ocenić zmiany jakie zastosowałem [ja się cieszę z tego co zrobiłem, ponieważ zrobiłem to okrężną drogą, bardziej zawiłą, ale udało mi się)

Post adf88 uważam za pomocny i również "materiał" w nim zawarty przerobię. A sprawa z tym, iż zrobiłem to najpierw po swojemu jest sprawą ambicji, ponieważ dało się zrobić to po "mojemu" i zgodnie(w pewnym sensie) z tutorialem. Wszystkie odpowiedzi uważam za pomocnicze, a każda nowo zdobyta wiedza jest bardzo wartościowa, zwłaszcza jeżeli nikt w nauce cię nie kieruje.

Wątki na tym forum się zamyka?

W każdym razie, dziękuję za poświęcony mi czas i życzę miłego wieczoru ;)

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