Jump to content

minesweeper

RexLee

The problem is:

input:

*...

....

.*..

....

output:

*100

2210

1*10

1110

The numbers show how many mines(*) there are adjacent to the square that "." is in.

#include <iostream>int main(){    int height, width;    std::cin >> height >> width;    char mine_hole[height][width];    int mine_count[height][width];    for (int i = 0; i < height; ++i)    {        for (int j = 0; j < width; ++j)        {            std::cin >> mine_hole[i][j];        }    }    for (int i = 0; i < height; ++i)    {        for (int j = 0; j < width; ++j)        {            int count = 0;            if (mine_hole[i][j] != '*')            {                if (mine_hole[i][j - 1] == '*')                {                    ++count;                }                if (mine_hole[i][j + 1] == '*')                {                    ++count;                }                if (mine_hole[i - 1][j] == '*')                {                    ++count;                }                if (mine_hole[i - 1][j - 1] == '*')                {                    ++count;                }                if (mine_hole[i - 1][j + 1] == '*')                {                    ++count;                }                if (mine_hole[i + 1][j] == '*')                {                    ++count;                }                if (mine_hole[i + 1][j - 1] == '*')                {                    ++count;                }                if (mine_hole[i + 1][j + 1] == '*')                {                    ++count;                }                mine_count[i][j] = count;            }            if (mine_hole[i][j] == '*')            {                mine_count[i][j] = -1;            }        }    }    for (int i = 0; i < height; ++i)    {        for (int j = 0; j < width; ++j)        {            if (mine_count[i][j] == -1)                std::cout << '*';            else                std::cout << mine_count[i][j];            if (j == width - 1)            {                           std::cout << "\n";            }        }    }    system("pause");    return 0;}

But the output has wrong outputs usually at the corners.

Does anyone know why?

Link to comment
Share on other sites

Link to post
Share on other sites

What compiler are you using?

 int height, width;std::cin >> height >> width;char mine_hole[height][width];int mine_count[height][width];

Should be giving a bunch of errors. To declare an array like that, height and width must be constant.

1474412270.2748842

Link to comment
Share on other sites

Link to post
Share on other sites

One of your problems is you don't do any bounds checking. Inside your loops when i or j is 0 or height-1/width-1 you're accessing memory outside of the array.

 

As for the array declaration I can only assume the compiler is using some default (most likely 0) for the height and width. Try commenting out

std::cin >> height >> width;

 

and changing

int height, width;

to

const int height=4, width=4;

for testing.

1474412270.2748842

Link to comment
Share on other sites

Link to post
Share on other sites

What compiler are you using?

 int height, width;std::cin >> height >> width;char mine_hole[height][width];int mine_count[height][width];

Should be giving a bunch of errors. To declare an array like that, height and width must be constant.

that's actually allowed with C99 standard, it's a feature called "variable size arrays" (i think so) so it should actually compile and run fine

(edit: "Variable Length Arrays")

 

and yeah, the problem is with the borders of the table, you're accessing unallocated space, like mine_hole[-1][-1]

 

 

 

yoda.jpg

 

++count;

Link to comment
Share on other sites

Link to post
Share on other sites

I had to create a 4x4 tictactoe for a coursework at uni last year,

the if statement I had to make to calculate the 3 in a row while maintaining bounds was pretty crazy.

The 'map' shows all possible checks for each type of position (top-left, top, top-right, left, somewhere in the middle, right, bottom-left, bottom, bottom-right)

35cpxc9.jpg

You simply have to exclude certain if statements depending on current coordinates by including a small && and the end of each of them 

This auto-eliminates any problems with size as long as your for loops are correct, since it will detect any edges and corners, and only allow only some if statements to trigger if the point isn't a the end

This should solve the problem with edges/corners having wrong output, other than that, as others said, make sure you initialize arrays with consts.

Ask if any of this nonsense actually sounds like nonsense to you.

P.S Drawings and sketches do help you a lot when working out stuff like this, pen and pencil ftw.

Link to comment
Share on other sites

Link to post
Share on other sites

Thanks for all your answers.

I fixed it by making sure it doesn't check out of bounds values.

#include <iostream>int main(){    int height, width;    std::cin >> height >> width;    char mine_hole[height][width];    int mine_count[height][width];    for (int i = 0; i < height; ++i)    {        for (int j = 0; j < width; ++j)        {            std::cin >> mine_hole[i][j];        }    }    for (int i = 0; i < height; ++i)    {        for (int j = 0; j < width; ++j)        {            int count = 0;            if (mine_hole[i][j] != '*')            {                if (mine_hole[i][j - 1] == '*')                {                    if (i < height && i >= 0 && j < width && j >= 0)                    {                        ++count;                    }                }                if (mine_hole[i][j + 1] == '*')                {                    if (i < height && i >= 0 && (j + 1) < width && (j + 1) >= 0)                    {                        ++count;                    }                }                if (mine_hole[i - 1][j] == '*')                {                    if ((i - 1) < height && (i - 1) >= 0 && j < width && j >= 0)                    {                        ++count;                    }                }                if (mine_hole[i - 1][j - 1] == '*')                {                    if ((i - 1) < height && (i - 1) >= 0 && (j - 1) < width && (j - 1) >= 0)                    {                        ++count;                    }                }                if (mine_hole[i - 1][j + 1] == '*')                {                    if ((i - 1) < height && (i - 1) >= 0 && (j + 1) < width && (j + 1) >= 0)                    {                        ++count;                    }                }                if (mine_hole[i + 1][j] == '*')                {                    if ((i + 1) < height && (i + 1) >= 0 && j < width && j >= 0)                    {                        ++count;                    }                }                if (mine_hole[i + 1][j - 1] == '*')                {                    if ((i + 1) < height && (i + 1) >= 0 && (j - 1) < width && (j - 1) >= 0)                    {                        ++count;                    }                }                if (mine_hole[i + 1][j + 1] == '*')                {                    if ((i + 1) < height && (i + 1) >= 0 && (j + 1) < width && (j + 1) >= 0)                    {                        ++count;                    }                }                mine_count[i][j] = count;            }            if (mine_hole[i][j] == '*')            {                mine_count[i][j] = -1;            }        }    }    for (int i = 0; i < height; ++i)    {        for (int j = 0; j < width; ++j)        {            if (mine_count[i][j] == -1)                std::cout << '*';            else                std::cout << mine_count[i][j];            if (j == width - 1)            {                           std::cout << "\n";            }        }    }    system("pause");    return 0;}

But I think this looks too long.

Is there a more efficient way to solve this problem?

Link to comment
Share on other sites

Link to post
Share on other sites

suppose the player wants a 10x10 field

you can create a 12x12 field, adding a dummy row/column on each border and fill it with not-mines

to iterate through the field use something like

for(i=1; i<11; i++)

this way you won't go off boundaries and you won't have to add specific code for boundaries

Link to comment
Share on other sites

Link to post
Share on other sites

i would do it this way

#include <iostream>int main(){	// i and j are declared here because almost every part of the program needs them, so there is no need to allocate and deallocate them every time you need them	int height, width, i, j; 	// auxiliary variable to read the user input	char input;	std::cin >> height >> width;	// add the two dummy rows and columns in the matrix you will check	int is_mine[height+2][width+2];	int mine_count[height][width];	// iterate through ALL the matrix, including the fake rows and cols, to set their value to 0	for(i = 0; i < height+2; i++)		for(j = 0; j < width+2; j++)			if(i==0 || j==0 || i==height+1 || j==width+1) // if it's a dummy row or column, then there is no mine				is_mine[i][j]=0;			else{				std::cin >> input;				is_mine[i][j]= input=='*' ? 1 : 0; // if it's a mine, write 1 in the matrix, 0 otherwise			}	// iterate through the cells that you want to count the close-mines-number of	// note: i and j are referring to coordinates that are valid for "is_mine". to use them in the "mine_count" matrix you need to subtract 1 to every index, to ignore the dummy column or row	for(i = 1; i < height+1; i++)		for(j = 1; j < width+1; j++)			if(!is_mine[i][j]) // if it's not a mine, sum all the mine flags nearby				mine_count[i-1][j-1] = 					is_mine[i-1][j-1]	+	is_mine[i-1][j]		+	is_mine[i-1][j+1]+					is_mine[i][j-1]		+		0		+	is_mine[i][j+1]+					is_mine[i+1][j-1]	+	is_mine[i+1][j]		+	is_mine[i+1][j+1];	// this time, i and j will refer to "mine_count" coordinates. add 1 to the indexes to use them in "is_mine"	for(i = 0; i < height; i++){		for (j = 0; j < width; j++)			if(is_mine[i+1][j+1])				std::cout << '*';			else				std::cout << mine_count[i][j];		std::cout << "\n";	}	system("pause");	return 0;}

i do not have a compiler so i couldn't test it, but yeah give it a shot and see if you like the method

Link to comment
Share on other sites

Link to post
Share on other sites

	int is_mine[height+2][width+2];	int mine_count[height][width];

arrays have to be initialized with CONST values!

To make it dynamic, I'd recommend looking up vectors. While slightly slower, I doubt minesweeper will suffer.

All you need is "#include <vector>" and replace those 2D arrays with std::vector<std::vector<int>> *nameHere*;

But please do research them if you want to use them as they have slightly different behavior than standard arrays.

Link to comment
Share on other sites

Link to post
Share on other sites

arrays have to be initialized with CONST values!

To make it dynamic, I'd recommend looking up vectors. While slightly slower, I doubt minesweeper will suffer.

All you need is "#include <vector>" and replace those 2D arrays with std::vector<std::vector<int>> *nameHere*;

But please do research them if you want to use them as they have slightly different behavior than standard arrays.

that's actually allowed with C99 standard, it's a feature called "variable size arrays" (i think so) so it should actually compile and run fine

(edit: "Variable Length Arrays")

 

anyway that's a fancy way of doing things, i don't recommend that either, even thought sometimes it's actually a better choice

the "correct" way would be using the "new" construct to dinamically allocate an array into the heap, or as an alternative, vectors

i kept using that method not to make it even more different from the user's original code

Link to comment
Share on other sites

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×