Cześć, muszę przyznać, że mnie zaciekawiłeś tym tematem. Już od dawna miałem się wziąć za naukę SFML a to pytanie będzie dobrą okazją :)
Widzę, że masz sporo pytań dotyczących mechaniki gry, jej okodowania itd, ale zanim zacznę cokolwiek pisać na temat gry chcę Ci przedstawić moją wersję klas Punkt i Plansza. Ty je zostawiłeś puste, i z kilkoma błędami więc pozwoliłem sobie na przygotowanie mojej interpretacji
class Pole
{
public:
Pole(int _value, bool _isNaked, bool _isArmed, bool _isMarked) : value(_value), isNaked(_isNaked), isArmed(_isArmed), isMarked(_isMarked) { }
Pole() : Pole(0, false, false, false) { }
~Pole() { }
int getValue() const { return value; }
bool getIsNaked() const { return isNaked; }
bool getIsArmed() const { return isArmed; }
bool getIsMarked() const { return isMarked; }
void setValue(int _value) { value = _value; }
void setIsNaked(bool _isNaked) { isNaked = _isNaked; }
void setIsArmed(bool _isArmed) { isArmed = _isArmed; }
void setIsMarked(bool _isMarked) { isMarked = _isMarked; }
private:
int value; //wartosc pola
bool isNaked; //jest odkryte ?
bool isArmed; //posiada minę ?
bool isMarked; //jest oznaczona przez gracza ?
};
enum GameState { START, PLAY, END };
class Plansza
{
public:
Plansza(size_t x, size_t y, GameState _s) : gameState(_s) { }
Plansza() : Plansza(10, 10, GameState::START) { }
~Plansza() { }
void setPole(size_t _x, size_t _y, Pole& _p) { board[_x][_y] = _p; };
void setGameState(GameState _s) { gameState = _s; }
Pole& getPole(size_t _x, size_t _y) const { return board[_x][_y]; }
GameState getGameState() const { return gameState; }
private:
vector<vector<Pole>> board;
GameState gameState;
};
Klasa Pole:
Pole(int _value, bool _isNaked, bool _isArmed, bool _isMarked) : value(_value), isNaked(_isNaked), isArmed(_isArmed), isMarked(_isMarked) { }
To jest konstruktor z użyciem http://www.p-programowanie.pl/cpp/lista-inicjalizacyjna/
Pole() : Pole(0, false, false, false) { }
To jest delegowanie konstruktorów - dzięki temu nie muszę pisać wiele razy tego samego.
~Pole() { }
Destruktor jest pusty bo nie alokuję własnoręcznie pamięci, więc nie muszę się martwić o jej zwolnienie
int getValue() const { return value; }
bool getIsNaked() const { return isNaked; }
bool getIsArmed() const { return isArmed; }
bool getIsMarked() const { return isMarked; }
void setValue(int _value) { value = _value; }
void setIsNaked(bool _isNaked) { isNaked = _isNaked; }
void setIsArmed(bool _isArmed) { isArmed = _isArmed; }
void setIsMarked(bool _isMarked) { isMarked = _isMarked; }
To są tzw gettery i settery, chodzi o to, by trzymać pola (inaczej mówiąc zmienne) obiektu z dala od użytkownika. Poczytaj więcej o enkapsulacji danych i napewno zrozumiesz
int value; //wartosc pola
bool isNaked; //jest odkryte ?
bool isArmed; //posiada minę ?
bool isMarked; //jest oznaczona przez gracza ?
Tu mamy faktyczne zmienne naszej klasy. Mają angielskie nazwy bo ładniej wyglądają
value - trzyma liczbę bomb wokół siebie - będziemy ją ustawiać wraz z losowaniem pól które należy uzbroić
isNaked - domyślnie jest ustawiona na 0 czyli że nie jest odkryta (użytkownik nie kliknął na dane pole). Będziemy ją zmieniać gdy użytkownik kliknie na to pole.
isArmed - będzie ustawiana wraz z losowaniem bomb.
isMarked - czy użytkownik oznaczył to pole prawym przyciskiem myszy ? Do tego będzie służyć nam ta zmienna.
Jeśli nadal nie do końca rozumiesz co tu się dzieje - obejrzyj pierwsze trzy odcinki tej serii https://www.youtube.com/playlist?list=PLOYHgt8dIdozvOVheSRb_qPVU-4ZJA7uB
Klasa Plansza
enum GameState { START, PLAY, END };
Wspomniałeś, że program ma zwracać aktualny stan gry więc dodałem takiego enuma, ale nie za bardzo widzę gdzie mógłby się przydać, gra ma po prostu za mało stanów i równie dobrze mógłbym je opisać komentarzami.
Plansza(size_t x, size_t y, GameState _s) : gameState(_s) { }
konstruktor jest narazie pusty, niedługo to poprawię. Zastanów się, co warto byłoby w nim napisać ?
void setPole(size_t _x, size_t _y, Pole& _p) { board[_x][_y] = _p; };
void setGameState(GameState _s) { gameState = _s; }
Pole& getPole(size_t _x, size_t _y) const { return board[_x][_y]; }
GameState getGameState() const { return gameState; }
setPole - ustawia wartości pola na podanych współrzędnych, nic trudnego
getPole - zwraca referencję (znak & po nazwie Pole) do aktualnego pola, a to znaczy, że będziemy mogli wywoływać metody klasy Pole! To nam niesamowicie ułatwi sprawę bo wszystko będzie się pięknie zazębiać :
plansza.getPole(4, 4).setIsArmed(true);
Dlaczego to działa ? Otóż, plansza to obiekt który stworzymy w main'ie.
Zawiera on metodę getPole która zwraca referencję do obiektu Pole
na rzecz którego wywołujemy metodę setIsArmed(true);
Jeśli nie rozumiesz tego co przed chwilą przeczytałeś, to poszukaj trochę informacji o referencjach, i odwoływaniu się do metod składowych obiektu
private:
vector<vector<Pole>> board;
GameState gameState;
Na koniec mamy dwie "zmienne składowe" naszej klasy:
board - obiekt klasy vector o specjalizacji klasy Pole - o co chodzi ? Vector to taka klasa zawarta w standardzie std która umożliwia nam robienie takich fajnych tablic u których nie da się przekroczyć zakresu - nie wystąpi nam błąd "off by one". Oczywiście można to też zrobić w ten sposób :
Punkt[10][10] board;
Ale jest to w kilku sytuacjach problematyczne - przypomnę o tym problemie gdy będziemy pisać funkcję do losowania bomb.