Minesweeper Basic Board Output

Hey guys, I worked on a code that was supposed to change some values in an array, but I don't know how to output it and check it if its correct. How would I do that (Or alternatively, is the 'checkMine' function correct???)


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
#include<iostream>
#include<ctime>
#include<cstdlib>
using namespace std;

const int ROWS = 5; // a constant of row 
const int COLS = 5; // a constant of column. I don't want the board to be more than 5 X 5

//enum to represent every possible value in the board.
enum Symbols {STAR = 42, AT = 64, X = 88, ZERO = 0, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE}; 

//Function to cout basic info (Rules, names etc..)
void info();
 
/* 
In this value,passing in the two-dimensional array and
the size. This function will simply initialize each position on the board to the enumerated
type representing the initial value, which is the character β€˜*’ (or STAR).
*/void initPosition(Symbols symbolArr[][COLS], int size); 

/*
 assign the number of mines between 5 and 10, inclusively, specified by
the user to randomly generated locations on the board using a bool function, passing
in the two-dimensional array and the size. This function will generate a random rowcolumn
position and then attempt to place a mine at that row-column position on the
board. Since the row-column position is randomly generated, if the function attempts to
place a mine on a square that already contains a mine, the method will return false,
indicating that the assignment was not successful. If the square, however, does not
already contain a mine, then the function will assign a mine to that location by assigning
that row-column position with the enumerated type representing the mine and return
true, indicative that the assignment was successful. Note that this function attempts to 
place only one (1) mine at a randomly generated location on the board, so a loop should
be implemented in the calling function to achieve this functionality.
*/bool checkMine(Symbols symbolArr[][COLS], int size, int total_mines);

int main()
{
	int mines;
	/*
	You shall declare a two-dimensional array in main() to represent the 5-by-5 board as an enum type you declare to represent the various values that a square can assume. *, @, X, 0-9
	*/
	Symbols symbolArr[][COLS] = {STAR, AT, X, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE};
	
	do
	{
		cout << "Enter The Numbers of Mines Between 5 and 10: " << endl;
		cin >> mines;
	}while(mines <= 4 || mines >=11);
	
	
	initPosition(symbolArr, ROWS);  // call initialboard w/ *
	checkMine(symbolArr, ROWS, mines); // call function that randomly assigns bombs
	//displayBoard(symbolArr, ROWS); //function to combine the two functions and display with border

	
	
	
	return 0;
}

void initPosition(Symbols symbolArr[][COLS], int size)
{
	for (int i = 0; i < size; i++)
	{
		for (int j = 0; j < COLS; j++)
		{
			cout <<static_cast<char>(42);
		}
		cout << endl;
	}
}

bool checkMine(Symbols symbolArr[][COLS], int size, int total_mines)
{
	srand(time(NULL));
	
	int row = rand() % total_mines;
	int col = rand() % total_mines;
	
	for (int mines_placed = 0; mines_placed < total_mines;) 
	{ 	
		if(symbolArr[row][col] != AT)
		{
			symbolArr[row][col] = AT; // place the mine
			mines_placed++;
		}
		else
		{
			return -1;
		}
 
}
	
}



Thanks in advance
Last edited on
Hello pdgaming,

A simple way to print your array. Copy and paste the function "initPosition", change the name, omething lime "PrintArray", and change cout <<static_cast<char>(42); to std::cout << symbolArr[i][j] << " ";.

Working on the answer for the "checkMine" function. It has several problems and I need to do some more checking. I will have something shortly.

Hope that helps,

Andy
Hello pdgaming,

After working with the function "checkMine" I have found these problems.

1. the function returns a bool, but you do not. You try to return a -1 which is not a bool. A bool can only have one of two values; false or zero(0) and true or (1). Any number > 1 is also considered true.

2. In the way you have the "checkMine" function "row" and "col" only receive a value once, so the for loop only loops once. On the second time the else is reached and the function returns. Not all mines are set.

3. You may want to rethink the use of the "else" and the "return" in the "else". Unless something is terribly wrong you should never reach the "else" until all mines are set first.

In "main" the "checkMine" function call is not set up to receive anything from the function.

And the "symbolArr" may not be what you want to use. Also you should check out what is in the "symbolArr" because the last two elements may not be what you want or something you do not want to use.

As a start this is how I have changed your code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
bool checkMine(Symbols symbolArr[][COLS], int size, int total_mines)
{
	srand(time(NULL));  // <--- Not the best place to put this, but since the function is only called once it works.

	//  for loop will only work until it tries to place a mine where one exists. Then it exits the function.
	//  before all mines are placed.
	for (int mines_placed = 0; mines_placed < total_mines;)
	{
		int row = rand() % total_mines;  // <--- Moved here so row and col will change.
		int col = rand() % total_mines;

		if (symbolArr[row][col] != AT)
		{
			symbolArr[row][col] = AT; // place the mine
			mines_placed++;
		}
		else
		{
			return false;  // <--- Changed to false because -1 is not a bool number.
		}

	}
	return true;  // <--- Added line. Do not believe it is ever reached.
}


Still have to figure what to so with the "else" part of the "checkMine" function.

Hope that helps,

Andy
Last edited on
Hm... Unfortunetly, that isn't working. When I output this code, this is what I get.

1
2
3
4
5
6
7
8
9
10
11
12

*****
*****
*****
*****
*****
*@X@

@@
@β””ΓΆ@
@ m


I am not sure what is wrong with the code. At least its placing the bombs correctly. How would I initialize the first code to have the '*', but not output it. I just want to show the bottom half, but replace all that gibberish with the '*'

Here is the code I have
1
2
3
4
5
6
7
8
9
10
11
12
13
14
void displayBoard(Symbols symbolArr[][COLS], int size)
{

	for (int i = 0; i < size; i++)
	{
		for (int j = 0; j < COLS; j++)
		{
			cout <<static_cast<char>(symbolArr[i][j]);
		}
		cout << endl;
	}

	return;		
}
Last edited on
Hello pdgaming,

The code in the "displayBoard"function is correct. I think your understanding of the "symbolArr" is incorrect. In main you define "Symbols symbolArr[][COLS]" as a 2D array with the first dimension being undetermined and the second dimension being 5. But when you initialize the array you have enough information for a 3 x 5 array with the last two elements being zeros. I still can not figure out why you have created the array this way. It does not make any sense. What makes more sense to me is char board[ROWS][COLS]; and then use the "initPosition" function to initialize the array to "-"s. Then place your mines. At some point you could write an overloaded "displayBoard" function with two extra parameters of "row" and "col" to change the "board" array and re-display the given "row" and"col" with either a space or an "*" if it is a mine. My opinion for what it is worth.

In the "checkMine" function I commented out the "else" part of the "if" statement and for now it seemed to work properly.

Hope that helps,

Andy
Hey Adam, thanks for your help so far. The main problem i am having is like you are saying is my check mine function. I am trying to make it so that the user can choose the amount of mines they want on the board. Right now though, it seems that it randomly chooses the amount of mines to be placed on the board. For example
1
2
3
4
5
6
Enter The Numbers of Mines Between 5 and 10: 7
*****
*****
@@***
***@*
@@***


How would i go about fixing this? am I just not calling the function correctly? Here is the code I have so far.
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
int main()
{
	int mines;
	
	do
	{
		cout << "Enter The Numbers of Mines Between 5 and 10: ";
		cin >> mines;
	}while(mines <= 4 || mines >=11);

	checkMine(symbolArr, mines);	
	return 0;
}

bool checkMine(Symbols symbolArr[ROWS][COLS], int size)
{
	srand(time(NULL));  //Random Number generator

	for (int mines_placed = 0; mines_placed < size;)
	{
		int row = (rand() % size);  
		int col = (rand() % size);

		if (symbolArr[ROWS][COLS] != AT)
		{
			symbolArr[row][col] = AT; // place the mine
			mines_placed++;
		}
	}
	return true;
}
Last edited on
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
// bool checkMine(Symbols symbolArr[ROWS][COLS], int size)
void place_mines( Symbols symbolArr[ROWS][COLS], int num_mines )
{
	// srand(time(NULL));  //Random Number generator
        // do this once, at the start of the program 
        
        // limit the number of mines to some reasonable value; in particular, avoid an infinite loop
        num_mines = std::min( num_mines, ROWS*COLS*3/4 ) ; 

	for (int mines_placed = 0; mines_placed < num_mines;)
	{
		// int row = (rand() % size);  
                const int row = std::rand() % ROWS ;
  
		// int col = (rand() % size);
                const int col = std::rand() % COLS ;

		if (symbolArr[ROWS][COLS] != AT)
		{
			symbolArr[row][col] = AT; // place the mine
			mines_placed++;
		}
	}

	// return true;
}
@JLBorges: Unfortunately, i have to use a bool function. If I could use a void function, it would be easier but for this assignment, I must use a bool to call this function.
Hello pdgaming,

I think either I am not communicating what I mean properly or you are putting more than you need into what I am saying.

The function: bool checkMine(Symbols symbolArr[][COLS], int size, int total_mines) is mostly fine the way it is. What I found and changed to is: bool checkMine(Symbols symbolArr[][COLS], int total_mines). I found that "int size" is never used an is not needed. total_mines is a more descriptive variable name than size and allows everyone to understand better what you mean and are doing.

Here is your code as I have changed it to make it work. It is more an understanding of how some things work that a working program, but it is a good start.

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
#include<iostream>
#include<ctime>
#include<cstdlib>
using namespace std;

const int ROWS = 5; // a constant of row 
const int COLS = 5; // a constant of column. I don't want the board to be more than 5 X 5

		//enum to represent every possible value in the board.
enum Symbols { STAR = 42, AT = 64, X = 88, ZERO = 0, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE };

//Function to cout basic info (Rules, names etc..)

void info();  // <--- Not used yet.

void initPosition(Symbols symbolArr[][COLS], int size);
bool checkMine(Symbols symbolArr[][COLS], int total_mines);
void displayBoard(Symbols symbolArr[][COLS]);

int main()
{
	int mines{ 0 };
	bool ok{ true };

	srand(time(NULL));  // <--- Moved from function to main.

	/*
	You shall declare a two-dimensional array in main() to represent the 5-by-5 board as an enum type you declare to represent the various values that a square can assume. *, @, X, 0-9
	*/
	Symbols symbolArr[ROWS][COLS] = { DASH, STAR, AT, X, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE };

	//  This would work better.
	//char board[ROWS][COLS]{ ' ' };
	// or
	//int board[ROWS][COLS]{ 0 };

	do
	{
		cout << "Enter The Numbers of Mines Between 5 and 10: " << endl;
		cin >> mines;
	} while (mines < 5 || mines > 10);

	std::cout << std::endl;

	initPosition(symbolArr, ROWS);  // call initialboard w/ *
	ok = checkMine(symbolArr, mines); // call function that randomly assigns bombs
									  // displayBoard(symbolArr, ROWS); //function to combine the two functions and display with border
	if (ok)  // <--- Used for testing.
		std::cout << "\n Mines deployed\n" << std::endl;
	else
		std::cout << "\n Mines not deployed\n" << std::endl;

	displayBoard(symbolArr);  // <--- Removed , mines.

	return 0;
}

void initPosition(Symbols symbolArr[][COLS], int size)
{
	for (int i = 0; i < size; i++)
	{
		for (int j = 0; j < COLS; j++)
		{
			symbolArr[i][j] = DASH;
			cout << static_cast<char>(45) << " ";  // <--- Added the space for a better look.
		}
		cout << endl;
	}
}

bool checkMine(Symbols symbolArr[][COLS], int total_mines)  // <--- Removed int size. Not needed or used,
{
	int mines_placed{ 0 };

	//  for loop will only work until it tries to place a mine where one exists. Then it exits the function.
	//  before all mines are placed.
	for (mines_placed = 0; mines_placed < total_mines;)
	{
		int row = rand() % total_mines;  // <--- Moved here so row and col will change.
		int col = rand() % total_mines;

		if (symbolArr[row][col] != AT && row < ROWS && col < COLS + 1)
		{
			symbolArr[row][col] = AT; // place the mine
			mines_placed++;
		}
		//else
		//{
		//	return false;  // <--- Changed to false because -1 is not a bool number.
		//}

	}
	return true;  // <--- Added line. Do not believe it is ever reached.
}

void displayBoard(Symbols symbolArr[][COLS])
{

	for (int i = 0; i < ROWS; i++)  // <--- Changed from size, which gave the wrong number, to ROWS.
                                        //  size could end up out side the boundrys of the array.
	{
		for (int j = 0; j < COLS; j++)
		{
			cout << static_cast<char>(symbolArr[i][j]) << " ";  // <--- Added the space for a better look.
		}
		cout << endl;
	}

	return;
}


Read this over and notice the "// <---" comments that I have made. If you are still confused let me know which part(s).

Hope that helps,

Andy
Thanks andy. Your code was almost perfect so I appreciate it. The only thing it was doing wrong was that it wasn't putting the correct amount of specified mines. : IE: Mines = 6, then the output would display only five mines. I fixed that by changing
 
int minesPlaced = -1;


Other than that, it works perfectly. Thank you so much for your help.

EDIT** Nevermind, it still doesn't work properly.
Last edited on
> The only thing it was doing wrong was that it wasn't putting the correct amount of specified mines. :
> IE: Mines = 6, then the output would display only five mines. I fixed that ...

You haven't fixed anything; the code is just as badly broken as it was earlier.

Hint: If the number of mines is greater than five, the program engenders undefined behaviour.
(unless you happen to get extraordinarily lucky with the result of each and every call to std::rand())
Hint: http://www.cplusplus.com/forum/beginner/213125/#msg995347
Last edited on
 
num_mines = std::min( num_mines, ROWS*COLS*3/4 ) ;


I don't understand this piece of code in particular. Could you explain what it is doing?

Also, I am not trying to generate a random amount of mines. What I am trying to do is randomly place the amount of mines specified.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
bool checkMine(Symbols symbolArr[ROWS][COLS], int total_mines)
{
	int mines_placed =0;
	
	total_mines = (std::min(total_mines, ROWS*COLS*3/4 ));

	for (mines_placed = 0; mines_placed < total_mines;)
	{
		int row = rand() % total_mines;  // <--- Moved here so row and col will change.
		int col = rand() % total_mines;

		if (symbolArr[row][col] != AT)
		{
			symbolArr[row][col] = AT; // place the mine
			mines_placed++;
		}
	}
	return true;


output is

1
2
3
4
5
6
Enter The Numbers of Mines Between 5 and 10: 8
*****
**@**
*@@**
**@**
@****
Last edited on
> num_mines = std::min( num_mines, ROWS*COLS*3/4 ) ;

We would never be able to place more than ROWS*COLS mines in symbolArr.
For instance if ROWS==5, COLS==5 and num_mines == 26, the loop would be an infinite loop.
If num_mines == 23, we could be looping for a very very long time.

num_mines = std::min( num_mines, ROWS*COLS*3/4 ) ; limits the number of mines to a maximum of 75% of the number of slots in the array - so that with a reasonable implementation of std::rand(), the loop could be expected to complete after some bounded number of iterations.


>
1
2
int row = rand() % total_mines;  // <--- Moved here so row and col will change.
int col = rand() % total_mines;


Consider: with ROWS==5, COLS==5 and num_mines == 8;
rand() % total_mines could yield 5, 6 or 7, resulting in out of bounds access to the array.
So I talked to my professor and it seems i didn't really understand the question. This is what he wanted me to do

The reason why it appears random amount is because there are some that are duplicate to
the already placed mines, but your function is incorrect. Read it carefully - your function
should only attempt to place 1 mine and return true if it can and false if it cannot. That
means that you will have loops in the main to call this function a certain number of times
that is specified by the user, and another loop until it is able to actually place the 1 mine.


so I tried to change it, but i just can't seem to figure it out.

I want to change the (place mines) to a void function. I have to do the bool part in the main. I am not sure how to do that. How would I go about doing that?

I have
1
2
3
4
5
6
7
8
int main()
{
	for (int i = 0; i < mines; i++)
	{
		checkMine(symbolArr, mines);
	}
// How do i create a loop that keeps looping until it is able to actually place the 1 mine.


1
2
3
4
5
6
7
8
9
10
11
void checkMine(Symbols symbolArr[ROWS][COLS], int total_mines)
{
		int row = rand() % total_mines;  // <--- Moved here so row and col will change.
		int col = rand() % total_mines;
		
		if(symbolArr[ROWS][COLS] != AT)
		{		
			symbolArr[row][col] = AT;
		}
return;	
}


output is
1
2
3
4
5
6
Enter The Numbers of Mines Between 5 and 10: 8
*****
*****
*****
*@***
*****
Last edited on
1
2
3
4
5
6
7
8
9
10
11
void checkMine(Symbols symbolArr[ROWS][COLS], int total_mines)
{
		int row = rand() % total_mines;  // <--- Moved here so row and col will change.
		int col = rand() % total_mines;
		
		if(symbolArr[ROWS][COLS] != AT)
		{		
			symbolArr[row][col] = AT;
		}
return;	
}


As already mentioned, the numbers generated for row and col in your code have the potential to be out of the boundaries of the array. total_mines has no place in that calculation, and I'm at a loss as to why this function takes that parameter, since it is completely irrelevant to what the function is required to do.

On the other hand, symbolArr[ROWS][COLS] (line 6) will always be out of the boundaries of said array.
How would I go about limiting my randomizer?
num_mines = std::min( num_mines, ROWS*COLS*3/4 ) ; isn't working (since i am not passing a second function). I have noticed that it randomizes in a pattern.

here is my code and below is the pattern I am seeing for the randomizer
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
bool checkMine(Symbols symbolArr[ROWS][COLS])
{
		int row = rand() % ROWS;
		int col = rand() % COLS;
		
		if (symbolArr[row][col] = AT)
		{
			int row = rand() % ROWS;
			int col = rand() % COLS;
		}
		else{
			symbolArr[row][col] = AT;
			return true;
		}
}


for example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
IF amount of mines = 5
then the output will randomly choose between 4 or 5 as the amount of mines


IF amount of mines = 6
then the output will randomly choose between 5 or 6 as the amount of mines

IF amount of mines = 7
then the output will randomly choose between 5 or 6 or 7 as the amount of mines

IF amount of mines = 8
then the output will randomly choose between 6 or 7 or 8 as the amount of mines

ETC...... all the way till the limit of 10



how would I go about solving this issue?
Last edited on
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
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <algorithm>

constexpr std::size_t NROWS = 10 ;
constexpr std::size_t NCOLS = 25 ;
enum symbol : char { STAR = '*', MINE = '@' /* ... */ };
using mine_field = symbol[NROWS][NCOLS] ;

void initialise( mine_field& fld )
{ for( auto& row : fld ) for( auto& sym : row ) sym = STAR ; }

void print( const mine_field& fld )
{
    for( auto& row : fld )
    {
        for( auto sym : row ) std::cout << char(sym) ;
        std::cout << '\n' ;
    }
}

bool try_place_mine( mine_field& fld )
{
    const int row = std::rand() % NROWS ;
    const int col = std::rand() % NCOLS ;

    if( fld[row][col] == MINE ) return false ;

    fld[row][col] = MINE ;
    return true ;
}

void place_mines( mine_field& fld, std::size_t num_mines )
{
    auto cnt = std::min( num_mines, NROWS*NCOLS*3/4 ) ;

    #ifndef NDEBUG
        if( cnt < num_mines )
            std::cout << "#mines reduced from " << num_mines << " to " << cnt << '\n' ;
    #endif // NDEBUG

    // place cnt mines in the mine field
    while( cnt > 0 ) if( try_place_mine(fld) ) --cnt ;
}

int main()
{
    std::srand( std::time(nullptr) ) ;

    for( std::size_t num_mines : { 5, 19, 45, 1'000'000 } )
    {
        mine_field fld ;
        initialise(fld) ;

        std::cout << "\n\n#mines == " << num_mines << '\n' ;
        place_mines( fld, num_mines ) ;
        print(fld) ;
    }

}

http://coliru.stacked-crooked.com/a/9b62e65303935811
Last edited on
Topic archived. No new replies allowed.