I have been trying to make a minesweeper game where given coordinates for a cell it will recursively reveal adjacent cells until a cell adjacent to a bomb is found. I have a method that given coordinates x and y calculates how many mines are surrounding it.
// Counts how many mines are adjacent to a given coordinate cell if any
void board::mineCount(int x, int y) {
// North
if (y > 0) {
if (board[x][y - 1].hasMine) {
board[x][y].mineCount++;
}
}
// South
if (y < dimensions[1] - 1) {
if (board[x][y + 1].hasMine) {
board[x][y].mineCount++;
}
}
// East
if (x < dimensions[0] - 1) {
if (board[x + 1][y].hasMine) {
board[x][y].mineCount++;
}
}
// West
if (x > 0) {
if (board[x - 1][y].hasMine) {
board[x][y].mineCount++;
}
}
// North East
if (x < dimensions[0] - 1 && y > 0) {
if (board[x + 1][y - 1].hasMine) {
board[x][y].mineCount++;
}
}
// North West
if (x > 0 && y > 0) {
if (board[x - 1][y - 1].hasMine) {
board[x][y].mineCount++;
}
}
// South East
if (x < dimensions[0] - 1 && y < dimensions[1] - 1) {
if (board[x + 1][y + 1].hasMine) {
board[x][y].mineCount++;
}
}
// South West
if (x > 0 && y < dimensions[1] - 1) {
if (board[x - 1][y + 1].hasMine) {
board[x][y].mineCount++;
}
}
}
Each cell is a struct which has a mineCount field that gets incremented by 1 each time a mine is found adjacent to it. I am having trouble figuring out where my recursion logic would go. I tried doing something like:
// North
if (y > 0) {
if (board[x][y - 1].hasMine) {
board[x][y].mineCount++;
} else {
minecount(x, y-1);
}
}
for each position but to no avail. Any pointers would be appreciated.
The recursion shouldn't be a part of the code that performs the mine count itself. It should be part of the function that's responsible for revealing nearby tiles.
int get_adjacent_mine_count(point p) {
int mine_count = 0;
for(int i = -1; i <= 1; i++) {
for(int j = -1; j <= 1; j++) {
point this_point(p.x + i, p.y + j);
//is_inside_board checks to see if the point's coordinates are less than 0
//or greater than the board size
if(!is_inside_board(board, this_point)) continue;
//We ignore the center tile
if(i == 0 && j == 0) continue;
if(board(this_point).hasMine)
mine_count++;
}
}
return mine_count;
}
void reveal_tiles(point p) {
//We shouldn't throw if the recursion is correct
if(board(p).hasMine) throw Explosion("Stepped on a Mine!");
//Single call to previously defined function
int num_of_adjacent_mines = get_adjacent_mine_count(p);
//I'm assuming this gets initialized to -1 beforehand
board(p).revealed = num_of_adjacent_mines;
if(num_of_adjacent_mines == 0) {
for(int i = -1; i <= 1; i++) {
for(int j = -1; j <= 1; j++) {
point this_point(p.x + i, p.y + j);
if(!is_inside_board(board, this_point)) continue;
if(i == 0 && j == 0) continue;
if(board(this_point).revealed == -1)
reveal_tiles(this_point);
}
}
}
}
I'm going to strongly recommend you write a simple Matrix class to represent board, which my code implies you've done, because that's a much more robust solution than just trying to interact with a 2D array the C-style way you're doing it.
Related
This function in the Game of Life assignment is supposed to loop through the 2nd array and check to see how many neighbors each cell has. When I call this in the main, not even in any sort of loop, the terminal freezes as if in an infinite while loop. Can anyone tell me what's wrong with my code? Thanks.
void Grids::simulate(int** myGrid, int rows, int columns)
{
int neighbors = 0; //variable to store how many neighbors a cell has
for (int r = 0; r < rows; ++r) // iterates through rows
{
for(int c = 0; c < columns; ++c)//iterates through columns
{
for(int x = -1; x < 2; x + 2) //iterates through -1 and 1, the spaces next to the cell
{
for(int y = -1; y < 2; y + 2)
{
if ((r + x >= 0) && (r + x < rows) && (c + y >= 0) && (c + y < columns)) //prevents indexing the 2d array outside of its bounds
{
if (myGrid[r + x][c + y] == 1) //checks if the surrounding cells are alive
{
++neighbors;
}
}
}
}
if (neighbors < 2) //underpopulation
{
myGrid[r][c] = 0; //dead
}
else if (neighbors == 3) //reproduction
{
myGrid[r][c] = 1; //alive
}
else if (neighbors >= 4) //overpopulation
{
myGrid[r][c] = 0; //dead
}
}
}
}
You should change this x + 2 to x += 2 and y + 2 to y += 2, to make the loop increase by 2 each cycle. I also advise you to remove extra parentheses in this line if (r + x >= 0 && r + x < rows && c + y >= 0 && c + y < columns).
So I'm trying to check if the cells surrounding the current cell of any given 2D array have a certain value (0 or 1) and depending on the value I want to count the total amount (total 1 values surrounding the current cell) however I'm not sure how to grab the positions below is some psuedocode I wrote that I think will consider each general position for a cell to be in however I'm not completely certain it is correct, and if it is correct I'm not sure how to grab the surrounding cells. Its not necessary to write out the whole code but basically I'm looking for conditions for positions to check for in future nested if statements that will of these big if statements such as array
if array([xPosition+1][yPosition+1] == 1)
Here is the pesudocode
if (xPosition==0 && yPosition==0) {
} else if (xPosition==rows && yPosition==columns) {
} else if (xPosition==rows && yPosition==0) {
} else if (xPosition==0 && yPosition==columns) {
} else if (xPosition==0) {
} else if (xPosition==rows) {
} else if (yPosition==0) {
} else if (yPosition==columns) {
} else {
}
You can use nested loops
int sum{0};
for (int x{std::max(xPosition, 1) - 1}; x < std::min(xPosition + 2, columns); ++x) {
for (int y{std::max(yPosition, 1) - 1}; y < std::min(xPosition + 2, rows); ++y) {
if (x == xPosition && y == yPosition) continue;
sum += array[x][y];
}
}
The code is self explanatory and I have added the comments
bool isSafe(int xPosition, int yPosition,
int rows, int columns) { // checking the boundry
return (xPosition >= 0 && xPosition < rows &&
yPosition >= 0 && yPosition < columns);
}
void checkNeighbours(int xPosition, int yPosition,
int rows, int columns) {
// Considering only 4 directions up, down , right, left
int count = 0;
if(isSafe(xPosition - 1, yPosition)) { // one cell up
if(array[xPosition - 1][yPosition] == 1) {
count ++;
}
}
if(isSafe (xPosition + 1, yPosition)) { // one cell down
if(array[xPosition + 1][yPosition] == 1) {
count ++;
}
}
if(isSafe(xPosition, yPosition - 1)) { // one cell left
if(array[xPosition][yPosition - 1] == 1) {
count ++;
}
}
if(isSafe(xPosition, yPosition + 1)) { // one cell right
if(array[xPosition][yPosition + 1] == 1) {
count ++;
}
}
// use count for whatever
}
I'm fighting with this for like few days, and I have no idea, how to do that, so I'd like to ask you for help. I've got no idea how collision should look like right here, so player could jump through 'down zone' of the block, and stay right on the block.
block.cpp
bool block::CollidingWithPlayer(character& player) {
for (int i = 1; i < MAX_BLOCKS; i++) {
if (player.x + player.width >= coordinateX[i] && player.x <= coordinateX[i] + width[i] && player.y + player.height >= coordinateY[i] && player.y <= coordinateY[i] + block_height) {
player.onGround = true;
return true;
}
}
}
character.cpp
void character::startJump(map& Map, character& player) {
if (onGround)
{
vel[1] = -11.0;
onGround = false;
}
}
void character::updateJump(block& Block, character& player) {
if (!onGround) {
Block.CollidingWithPlayer(player);
vel[1] += 0.5;
y += vel[1];
x += vel[0];
}
if (y > 460){
y = 460;
vel[1] = 0.0;
onGround = true;
vel[0] = 0.0;
}
if ((x + width >= START_OF_RIGHT_WALL && x <= WALL_WIDTH + START_OF_RIGHT_WALL) || (x + width >= START_OF_LEFT_WALL &&x <= START_OF_LEFT_WALL + WALL_WIDTH)){
vel[0] *= -1;
bound = true;
if (direction == 1)
direction = 2;
else if (direction == 2)
direction = 1;
}
}
I am trying to create a maze generator using recursive backtracking and have come across a problem that I just can't get my head around. For some reason my move function is returning the value "18446744073709551615". This is (of course) leading to a segmentation fault. Why is my move function returning such a large value when my move function can only increase or decrease the value by 2?
bool maze::generate(size_t x, size_t y) {
//mark the position as visited
labyrinth.s[y][x] = true;
//print to see progress
//this->print();
//if the position is not out of bounds
if (x < 0 || x > labyrinth.MAXWIDTH - 1 || y < 0 || y > labyrinth.MAXHIGHT - 1) {
//if the position is the endpoint return true
if (labyrinth.v[y][x - 1] == 'W' || labyrinth.v[y][x + 1] == 'W' || labyrinth.v[y - 1][x] == 'W' || labyrinth.v[y + 1][x] == 'W') {
return true;
}
}
//pick a random direction
do {
d = size_t(rand() % 4);
} while(!this->pos_test(x, y, d));
std::cout << x << ' ' << y << std::endl;
if (d == UP) {
y = move(x, y, UP);
}
else if (d == DOWN) {
y = move(x, y, DOWN);
}
else if (d == RIGHT) {
x = move(x, y, RIGHT);
}
else if (d == LEFT) {
x = move(x, y, LEFT);
}
else{
}
std::cout << x << ' ' << y << std::endl;
//recursively generate the maze
if (this->generate(x, y)) {
return true;
}
}
void maze::initialize(size_t x, size_t y) {
//set the maxhight and the maxwidth to y and x
labyrinth.MAXHIGHT = y;
labyrinth.MAXWIDTH = x;
//set all elements in the vector to #
for (size_t i = 0; i < labyrinth.MAXHIGHT; i++) {
std::vector<char> temp;
for (size_t j = 0; j < labyrinth.MAXWIDTH; j++) {
temp.push_back(labyrinth.wall);
}
labyrinth.v.push_back(temp);
}
for (size_t i = 0; i < labyrinth.MAXHIGHT; i++) {
for (size_t j = 0; j < labyrinth.MAXWIDTH; j++) {
if (j % 2 == 1 && i % 2 == 1 && j != labyrinth.MAXWIDTH - 1 && j != 0 && i != labyrinth.MAXHIGHT - 1 && i != 0) {
labyrinth.v[j][i] = labyrinth.path;
}
}
}
//set all posistions to unvisited
for (size_t i = 0; i < labyrinth.MAXHIGHT; i++) {
std::vector<bool> temp2;
for (size_t j = 0; j < labyrinth.MAXWIDTH; j++) {
temp2.push_back(false);
}
labyrinth.s.push_back(temp2);
}
//setup the start point
labyrinth.v[0][1] = 'S';
//setup the endpoint
labyrinth.v[labyrinth.MAXHIGHT - 2][labyrinth.MAXWIDTH - 1] = 'W';
}
//if a position has been visited or if not possible to go to return true
bool maze::pos_test(size_t x, size_t y, size_t d) const {
//if the position is out of bounds return false
if (x < 0 || y < 0 || x > labyrinth.MAXWIDTH - 1 || y > labyrinth.MAXHIGHT - 1) {
return true;
}
else if (x == 1 && d == LEFT) {
return true;
}
else if (y == 1 && d == UP) {
return true;
}
else if (x == labyrinth.MAXWIDTH - 1 && d == RIGHT) {
return true;
}
else if (y == labyrinth.MAXHIGHT - 1 && d == DOWN) {
return true;
}
else if (d == UP) {
return labyrinth.s[y - 2][x];
}
else if (d == DOWN) {
return labyrinth.s[y + 2][x];
}
else if (d == RIGHT) {
return labyrinth.s[y][x + 2];
}
else if (d == LEFT) {
return labyrinth.s[y][x - 2];
}
else {
return true;
}
}
size_t maze::move(size_t x, size_t y, size_t d) {
//if the position is out of bounds return without modifying
if (x < 0 || x > labyrinth.MAXWIDTH - 1) {
return x;
}
else if (y < 0 || y > labyrinth.MAXHIGHT - 1) {
return y;
}
else if (d == UP) {
labyrinth.v[y - 1][x] = labyrinth.path;
return y = y - 2;
}
else if (d == DOWN) {
labyrinth.v[y + 1][x] = labyrinth.path;
return y = y + 2;
}
else if (d == RIGHT) {
labyrinth.v[y][x + 1] = labyrinth.path;
return x = x + 2;
}
else if (d == LEFT) {
labyrinth.v[y][x - 1] = labyrinth.path;
return x = x - 2;
}
else {
}
}
You are underflowing your unsigned 64-bit return type size_t.
You are checking whether x and y are below zero, but that's not enough, because 0 and 1 will still be too low because you are subtracting 2!
The number you get is 0xFFFFFFFFFFFFFFFF in hexadecimal. This is the highest possible value for an unsigned 64-bit integer.
It comes from calculating 1 - 2. Yes, this is supposed to be -1, but because your move function doesn't return a signed number but an unsigned one (check the docs on size_t), it can't be negative! Instead, it wraps around to the highest possible number.
You can imagine this in the same way you would get ...99999999999 when you try to calculate 1 - 2 on paper ignoring the "you can't subtract a higher number from a smaller one on paper" rule.
As a side note: I guess the negative result is undesired anyway, because actually your huge number, once added to a pointer, will in turn overflow back into positive, so basically it will work the same is a real -1 in your case and the segmentation fault comes from accessing something right before the beginning of your buffer, not far beyond it, but it comes down to the same thing.
Apart from that, there is no need to do return y = y - 2 and such. Just return y - 2.
This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 11 years ago.
I'm writing Snake in C++, using OpenGL and GLFW. I'm trying to implement a feature where the game exits, when the snakes head crashes into its body.
Here are the move() and CrashCheck() functions of the Snake class that I wrote.
x_pos is a floating point array that stores the x_coordinate of a segment of the snake body. y_pos does the same with the y_coordinate. length is the number of body segments in the snake, and increases when the snake eats food(not yet implemented). x_speed and y_speed store the speeds of the segments along the axis. The snake can never move along both the axes simultaneously; Also, float MAX_S = 0.00075;. I've included my draw() function as well. And Fix_Snake_x and Fix_Snake_y are functions that realign the segments of the snake (because they kept separating and causing havoc with the game). I know it's a stupid way to correct the problem, so if you can suggest fixes in the move() function, that would helpful.
void draw(float win_aspect)
{
for(int a = 0; a < length; a++)
{
Fix_Snake_y();
glBegin(GL_QUADS);
glColor3f(1.0,0.0,0.0);
glVertex2f(x_pos[a],y_pos[a]);
glVertex2f((x_pos[a]+0.05),y_pos[a]);
glVertex2f((x_pos[a]+0.05),y_pos[a]-0.05);
glVertex2f(x_pos[a],y_pos[a] - 0.05);
glEnd();
Fix_Snake_x();
}
}
void move()
{
for(int a = length ; a >= 0; a--)
{
if(a > 0)
{
if(x_pos[a] >= x_pos[a-1] && x_speed[a] < 0)
{
x_pos[a] += -MAX_S;
Fix_Snake_y();
Fix_Snake_x();
if(x_pos[a] <= x_pos[a - 1])
{
x_speed [a] = 0;
if(y_pos[a] <= y_pos[a-1])
{
y_speed[a] = MAX_S;
}
else
{
y_speed[a] = -MAX_S;
}
}
}
if(x_pos[a] <= x_pos[a-1] && x_speed[a] > 0)
{
x_pos[a] += MAX_S;
Fix_Snake_y();
Fix_Snake_x();
if(x_pos[a] >= x_pos[a - 1])
{
x_speed [a] = 0;
if(y_pos[a] <= y_pos[a-1])
{
y_speed[a] = MAX_S;
}
else
{
y_speed[a] = -MAX_S;
}
}
}
if(y_pos[a] <= y_pos[a-1] && y_speed[a] > 0)
{
y_pos[a] += MAX_S;
Fix_Snake_y();
Fix_Snake_x();
if(y_pos[a] >= y_pos[a-1])
{
y_speed[a] = 0;
if(x_pos[a] >= x_pos[a-1])
{
x_speed[a] = -MAX_S;
}
if(x_pos[a] <= x_pos[a-1])
{
x_speed[a] = MAX_S;
}
}
}
if(y_pos[a] >= y_pos[a-1] && y_speed[a] < 0)
{
y_pos[a] += -MAX_S;
Fix_Snake_y();
Fix_Snake_x();
if(y_pos[a] <= y_pos[a-1])
{
y_speed[a] = 0;
if(x_pos[a] >= x_pos[a-1])
{
x_speed[a] = -MAX_S;
}
if(x_pos[a] <= x_pos[a-1])
{
x_speed[a] = MAX_S;
}
}
}
}
if(a == 0)
{
x_pos[0] += x_speed[0];
y_pos[0] += y_speed[0];
Fix_Snake_y();
Fix_Snake_x();
}
CrashCheck();
}
}
void CrashCheck()
{
for(int a = 1; a < length; a++)
{
if(y_speed[0] > 0 && y_speed[a] == 0)
{
if(x_pos[0] < x_pos[a] && x_pos[0] < x_pos[a] + 0.05)
{
if(y_pos[0] < y_pos[a] && y_pos[0] > y_pos[a] - 0.05)
{
exit(0);
}
}
}
else if(y_speed[0] < 0 && y_speed[a] == 0)
{
if(x_pos[0] > x_pos[a] && x_pos[0] < x_pos[a] + 0.05)
{
if(y_pos[0] < y_pos[a] && y_pos[0] > y_pos[a] - 0.05)
{
exit(0);
}
}
}
}
}
void Fix_Snake_x()
{
for(int a = 1; a<length; a++)
{
if(a > 0)
{
if(x_pos[a] <= x_pos[a-1] - 0.05)
{
x_pos[a] = x_pos[a-1] - 0.05;
}
if(x_pos[a] >= x_pos[a -1] + 0.05)
{
x_pos[a] = x_pos[a-1] + 0.05;
}
}
}
}
void Fix_Snake_y()
{
for(int a = 1; a < length; a++)
{
if(a > 0)
{
if(y_pos[a] <= y_pos[a-1] - 0.05)
{
y_pos[a] = y_pos[a-1] - 0.05;
}
if(y_pos[a] >= y_pos[a-1] + 0.05)
{
y_pos[a] = y_pos[a-1] + 0.05;
}
}
}
}
Edit:
New move function
for(int a = 0; a < length; a++)
{
if(a > 0)
{
if(x_speed[a] < 0 && x_pos[a] >= x_pos[a-1])
{
x_pos[a] += x_speed[a];
if(x_pos[a] == x_pos[a-1])
{
y_speed[a] = y_speed[a-1];
x_speed[a] = 0;
continue;
}
}
if(x_speed[a] > 0 && x_pos[a] <= x_pos[a-1])
{
x_pos[a] += x_speed[a];
if(x_pos[a] == x_pos[a-1])
{
y_speed[a] = y_speed[a-1];
x_speed[a] = 0;
continue;
}
}
if(y_speed[a] > 0 && y_pos[a] <= y_pos[a-1])
{
y_pos[a] += y_speed[a];
if(y_pos[a] == y_pos[a-1])
{
x_speed[a] = x_speed[a-1];
y_speed[a] = 0;
}
}
if(y_speed[a] < 0 && y_pos[a] >= y_pos[a-1])
{
y_pos[a] += y_speed[a];
if(y_pos[a] == y_pos[a-1])
{
x_speed[a] = x_speed[a-1];
y_speed[a] = 0;
}
}
}
else
{
x_pos[0] += x_speed[0];
y_pos[0] += y_speed[0];
}
}
Is causing a few problems. The snake breaks it there are too many simultaneous turns. Only the first two blocks remain in motion
If I were you, I would store a std::set with all the invalid coordinates that the snake can't go to. That would include:
the border of the "playground"
obstacles
the snake's body
Then for each move of the snake, considering the x/y speed(s) I would first try to InsertLocation into CInvalidPlaces, if that returns true then I can step there, if false then the snake's just about to hit a wall, the border or it's own body and the "game" can finish. Here's the code for that:
#include <set>
using namespace std;
typedef pair<int,int> tInvalidLocation;
struct ltSeCmp
{
bool operator()(tInvalidLocation s1, tInvalidLocation s2) const
{
if (s1.first == s2.first) return s1.second > s2.second;
return s1.first > s2.first;
}
};
typedef set<tInvalidLocation, ltSeCmp> tInvalidLocations;
class CInvalidPlaces
{
private:
tInvalidLocations mInvalid; //this set will hold all the invalid locations for the snake to go to
public:
bool InsertLocation(tInvalidLocation iLoc)
{
if (mInvalid.find(iLoc) != mInvalid.end()) return false; //check if the location is already in the set
//we survived.. it's safe to go there :)
mInvalid.insert(iLoc);
return true;
}
bool RemoveLocation(tInvalidLocation iLoc)
{
if (mInvalid.find(iLoc)== mInvalid.end()) return false;
mInvalid.insert(iLoc);
return true;
}
};
What you will have to do additionally is :
initially add the margins, all the obstacles, and all the positions of the snake just as they are from where the snake starts
modify the move routine, so that when the snake moves, it also has to remove from CInvalidPlaces it's tail using RemoveLocation
after you implement the "enlargement" of the snake you'll also have to add to CInvalidPlaces the extra segment.
If need be, you can find in the following places extra information about an stl::set :
SGI
CPP.com
HTH,JP
I highly recommend that you use a dynamic container to hold the coordinates of the snakes's body. This allows to you take the coordinate of the snakes new position and search the container for the coordinates. If the point is found, the snake has run into itself.
Similarly you can have container for points of walls and blocks and other entities that is not part of the board.
An alternative is to use a grid data structure (or matrix), and place values in it representing the snakes body and other obstacles.