kod spaghetti wyrzuca memory overflow

0

Witam, Dzień dobry, Cześć
Na projekt zaliczeniowy do szkółki uznałem zrobić grę saper. Niestety mam z nią kilka problemów, główne to 2:

Przy większych polach wyrzuca błąd pamięci (podejrzewam że funkcja difuse wywołując samą siebie na polach sąsiednich zajmuje za dużo pamięci), niestety nie wiem jak to obejść, lubię obecny sposób działania i nie chcę go zmieniać

nie mam obsługi polskich znaków

Jeśli chodzi o sam kod to proszę jakąś ocenę pod względem stylistyki i podrzucenie jakiś dobrych praktyk dla cpp.

Pozdrawiam




#include <iostream>

using namespace std;



double lvl{};
struct cell {
	int neigbouring_mines = 0;
	bool is_mine = false;
	bool is_unfolded = false;
	bool is_questionmark = false;
	bool is_flagged = false;
};

int size_board_x=0, size_board_y=0, max_mines=0, mines_planted=0;
cell board[32][32];






void make_board(int lvl) {

	int count = 0, max_mines=0;//count of mines planted

	if (lvl == 1) {
		size_board_x = 10;
		size_board_y = 10;
		max_mines = 10;

	}

	if (lvl == 2) {
		size_board_x = 16;
		size_board_y = 16;
		max_mines = 40;
		
	}

	if (lvl == 3) {
		size_board_y = 32;
		size_board_x = 16;
		max_mines = 99;
	}

	while (mines_planted < max_mines) {
		int x = rand() % size_board_x, 
			y = rand() % size_board_y;

		if (board[x][y].is_mine == false) {
			board[x][y].is_mine = true;
			board[x+1][y].neigbouring_mines ++;
			board[x+1][y+1].neigbouring_mines++;
			board[x+1][y-1].neigbouring_mines++;
			board[x-1][y].neigbouring_mines++;
			board[x-1][y-1].neigbouring_mines++;
			board[x-1][y+1].neigbouring_mines++;
			board[x][y+1].neigbouring_mines++;
			board[x][y-1].neigbouring_mines++;
			mines_planted++;
		}
	}
}

void display_board(int lvl) {
	for (int i = 0; i < size_board_x; i++) {
		for (int j = 0; j < size_board_y; j++) {
			if (board[i][j].is_unfolded) {
				cout << " " << board[i][j].neigbouring_mines << " ";
			}
			else cout << " | ";

		}
		cout << i << endl;
	}
	/*for (int i = 0; i < size_board_x; i++) {
		for (int j = 0; j < size_board_y; j++) {
			if (board[i][j].is_mine) {
				cout << " # ";
			}
			else {
				cout << " O ";
			}

		}
		cout << i << endl;
	}
		for (int j = 0; j < size_board_x; j++) {
			cout << " " << j;
		}
		*/
}



int display_menu() {
	int choice = 0;
	cout << "Wybierz poziom trudności" << endl << "1. Łatwy" << endl << "2. Średni" << endl << "3. Trudny" << endl;
	cin >> choice;
	return choice;
}


int difuse(int x, int y) {
	//make sure that input data are valid (in range of game board)
	if ((x >= 0) && (x < size_board_x) && (y >=0) && (y < size_board_y)) 
	{
		if (board[x][y].is_mine)
			//if mine field is hit, end game
			return 0;
		else if (board[x][y].neigbouring_mines == 0) 
		{
			//if there are no mines nearby, difuse all the neighbouring fields 
			difuse(x - 1, y + 1);
			difuse(x - 1, y);
			difuse(x - 1, y - 1);
			difuse(x, y + 1);
			difuse(x, y - 1);
			difuse(x + 1, y + 1);
			difuse(x + 1, y);
			difuse(x + 1, y + 1);
			board[x][y].is_unfolded = true;
		}
		else if (board[x][y].neigbouring_mines != 0) 
		{
			//if there are mines nearby, only show value of difused field
			board[x][y].is_unfolded = true;
		}
		return 1;
	}
}


int main()
{
	//setlocale(LC_CTYPE, "Polish");

	int choice = display_menu();
	while (choice==1||choice==2||choice==3) {
		//int choice = 1;
		if (choice > 0 && choice < 4) {
			make_board(choice);//if choice != quit than choice = difficulty_lvl
			//display_board(choice);
			while (difuse != 0) {
				display_board(choice);
				int x{}, y{};
				cin >> x >> y;
				if (board[x][y].is_unfolded == false)
				{
					int field_is_safe = difuse(x, y);
					if (field_is_safe==false) {
						//char k{};
						for (int i = 0; i < size_board_x; i++) {
							for (int j = 0; j < size_board_x; j++) {
								if (board[i][j].is_mine) {
									cout << " # ";
								}
								else if (board[i][j].is_unfolded) {
									cout << " " << board[i][j].neigbouring_mines << " ";
								}
								else cout << " | ";

							}
							cout << i << endl;
						}
					}
					else {
						//cout << " Już odkryłeś to pole, spróbuj ponownie ";

					}
				}
			}
		}
		int choice = display_menu();
	}
}```
0

Gdy wylosujesz wartość x równą zero, to podstawienie

board[x-1][y].neigbouring_mines++;

prowadzi do UB ( Undefined Behavior ), podstawiasz do nieistniejącej komórki tablicy board[-1][y].

0
if (board[x][y].is_mine == false) {
			board[x][y].is_mine = true;
			board[x+1][y].neigbouring_mines +=is_good(x+1,y);
			board[x+1][y+1].neigbouring_mines+= is_good(x + 1, y+1);
			board[x+1][y-1].neigbouring_mines += is_good(x + 1, y-1);
			board[x-1][y].neigbouring_mines += is_good(x-1 + 1, y);
			board[x-1][y-1].neigbouring_mines += is_good(x-1 + 1, y-1);
			board[x-1][y+1].neigbouring_mines += is_good(x - 1, y+1);
			board[x][y+1].neigbouring_mines += is_good(x, y+1);
			board[x][y-1].neigbouring_mines += is_good(x, y-1);
			mines_planted++;
		}
	}
}

int is_good(int x, int y) {
	if ((x >= 0) && (y >= 0) && (x < size_board_x) && (y < size_board_y)) 
		return 1;
	return 0;
}

Zamieniłem to na takie coś. Pytanie czy dodawanie 0 do board[-1][y] też nie daje UB

kod online compiler:
https://onlinegdb.com/rybvkAtbI

0

Pytanie czy dodawanie 0 do board[-1][y] też nie daje UB

Tak, jest to UB.

1

Cały czas masz ten sam problem UB, spróbuj zmienić na:


bool is_good(int x, int y)
{
    return ((x >= 0) && (y >= 0) && (x < size_board_x) && (y < size_board_y)); 
}

while (mines_planted < max_mines)
 {
        int x = rand() % size_board_x, 
             y = rand() % size_board_y;

        if( !board[x][y].is_mine ) 
        {
            board[x][y].is_mine = true;
 
            for( int index i=-1 ; i<=1 ; ++i )
            {
               for( int index j=-1 ; j<=1 ; ++j )
               {
                    if( is_good(x+i,y+j) ) ++board[x+i][y+j].neigbouring_mines;
               }
            }

            mines_planted++;
        }
    }
0

Nie myślałeś, żeby napisać funkcę, która zlicza ilość min dookoła (biorąc pod uwagę ograniczenia planszy), i w razie potrzeby, zwyczajnie je zliczać? Taka konstrukcja powinna znacznie skrócić kod, to może okaże się, że coś w oczywisty sposób nie jest poprawne.

Btw, wygląda na to, że brakuje Tobie warunku, że próbujesz unfoldować tylko jeśli nie jest jeszcze unfoldowane, bo w obecnej chwili, jeśli masz cztery pola z zerami, ułożonymi w kwadrat, to nigdy nie skończysz unfoldowania ich - będziesz iść w kółko, prawy-górny -> prawy-dolny -> lewy-dolny -> lewy-górny -> prawy-górny itd.

0
            difuse(x - 1, y + 1);
            difuse(x - 1, y);
            difuse(x - 1, y - 1);
            difuse(x, y + 1);
            difuse(x, y - 1);
            difuse(x + 1, y + 1);
            difuse(x + 1, y);
            difuse(x + 1, y + 1);
            board[x][y].is_unfolded = true;

To się zapętla w nieskończoność, wystarczy zamienić na:

            board[x][y].is_unfolded = true;
            difuse(x - 1, y + 1);
            difuse(x - 1, y);
            difuse(x - 1, y - 1);
            difuse(x, y + 1);
            difuse(x, y - 1);
            difuse(x + 1, y + 1);
            difuse(x + 1, y);
            difuse(x + 1, y + 1);
            ```
i hula

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