I am working on a minesweeper assignment right now. And I used recursion to implement the function that removes an empty area. However my program always runs into eroor. The error message states:
a Exception in thread "AWT-EventQueue-0" java.lang.StackOverflowError
And this is my code, I know it looks messy, apologize in advance. I would appreciate any help!
public void removeEmptyRegion(int x, int y){ //note: uses recursive decomposition
if (x < 0 || x > width-1 || y < 0 || y > length-1) {
return; // check for bounds
}else if(tiles[y][x].getClicked()){ //first time activated this method
//checks the tiles surround it
removeEmptyRegion(x,y+1);//up
removeEmptyRegion(x,y-1);//down
removeEmptyRegion(x+1,y);//left
removeEmptyRegion(x-1,y);//right
removeEmptyRegion(x-1, y+1); //up-left
removeEmptyRegion(x+1, y+1); //up-right
removeEmptyRegion(x-1,y-1); //down-left
removeEmptyRegion(x+1,y-1); //down-right
}
else if(!(tiles[y][x].getValue() == -1) && tiles[y][x].getClicked() == false ) {
//check: -1 indicates it is a bomb
if(tiles[y][x].getValue() == 0) {
tiles[y][x].clickTile();
//chain reaction
removeEmptyRegion(x,y+1);//up
removeEmptyRegion(x,y-1);//down
removeEmptyRegion(x+1,y);//left
removeEmptyRegion(x-1,y);//right
removeEmptyRegion(x-1, y+1); //up-left
removeEmptyRegion(x+1, y+1); //up-right
removeEmptyRegion(x-1,y-1); //down-left
removeEmptyRegion(x+1,y-1); //down-right
return;
}else { //stops if the tile is a numbered tile
tiles[y][x].clickTile();
return;
}
} else {
return;
}
}
You check each possible direction from each tile recursively.
Say your code is at 0,0 and now it checks the tile above. Now it's at 0,1. Then, from 0,1 your code checks a few directions, including down. Now it's back at 0,0. This repeats infinitely, causing a stack overflow.
I suggest using something called memoization.
Create a boolean[][] with the same dimensions as your minesweeper grid. When you check a square, mark boolean[y][x]=true.
At the top of your method where you check if you are out of bounds, use if (boolean[y][x]) to check if you've already checked there.
Related
I've got a program that can hexagonal tiles using images that are loaded into it. It creates these tiles images by replacing any pixels outside the hexagon with transparent pixels using a function called inHex(). This works.
Now I want to create a border on the inner edge of the hexagon. So I modified a copy of inHex(), changing the &&s to ||s, and adding two lines for the flat edges. The problem is that only the upper borders get drawn.
I've tried changing the order of the statements, and replacing all of the ors with separate if statements, no dice. Using System.out.print line in the loop I know hexEdge() doesn't return true when it should except for the upper lines.
public boolean hexEdge(int x, int y)
{
/**
* returns true if the coordinates are inside the hexagon bounded by the width and height of the tile
*/
double slope = (tileHeight/2.0)/(tileWidth);
boolean inside=false;
//check in acordance to sides
if (x<(tileWidth/2 +1) )
{
inside=
( y == (int)(0.25*tileHeight-slope*x) ) ||//this works
( y == (int)(0.75*tileHeight+slope*x) ) ||
(x==0 && y>(int)(0.25*tileHeight) && y<=(int)(0.25*tileHeight) );
}else {
int x2=x-tileWidth/2;
inside =
(y == (int)(0+slope*x2) )||//this works
(y == (int)(tileHeight -slope*x2 ) )||
(x==tileWidth-1 && y>(int)(0.25*tileHeight) && y<=(int)(0.25*tileHeight) );
}
return inside;
}
I am writing a simple minesweeper, but I can't find a way to reveal the adjacent tiles properly. If a tile is blank, it is revealed and then the algorithm reveals all adjacent blank tiles. However I would like to reveal a layer of non blank tiles as well, just like the real minesweeper.
Here is my code:
void revealAdjCells(Tile [][] t,int x, int y) {
if (!checkBounds(x,y)) {
return; // check for bounds
}
if ((t[x][y].getNeighbours() == 0) && (!t[x][y].getVisibleState())) { // NO neighbours and not revealed
t[x][y].setVisibleState(true); // reveal tile
revealAdjCells(t,x+1,y); // recursion, reveal adjacent tiles
revealAdjCells(t,x-1,y);
revealAdjCells(t,x,y-1);
revealAdjCells(t,x,y+1);
}
else
{
return;
}
}
getNeighbours() returns the amount of bombs that surround a nearby tile (horizontal,vertical,diagonal) and getVisibleState() returns a boolean that indicates whether a tile has been revealed or not.
Things that I have tried:
1) Removing getVisibleState() from if condition (terrible idea, leads obviously to stack overflow).
2) Checking bounds (x-1,x+1,y+1,y-1) and then revealing the tiles accordingly (doesn't work, getVisibleState() won't let the statement execute, because the tile that is examined by the recursion is already revealed).
So... yeah... I am stuck and I can't find a solution. Any algorithmic help is appreciated.
Your code is close, but you're not revealing the tile if t[x][y].getNeighbours() != 0 and you should be doing this. Perhaps something like:
void revealAdjCells(Tile [][] t,int x, int y) {
// if out of bounds **or** if already revealed, return
if (!checkBounds(x,y) || t[x][y].getVisibleState()) {
return;
}
t[x][y].setVisibleState(true); // reveal tile **here **
// do recursion only if no neighbors
if (t[x][y].getNeighbours() == 0) {
// t[x][y].setVisibleState(true); // not **here**
revealAdjCells(t,x+1,y);
revealAdjCells(t,x-1,y);
revealAdjCells(t,x,y-1);
revealAdjCells(t,x,y+1);
} else {
return;
}
}
I have a tester program which is used to build the start of a game.
I am having issues with the velocity attributes in the if statements which are supposed to create the bounce effect off the sprite of the screen but I can't seem to get the correct combination. Been working on this for a good while and cant seem to get any progress. Any help will be appreciated.
On a side note, in the else if methods there is a attribute called getWidth and getHeight, this is supposed to get the height and width of the screen. But I am unsure if it does. I can attach that class if needed. But below I will add the method I have for trying to create this "Bounce" effect of the edges of my screen.
public void checkScreenEdge(Sprite s){
if (s.getX() > getWidth()){
}
else if (s.getX() + s.getWidth() >= getWidth());
{
}
if (s.getY() > getHeight()) {
}
else if (s.getY() + s.getHeight() >= getHeight())
{
}
}
If you're using a deltaX and deltaY value (or velocity value) to decide which direction to move, simply change the value from positive to negative or visa versa at the appropriate location. For example:
if (s.getX() <= 0) {
s.setDeltaX(Math.abs(s.getDeltaX());
} else if (s.getX() + s.getWidth() >= MAX) {
s.setDeltaX(-Math.abs(s.getDeltaX());
}
I feel that it's important to use absolute value rather than directly swapping deltaX values, because if you did this:
if (s.getX() <= 0) {
s.setDeltaX(-s.getDeltaX());
}
you risk the sprite being "trapped" at the edges with the deltas being flipped repeatedly due to an over-shoot.
I'm given two points per rectangle, the top left and bottom right (with the points for the two rectangles being denoted as bR1 and bR2, the top left points being denoted as tL1 and tL2, et cetera), and I want to find out if the two rectangles overlap. Right now my code is as follows:
if(!(bR1.y < tL2.y ||
tL1.y > bR2.y ||
bR1.x < tL2.x ||
tL1.x > bR2.x ) )
//if this combination of conditions are met, then the rectangles overlap at some point
//
{
System.out.println("overlap found");
}
else if (rectangle1.tL.equals(rectangle2.tL) &&
rectangle1.bR.equals(rectangle2.bR))
//if this combination of conditions are met, then the rectangles are perfectly on top of one another
{
System.out.println("rectangles completely overlap");
}
else if(bL1.x>bL2.x &&
bL1.y<bL2.y &&
tR1.x<tR2.x &&
tR1.y>tR2.y) //if rectangle1 is within rectangle2
{
System.out.println("one rectangle completely within another");
}
else if(bL1.x<bL2.x &&
bL1.y>bL2.y &&
tR1.x>tR2.x &&
tR1.y<tR2.y)//if rectangle2 is within rectangle1
{
System.out.println("one rectangle completely within another");
}
Based on my tests, my algorithm is finding too few overlaps. I am almost certain that the only issue with my algorithm is that it does not account for squares were only the edges or corners are touching. Is this the case? If it is, then how do I address the issue of only edges overlapping? (I can easily address the corners touching issue the same way I address the rectangles fitting perfectly on top of one another.)
Here is how it's solved in java AWT source code of Rectangle2D: http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/awt/geom/Rectangle2D.java#675
In general you can use something similar to:
if (Math.max(tL1.x, tL2.x) <= Math.min(bR1.x, bR2.x) &&
Math.max(tL1.y, tL2.y) <= Math.min(bR1.y, bR2.y)) {
// It covers all cases of intersection including equality and inclusion.
}
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 9 years ago.
I am trying recreate the board game "go" in Java. I am currently working on the capturing system. Basically once a stone has been surrounded by the enemy stone on all four sides (diagonal don't count) you remove that stone. Like in the screenshot below.
Or if multiple of the same stones are connected you have to surround all the open sides. Like in the screenshot below.
In both cases the black stones should be removed at this point. This link explains more on the rules of capturing stones. societies.cam. ac. uk /cugos/go/rules_03.html
I was told it would be best to use recursion to do this. After doing some research on recursion I managed to write some code. But it's not working. It only seems to detect the enemy stone on the second move of the game. I call my method every time a stone is placed in my mouseReleased.
public static boolean checkCapture(int x, int y)
{
{
if ((board[x][y + 1] != move) && (board[x][y + 1] != 0)) //bellow
{
System.out.println("enemy is bellow");
if (checkCapture(x, y + 1))
board[x][y] = 0;
} else if (board[x][y + 1] == 0)
{
return false;
}
if ((board[x][y - 1] != move) && (board[x][y - 1] != 0)) //above
{
System.out.println("enemy is above");
if (checkCapture(x, y - 1))
board[x][y] = 0;
} else if (board[x][y - 1] == 0)
{
return false;
}
if ((board[x + 1][y] != move) && (board[x + 1][y] != 0)) // right
{
System.out.println("enemy is right");
if (checkCapture(x + 1, y))
board[x][y] = 0;
} else if (board[x + 1][y] == 0)
{
return false;
}
if ((board[x - 1][y] != move) && (board[x - 1][y] != 0)) //left
{
System.out.println("enemy is left");
if (checkCapture(x - 1, y))
board[x][y] = 0;
} else if (board[x - 1][y] == 0)
{
return false;
}
}
return true;
}
My int x is my column and my int y is my row, move is my variable that holds whose turn it is( 1 = black , 2 = white) board is my 2d array that holds the position of all the stones on the board.
I think that recursion complicates this solution more than necessary. If I were to implement something like this, I would take the following steps:
Find connected groups of stones. You can limit this to just dragons if you can detect if a group is alive because it has two eyes.
For each group of connected stones, count the liberties vertically and horizontally. (Liberties are unoccupied locations adjacent to a connected group of stones.) If the number of liberties is 0, then the group is captured.
If you are checking for a capture after a move has been made, then you really only need to check the connected groups which are adjacent to the most recent move, not all connected groups.
First, start out by being explicit about what your function does.
/**
* Checks to see if the grid point passed in is captured.
* #param...(you should say what your params are here
**/
public static boolean checkCapture(int x, int y) {
//some code
}
This is important: what if this function checks to see if the gird point is capturing some other, arbitrary point? Further, we immediately see a problem... captured by who? Whenever solving a recursive problem you need to understand the base case: here it is that there is no vertical or horizontal adjacent area that isn't occupied by an enemy.
Therefore, we must check to see in regards to a particular color:
/**
* Checks to see if the grid point passed in is captured.
* #param...(you should say what your params are here
**/
public static boolean checkCapture(int x, int y) {
if (!isOccupied(x,y)) {//writing this function should be trivial
return false;//can't be captured; no one is there!
}
Color color = getColor(x,y);//similarly, get the color of whoever is there.
Status status = checkFlanked(x, y, color);
if (status = Status.FLANKED) {
return true;
}
}
private static Status checkFlanked(int x, int y, Color color) {
//check to see that this location is valid for the board
//check to see if this square is occupied at all
//if it is not, return LIBERTY (an empty space means no capture, right?)
//if it is, is it occupied by the opposite color? --> Return a FLANKED result!
//if it is, is it occupied by the same color? --> recurse!
}
Now we've broken down our problem a bit! And it's easy to see how the base case is resolved: if the square is unoccupied, it can't be flanking... so it returns a LIBERTY result. If it's occupied by the opposite color, then this square is flanking whomever you were originally checking. The only difficult part is then checking to see whether, in the case of this being occupied by the original color, any other locations have liberty or not.
//get all valid adjacent locations
//call checkFlanked on those locations.
//If any return LIBERTY, return LIBERTY. Otherwise return FLANKED.
(Note: I'm assuming LIBERTY and FLANKED have been defined as an enum for clarity's sake.)
I hope this helps you break down your problem in a more sensible way. Remember: when you're using recursion, you care about two cases: the base case, and the '+1 iteration' case. Note that even with the above you have to solve some problems:
You need to intelligently not recurse back to squares you've already visited. (Investigate tail recursion, but you can also just pass in additional state indicating squares that are checked already.)
You need to make sure you don't fall off the board and return an appropriate result if you do. Basically, you need to solve the 'what is a valid location?' problem.
Some other interesting questions to ask are:
Do you search by-breadth or by-depth?
Is this appropriate as a static method, or should it be captured in a class?
I have some code that lets you play and capture stones. See this answer: https://gamedev.stackexchange.com/questions/23291/go-game-placing-stones-on-grid-intersections/23406#23406
The trick is to keep track of contiguous blocks of stones and then check after every move to see if that move captures a block.
There is also ko to worry about.
The problem with recursion in this case is it is very easy to fall into an infinite loop. Checking two stones, checking the right stone will check the left stone will check the right again etc. You need to keep track of the stones you have already checked. You are going to need to pass some state of the stones that you have already checked.