Skip to content

Instantly share code, notes, and snippets.

@Phitherek
Created July 23, 2012 23:12
Show Gist options
  • Save Phitherek/3166846 to your computer and use it in GitHub Desktop.
Save Phitherek/3166846 to your computer and use it in GitHub Desktop.
Minesweeper v. 0.1
// Minesweeper v. 0.1 (c) 2012 by Phitherek_
#include <iostream> // Do streamów IO
#include <cstdlib> // EXIT_SUCCESS i inne przydatne rzeczy z C
#include <iomanip> // Do manipulacji streamem IO - ustawienie szerokości wierszy, aby zwiększyć czytelność planszy
using namespace std; // Odkrycie standardowej przestrzeni nazw - bo nic nam nie będzie kolidować z tą przestrzenią
struct field { // Struktura opisująca pole na planszy:
int bomb; // Czy jest bomba na tym polu? 1 - tak, 0 - nie
int checked; // Czy pole jest odkryte? 1 - tak, 0 - nie
int ba; // Ilość bomb wokół pola
int flag; // Flaga: 0 - brak, 1 - flaga, 2 - flaga jako niepewne (?)
};
char itoa(int i) { // Funkcja zamieniająca liczby na znaki:
if(i == 0) { // Jeżeli i jest 0
return '0'; // zwróć znak 0
} else if(i == 1) { // itd...
return '1';
} else if(i == 2) {
return '2';
} else if(i == 3) {
return '3';
} else if(i == 4) {
return '4';
} else if(i == 5) {
return '5';
} else if(i == 6) {
return '6';
} else if(i == 7) {
return '7';
} else if(i == 8) {
return '8';
} else if(i == 9) {
return '9';
}
}
char convert_printable(field f) { // Funkcja wypisująca pole w formacie możliwym do wyświetlenia na planszy:
if(f.checked == 0) { // Jeżeli pole nie jest odkryte:
if(f.flag == 0) { // Jeżeli nie ma flagi
return '#'; // Zwróć # - znak normalnego zakrytego pola
} else if(f.flag == 1) { // Jeżeli jest normalna flaga
return 'F'; // Zwróć F - znak flagi
} else if(f.flag == 2) { // Jeżeli jest flaga jako niepewne
return '?'; // Zwróć ? - znak flagi jako niepewne
}
} else if(f.checked == 1) { // Jeżeli pole jest odkryte:
if(f.bomb == 0) { // Jeżeli na polu nie ma bomby
return itoa(f.ba); // Zwróć znak oznaczający liczbę bomb wokół pola (konwersja za pomocą powyższej funkcji itoa)
} else { // Jeżeli na polu jest bomba
return 'o'; // Zwróć o - znak bomby
}
}
}
void display_board(field** board, int x, int y) { // Funkcja wyświetlająca planszę
cout << setw(2) << " " << " "; // Wyświetl 2 spacje o szerokości 2
for(int i = 0; i < y; i++) { // Wyświetlenie numerów kolumn
cout << setw(2) << i << " "; // Wyświetl numer kolumny i spację po nim - o szerokości 2
}
cout << endl; // Przejdź do następnej linii
for(int i = 0; i < x; i++) { // Pętla przechodząca po kolejnych wierszach planszy
cout << setw(2) << i << " "; // Wyświetl numer wiersza i spację - o szerokości 2
for(int j = 0; j < y; j++) { // Pętla przechodząca po elementach wiersza
char tp; // Znak do wyświetlenia (ToPrint)
tp = convert_printable(board[i][j]); // Zdobądź znak danego pola za pomocą powyższej funkcji convert_printable
cout << setw(2) << tp << " "; // Wyświetl znak pola i spację - o szerokości 2
}
cout << endl; // Przejdź do następnej linii
}
}
field** uncover_board(field** board, int x, int y) { // Funkcja odsłaniająca wszystkie pola w planszy
for(int i = 0; i < x; i++) { // Dwie pętle przechodzące po planszy
for(int j = 0; j < y; j++) {
board[i][j].checked = 1; // Odsłoń bieżące pole
}
}
return board; // Zwróć odsłoniętą planszę
}
field** uncover(field** board, int x, int y, int i, int j, int* flp) { // Funkcja odsłaniająca pole w planszy
int fl = *flp; // Wyłuskaj wartość licznika pól
if(i > -1 and i < x and j > -1 and j < y) { // Jeżeli nie wyszliśmy poza zakres planszy
if(board[i][j].checked == 0) { // Jeżeli pole nie jest jeszcze odsłonięte
if(board[i][j].ba > 0) { // Jeżeli są jakieś bomby wokół pola
board[i][j].checked = 1; // Odsłoń pole
fl--; // Zmniejsz licznik pól w funkcji
*flp = fl; // Zaktualizuj zewnętrzny licznik pól przez wskaźnik
} else { // Jeżeli nie ma bomb wokół pola
board[i][j].checked = 1; // Odsłoń pole
fl--; // Zmniejsz licznik pól w funkcji
*flp = fl; // Zaktualizuj zewnętrzny licznik pól przez wskaźnik
// Wywołaj rekursywnie funkcję odsłaniającą pole w planszy dla wszystkich pól wokół bieżącego:
board = uncover(board, x, y, i-1, j-1, flp);
board = uncover(board, x, y, i-1, j, flp);
board = uncover(board, x, y, i-1, j+1, flp);
board = uncover(board, x, y, i, j-1, flp);
board = uncover(board, x, y, i, j+1, flp);
board = uncover(board, x, y, i+1, j-1, flp);
board = uncover(board, x, y, i+1, j, flp);
board = uncover(board, x, y, i+1, j+1, flp);
}
}
}
return board; // Zwróć zmienioną planszę
}
field** gen_board(field** board, int x, int y, int l) { // Funkcja generująca planszę
srand(time(NULL)); // Zainicjuj generator liczb losowych
cout << "Generowanie planszy..." << endl; // Wyświetl informację o generowaniu planszy
for(int i = 0; i < x; i++) { // Zainicjuj wszystkie parametry pól w nowej planszy wartością 0
for(int j = 0; j < y; j++) {
board[i][j].bomb = 0;
board[i][j].checked = 0;
board[i][j].ba = 0;
board[i][j].flag = 0;
}
}
while(l > 0) { // Dopóki mamy jeszcze bomby do rozstawienia
for(int i = 0; i < x; i++) { // Przechodzimy po planszy
for(int j = 0; j < y; j++) {
if (l > 0) { // Jeżeli mamy jeszcze bomby do rozstawienia
if(board[i][j].bomb == 0) { // Jeżeli na tym polu nie ma jeszcze bomby
int ch; // Zmienna przechowująca wartość losową
ch = rand()%10; // Wylosuj liczbę z zakresu 0-9
if(ch == 5) { // Jeżeli liczba ta jest równa 5
board[i][j].bomb = 1; // Przypisz bombę do bieżącego pola
}
if(board[i][j].bomb == 1) { // Jeżeli została wygenerowana bomba
l--; // Zmniejsz liczbę bomb pozostałych do rozstawienia
}
}
}
board[i][j].checked = 0; // Dla pewności zakrywamy bieżące pole
}
}
}
for(int i = 0; i < x; i++) { // Zliczanie parametru BombsAround - bomb wokół każdego pola - przechodzimy po planszy
for(int j = 0; j < y; j++) {
int bac = 0; // Dla danego pola inicjujemy licznik bomb wokół niego (BombsAroundCounter)
int a = i-1; // Zaczynamy od pola w górę i na lewo od bieżącego
int b = j-1;
if(a > -1 and b > -1 and a < x and b < y) { // Jeżeli nie jesteśmy poza zakresem
bac += board[a][b].bomb; // Dodaj wartość 1 lub 0 parametru bomb - czyli licznik zwiększy się, jak bomba będzie na polu
}
b++; // I tak dla każdego pola wokół bieżącego...
if(a > -1 and b > -1 and a < x and b < y) {
bac += board[a][b].bomb;
}
b++;
if(a > -1 and b > -1 and a < x and b < y) {
bac += board[a][b].bomb;
}
b = b-2;
a++;
if(a > -1 and b > -1 and a < x and b < y) {
bac += board[a][b].bomb;
}
b = b+2;
if(a > -1 and b > -1 and a < x and b < y) {
bac += board[a][b].bomb;
}
b = b-2;
a++;
if(a > -1 and b > -1 and a < x and b < y) {
bac += board[a][b].bomb;
}
b++;
if(a > -1 and b > -1 and a < x and b < y) {
bac += board[a][b].bomb;
}
b++;
if(a > -1 and b > -1 and a < x and b < y) {
bac += board[a][b].bomb;
}
board[i][j].ba = bac; // Ustaw parametr ba (BombsAround) dla danego pola - jest równy zliczonej ilości bomb
board[i][j].flag = 0; // Ustaw brak flagi dla bieżącego pola
}
}
return board; // Zwróć wygenerowaną planszę
}
int main() { // Główna funkcja programu
cout << "Minesweeper v. 0.1 (c) 2012 by Phitherek_" << endl; // Wyświetl nazwę programu, rok i autora, a jakże :)
int x, y, l; // Rozmiar planszy x*y, liczba bomb l
cout << "Podaj rozmiar planszy: " << endl << "x: "; // Prosimy użytkownika o rozmiar planszy - x
cin >> x; // Wczytujemy x
cout << "y: "; // Prosimy użytkownika o y
cin >> y; // Wczytujemy y
cout << "Podaj ilość bomb: "; // Prosimy użytkownika o ilość bomb l
cin >> l; // Wczytujemy l
char action = 'r'; // Ustawiamy bieżącą akcję - r (restart gry)
field **board = NULL; // Tworzymy tablicę reprezentującą planszę gry
board = new field *[x]; // Tworzymy tablicę wskaźników na początki wierszy
for(int i = 0; i < x; i++) {
board[i] = new field[y]; // Tworzymy wiersze
}
while(action != 'q') { // Dopóki akcja to nie q - wyjście - GŁÓWNA PĘTLA PROGRAMU
int status, bl, fl; // Tworzymy zmienne opisujące stan gry, liczbę bomb i liczbę pól
if(action == 'r') { // Jeżeli akcja to r - restart gry
board = gen_board(board, x, y, l); // Generujemy planszę
cout << "Rozpoczynam grę!" << endl; // I rozpoczynamy grę!
action = 'g'; // Zatem akcja to g - gra
status = 0; // Stan to 0, czyli gracz nie natknął się na bombę
bl = l; // Wczytaj liczbę bomb
fl = x*y; // Oblicz i wczytaj liczbę pól
} else if(action == 'g') { // Jeżeli gramy (akcja: g - gra)
if(status == 0) { // Jeżeli stan to 0 - gracz nie natknął się jeszcze na bombę
if(bl == fl) { // Jeżeli liczba pozostałych pól jest równa liczbie bomb... to gracz wygrał!
board = uncover_board(board, x, y); // Odsłaniamy planszę
cout << endl; // Na wszelki wypadek przechodzimy do nowej linii
display_board(board, x, y); // Wyświetlamy planszę
cout << endl; // Przechodzimy do nowej linii
cout << "Status: :D (WYGRANA!)" << endl << "r - Zagraj ponownie, q - wyjdź: "; // Wyświetlamy radosny status wygranej i pytamy użytkownika, co dalej
cin >> action; // Pobieramy akcję
if(action == 'q') { // Jeżeli akcja to q - wyjście
break; // Przerywamy główną pętlę programu
} // A jeżeli nie
continue; // To puszczamy kolejną iterację głównej pętli programu
} else { // Jeżeli liczba pozostałych pól to nie liczba bomb to gra trwa nadal
cout << "Status: :)" << endl; // Wyświetl uśmiechnięty status
}
} else { // Jeżeli jednak status to 1, czyli gracz stanął na bombie
board = uncover_board(board, x, y); // Odkrywamy planszę
cout << endl; // Na wszelki wypadek przechodzimy do nowej linii
display_board(board, x, y); // Wyświetlamy planszę
cout << endl; // Przechodzimy do nowej linii
cout << "Status: :( (PRZEGRANA!)" << endl << "r - Zagraj ponownie, q - wyjdź: "; // Wyświetlamy smutny status przegranej i pytamy użytkownika, co dalej
cin >> action; // Pobieramy akcję
if(action == 'q') { // Jeżeli akcja to q - wyjście
break; // Przerywamy główną pętlę programu
} // A jeżeli nie
continue; // Puszczamy kolejną iterację głównej pętli programu
}
cout << "Pozostało bomb: " << bl << endl << "Pozostało pól: " << fl << endl; // Wyświetlamy ilość bomb i pozostałych pól
display_board(board, x, y); // Wyświetlamy planszę
int c, d; // Zmienne c,d - współrzędne bieżącego pola
cout << endl << "Wprowadź współrzędne pola:" << endl << "Wiersz: "; // Prosimy użytkownika o indeks wiersza
cin >> c; // Wczytujemy indeks wiersza
cout << "Kolumna: "; // Prosimy użytkownika o indeks kolumny
cin >> d; // Wczytujemy indeks kolumny
if(c > -1 and c < x and d > -1 and d < y) { // Jeżeli pole jest na planszy
char sasasa; // Zmienna sasasa (od SubAction) - przechowuję podakcję akcji g - gra
cout << "o - odsłoń, f - o(d)flaguj, ? - o(d)flaguj jako niepewne: "; // Pytamy użytkownika o podakcję - co chce zrobić z polem
cin >> sasasa; // Pobieramy podakcję
if(sasasa == 'o') { // Jeżeli podakcja to o - odsłonięcie pola
if(board[c][d].checked == 1) { // Jeżeli pole jest już odsłonięte
cout << "Pole już odsłonięte!" << endl; // To informujemy użytkownika, że coś mu się chyba pomyliło
} else { // Jeżeli nie jest odsłonięte
if(board[c][d].bomb == 1) { // Jeżeli mamy bombę na polu
cout << "BOMBA!!!" << endl; // Ehm, playerze, stanąłeś na bombie...
status = 1; // Status: 1 - przegrana
} else { // W przeciwnym wypadku
uncover(board, x, y, c, d, &fl); // Odsłaniamy pole
}
}
} else if(sasasa == 'f') { // Jeżeli podfunkcja to f - flaga
if(board[c][d].flag == 1) { // Jeżeli pole jest oflagowane
board[c][d].flag = 0; // Zdejmij flagę
} else { // W przeciwnym wypadku
board[c][d].flag = 1; // Ustaw flagę
}
} else if(sasasa == '?') { // Jeżeli podakcja to ? - flaga jako niepewne
if(board[c][d].flag == 2) { // Jeżeli pole jest oflagowane jako niepewne
board[c][d].flag = 0; // Zdejmij flagę jako niepewne
} else { // W przeciwnym wypadku
board[c][d].flag = 2; // Ustaw flagę jako niepewne
}
} else { // Jeżeli podakcja to cokolwiek innego
cout << "Zły wybór!" << endl; // To niedobrze
}
} else { // Jeżeli jesteśmy poza zakresem planszy
cout << "Brak takiego pola!" << endl; // No to niedobrze
}
}
}
cout << "Dziękuję za grę!" << endl; // Zakończenie programu - ładnie dziękujemy za grę
return EXIT_SUCCESS; // I mówimy systemowi, że jest wszystko w porządku
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment