Help with a minesweeper project

Hi, my problem is that I'm trying to make a recursive function (function "reveal") in order to "open" all the empty grids until they found a wall of numbers, but when I introduce the coordinates of a grid the program stop working, I would really appreciate any suggestion to solve this.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
#include <iostream>
#include <stdio.h>      
#include <stdlib.h>
#include <time.h> 
#include <string>

using namespace std;
// array is the one with the solved game.
// array2 is the in game board.
char array[9][9];
char array2[9][9];

void generateMines(int y, int x){
	int a,b,i;
	srand (time(NULL));

	while (i != 10) {
	a = rand() % 8;
	b = rand() % 8;
		if (array[a][b] == '_' && a != y && b != x){
		array[a][b] = '*';
		i++;
		}
    }
}

void findMines(){
	
	int a = 0;
	
	for (int y = 0; y < 9; y++){
		for (int x = 0; x < 9; x++){
			if (array[y][x] != '*'){
					if (x == 0){
				
						if (array[y-1][x] == '*' || array[y-1][x+1] == '*' || array[y][x+1] == '*' || array[y+1][x] == '*' || array[y+1][x+1] == '*'){
							a++;
							array[y][x] = a + '0';
						}
					} else if (x == 8){
						
						if (array[y-1][x-1] == '*' || array[y-1][x] == '*' || array[y][x-1] == '*' || array[y+1][x-1] == '*' || array[y+1][x] == '*'){
							a++;
							array[y][x] = a + '0';
					    }
					} else {
						if (array[y-1][x-1] == '*' || array[y-1][x] == '*' || array[y][x-1] == '*' || array[y+1][x-1] == '*' || array[y+1][x] == '*'){
							a++;
							array[y][x] = a + '0';
						} if (array[y-1][x+1] == '*' || array[y][x+1] == '*' || array[y+1][x+1] == '*'){
							a++;
							array[y][x] = a + '0';
						}
					}
			}
			a = 0;
		}
	}
}

void reveal(int y, int x){
	
		if (array[y][x] == '_'){
			array2[y][x] = array[y][x];		
	// this the part when the program stop working.
			reveal(y-1, x-1);	
			reveal(y, x-1);
			reveal(y+1,x-1);
			reveal(y-1,x); 
				
			reveal(y+1,x); 
			reveal(y-1, x+1); 	
			reveal(y, x+1); 
			reveal(y+1, x+1);

		} else {
			array2[y][x] = array[y][x];	
		}
	
}	
	
int  checkwin(){
	int mark = 0;
	for (int y = 0; y < 9; y++){
		for (int x = 0; x < 9; x++){
			if (array2[y][x] != array[y][x]){
				mark++;
			}
		}
	}
	return mark;
}

int main(){
	
	bool game = true;
	int first_turn = 0;
	int a,b,check;

	for (int y = 0; y < 9; y++){
		for (int x = 0; x < 9; x++){
			array2[y][x] = '_';
			array[y][x] = '_';
		}
	}
	

    while (game == true){
    // show the solved game for testing	
    	for (int y = 0; y < 9; y++){
			if (y <= 9){
				cout << y << "  " << "|";
			} else if (y > 9){
				cout << y << " |";
			}
			for (int x = 0; x < 9; x++){
				cout << "[" << array[y][x] << "]";
			}
			cout << endl;
		}
		cout << endl << endl;
		
	// in game board	
    	cout << "     0  1  2  3  4  5  6  7  8" << endl;
		cout << "    ___________________________" << endl;
		for (int y = 0; y < 9; y++){
			if (y <= 9){
				cout << y << "  " << "|";
			} else if (y > 9){
				cout << y << " |";
			}
			for (int x = 0; x < 9; x++){
				cout << "[" << array2[y][x] << "]";
			}
			cout << endl;
		}
	
		cout << "\nChoose the grid you want to open" << endl;
		cout << "Row: ";
		cin >> a;
		cout << "Column: ";
		cin >> b;
		
		while (first_turn == 0){
			generateMines(a,b);
	   		findMines();
	    	first_turn = 1;
		}
		
		    reveal(a,b);
		    
		    check = checkwin();
	
		system("cls");
		
		 if (check == 10){
		    	cout << "You Win!";
		    	exit(1);
			} else if (array2[a][b] == '*'){
		    	cout << "You Lose";
		    	exit(1);
			} 
			
	}
	return 0;
}
A very complicated program. Just to get it to build on my end I had to rename array to array1 and on line 14 set i = 0 or you can't use it yet.

Still working on it.
its a hell of a code....there is a code on GFG for minesweeper refer that!!
sry, what's GFG?
geeksforgeeks
oh ok, thanks
Try this instead...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
void reveal(int y, int x) {

	if (array1[y][x] == '_') {
		array2[y][x] = array1[y][x];
		for (int y1 = y - 1; y1 <= y + 1 && y1 < 9; y1++) {
			if (y1 < 0) { y1++; }
			for (int x1 = x - 1; x1 <= x + 1 && x1 < 9; x1++) {
				if (x1 < 0) { x1++; }
				array2[y1][x1] = array1[y1][x1];
			}
		}

	}
	else {
		array2[y][x] = array1[y][x];
	}

}
One problem is that you can make a recursive call using the same coordinates, so you get infinite recursion:

reveal(10,10) -> reveal(9,10) -> reveal(10,10)...

Another problem is that you do no bounds checking so you can go off the array:
reveal(0,0) -> reveal(-1, 0) -> crash

To solve the first problem you need a way to mark the squares that you've checked. To solve the second problem, it's easiest to check the x and y values at the top of reveal(). The alternative of checking the values before each call just involves a ton of code:


Manga response helps me a lot, know I'm going to think for a way to solve the problems Dhayden mention, thanks for the help guys.
The main problem with "reveal" is that you aren't protecting it from out-of-bounds access. Also, I don't see how it's actually showing the open areas. If the board has been filled with the counts of neighboring mines, then the open areas should be zeros.

There are other problems, too.
You are "generating" the mines every turn (and calling srand every time, too).
You are not "finding" mines (i.e., counting neighboring mines) properly.
Last edited on
You are "generating" the mines every turn (and calling srand every time, too).

No, it generates mines on the first turn only. first_turn assures that the code executes once. However, first_turn has the wrong sense (0-> first turn, 1-> other turns). And it should be a boolean. And that code should be inside an if instead of a while.

Also generateMines() ensures that the players first guess isn't on a mine. Why?
Also generateMines() will never place a mine in the last row or column.

I found it much easier on my head to replace array2 with an array of booleans that just says whether the corresponding square in array is exposed to the player:

the test in checkwin becomes:
if (exposed[y][x] && array[y][x] == '*') {
When printing the board I did:
1
2
                char ch = (exposed[y][x] ? array[y][x] : ' ');
                cout << "[" << ch << "]";


And right after calling reveal, I always expose the current square:
1
2
        reveal(a, b);
        exposed[a][b] = true;   // always expose the one they picked. 


I counted the mines differently: first I found where the mines are, then I incremented the squares around them. Note that it would be more efficient to increment the squares when you place the mines instead.

Here is how I did reveal:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
void
reveal(int y, int x)
{
    if (x<0 || x>=9) return;    // x out of bounds
    if (y<0 || y>=9) return;    // y out of bounds
    if (exposed[y][x]) return;  // already did this square

    if (array[y][x] != '*') {
        exposed[y][x] = true;
    }
    if (array[y][x] == '_') {
        reveal(y - 1, x - 1);
        reveal(y, x - 1);
        reveal(y + 1, x - 1);
        reveal(y - 1, x);

        reveal(y + 1, x);
        reveal(y - 1, x + 1);
        reveal(y, x + 1);
        reveal(y + 1, x + 1);
    }
}

You might want to get reveal() working (or at least not crashing) first. Then you can work on the other problems.
wow! that really works for me, thanks man and thanks all of you for the help
Topic archived. No new replies allowed.