I'm trying to make a Minesweeper-like game in Java and I've got most of it to work. Something I need help with is FloodFill - http://en.wikipedia.org/wiki/Flood_fill.
Can someone explain how it works? I've looked online but I don't really understand the explanation so I thought it would be easier to ask here.
In my Minesweeper I have:
JButton[] btn = new JButton[100]//buttons being clicked and displaying the values/bombs
int[] mines = new int[100];//int array holding the values for each button.
The grid is a 10x10 grid so say the button you clicked was btn[14],
btn[4] // north of btn[14](14-10)
btn[24] // south of btn[14](14+10)
btn[13] // west of btn[14](14-1)
btn[15] // east of btn[14](14+1)
So back to the question, could someone explain it to me?
EDIT:
I changed my code to be 2D so instead of the above one it is now
btn[1][4]//row one, column 4
When the button is clicked, i want it to check a variable called mines[][] which has the values and if the value is equal to 0(around the initial clicked) it changes the BG
btn[x][y].setBackground(Color.GRAY);
Its a recursive algorithm. You start at some start position in a 2D Grid [x,y], then look in all directions and fill them if you can. If (x,y) can't be filled, return.
void floodFill( int x, int y ) {
if ( btn( x, y ) isFillable ) {
fillBtn(x,y);
floodFill( x+1, y );
floodFill( x-1, y );
floodFill( x, y-1 );
floodFill( x, y+1 );
} else {
return;
}
}
(ommited check for boundaries of grid)
I guess you are mainly asking about floodfill.
Actually it is a simple and common recursive algorithm. It can solve whatever your data structure is 1D or 2D.
For 2D version, #RMoeller has given the answer.
For your previous 1D declaration, it is also similar like this:
void floodFill( int pos ) {
if ( btn( pos ) isFillable ) {
fillBtn(pos);
floodFill( pos+1 );
floodFill( pos-1 );
floodFill( pos+10 );
floodFill( pos-10 );
} else {
return;
}
}
One thing you should remember is that floodfill, and almost all recursive algorithms, need to check boundaries. Otherwise you may get into an infinite loop or get a wrong result.
In above example (1D version), you should check whether:
pos >= 1 && pos <= 100
Similar to 2D version which is to check:
x >= 1 && x <= 10 && y>=1 && y <=10
Hope this helps.
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 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.
I have this program to detect objects in a binarized BufferedImage, which the image is a multiple choice answer sheet.
I'm trying to use 4-Connectivity as in to detect each object (answer on the sheet).
So far what I have in hand as source is these:
http://en.wikipedia.org/wiki/Connected-component_labeling
http://homepages.inf.ed.ac.uk/rbf/HIPR2/label.htm
and I have came up with this, following instructions from Wikipedia:
if(getPixel(image, x, y) != 0){
if(getPixel(image, x-1, y) !=0){
System.out.println("we are in the same region");
region[x][y] = region[x-1][y];
}
else if(getPixel(image, x-1, y) !=0 && getPixel(image, x, y-1) !=0){
System.out.println("North and West pixels belong to the same region and must be merged");
region[x][y] = Math.min(region[x-1][y], region[x][y-1]);
}
else if( getPixel(image, x-1, y) ==0 && getPixel(image, x, y-1) !=0){
System.out.println("Assign the label of the North pixel to the current pixel");
region[x][y] = region[x][y-1];
}
else if(getPixel(image, x-1, y) ==0 && getPixel(image, x, y-1) ==0){
System.out.println("Create a new label id and assign it to the current pixel");
cpt++;
region[x][y] = cpt;
}
But the problem is it creates 51 regions! and it only prints a couple of top pixels of each object (not all pixels).
Can anyone please help me to find what the problem is and how can I detect my objects?
I would appreciate any help.
You probably get a lot of regions because you do not seem to merge equal labels. There is no code for storing equal labels in your code snippet. The algorithm is a two-pass algorithm where the first pass assigns labels and the second pass merges equal labels.
Here are the condition checks quoted from the Wikipedia page:
Conditions to check:
Does the pixel to the left (West) have the same value as the current pixel?
Yes – We are in the same region. Assign the same label to the current pixel
No – Check next condition
Do both pixels to the North and West of the current pixel have the same value as the current pixel but not the same label?
Yes – We know that the North and West pixels belong to the same region and must be merged. Assign the current pixel the minimum of the North and West labels, and record their equivalence relationship
No – Check next condition
Does the pixel to the left (West) have a different value and the one to the North the same value as the current pixel?
Yes – Assign the label of the North pixel to the current pixel
No – Check next condition
Do the pixel's North and West neighbors have different pixel values than current pixel?
Yes – Create a new label id and assign it to the current pixel
Your second condition check,
else if(getPixel(image, x-1, y) !=0 && getPixel(image, x, y-1) !=0)
does not check if the left pixel and up pixel have different labels.
Furthermore, just like supersam654 mentions in the comment, the first else if will never be called. It seems like condition check (1) and (2) on the Wikipedia page should be in the opposite order. That is, first check if the left and up pixel have the same value as the current pixel but not the same label. Then, if that check fails, check if the left pixel has the same value as the current.
So try the following:
Add the label condition to your second condition check.
Switch the order of your first two condition checks.
Keep track of equal labels (i.e., which labels represent the same region).
Do a second pass over the image and merge equal labels.
I hope this helps.
While I'm not entirely sure that this answers your question, I would modify your code to look like this:
if(getPixel(image, x, y) != 0){
if(getPixel(image, x-1, y) !=0){
if(getPixel(image, x, y-1) !=0) {
System.out.println("North and West pixels belong to the same region and must be merged");
region[x][y] = Math.min(region[x-1][y], region[x][y-1]);
} else {
System.out.println("we are in the same region");
region[x][y] = region[x-1][y];
}
} else if(getPixel(image, x-1, y) ==0) {
if(getPixel(image, x, y-1) !=0) {
System.out.println("Assign the label of the North pixel to the current pixel");
region[x][y] = region[x][y-1];
} else if (getPixel(image, x, y-1) ==0) {
System.out.println("Create a new label id and assign it to the current pixel");
cpt++;
region[x][y] = cpt;
}
}
I am working on a game in which you are a simple circle that fires bullets and its multiplayer and so on. Well, I am trying to make boundaries sort of like a maze type thing that u have to go through I have tried collision detection like this:
public void checkCollisions(){
Rectangle r1 = bo.getBounds();
Rectangle d = p.getBounds();
if (d.intersects(r1))
border = true;
}
And basically if border = true then i stop the character from moving. I have 2 problems when i do this,
He doesnt stop just goes REALLY slow.
He stays at the REALLY slow state even off the border.
I use border like this:
boolean border = false;
then in my paint method i state this:
if (border)
p.dx = 0;
p.dy = 0;
p represents the Guy class :P
More of the dx and dy:
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
if (key == KeyEvent.VK_A)
dx = -2;
if (key == KeyEvent.VK_D)
dx = 2;
if (key == KeyEvent.VK_W)
dy = -2;
if (key == KeyEvent.VK_S)
dy = 2;
and for keyReleased i just change the value of dx and dy to 0
also for how the guy moves:
public void move() {
x = x + dx;
y = y + dy;
}
Please help me figure out why this isn't working.
OK, I still think a full restructuring of your game logic is in order, but I think I can shed light as to what's going on. Let's look at the various places where things are happening:
PAINT: On the Swing thread, when paint() is called, you see if there were collisions and if so zero out the speeds (assuming you fix that if block).
KEY: On the Swing thread, when a key is pressed, you set the speed according to the key pressed.
CHECK: At some unknown point, you check for collisions and record whether there was one.
MOVE: At some unknown point, you update your "guy's" position with the speed.
So here's the problem: in Java, just like any other program, you get multiple key pressed events when you're holding down a key. There will be a short delay between the first and second, and then they will repeat rapidly. Try it in a text box in your browser, the same behaviour occurs there.
So how does that affect you? Well, you're probably getting into a scenario like this:
PAINT -> speed set to zero
KEY -> speed set back to -2
MOVE -> guy is moved -2
CHECK -> border = false
PAINT -> speed set to zero again
Really, if you restructure the code so that you get a game loop that looks something like this:
public void runGame() {
while(true) {
updateSpeeds();
updatePositionFromSpeed();
repaint();
}
}
Where updateSpeeds() would instead query whether the key is down or up and also compute whether the guy could move in that direction, and updatePositionFromSpeed() would update the guy's position. Then paint() would rely only on the guy's x and y coordinates, would not write to them, and would not need to know about the speed.
here's a very easy solution.
Here's a bit of my pseudo code.
if(player.getBounds().intersects(wall.getBounds())){
//Go Back to prior position, regardless of direction coming from. Since the reverse velocity X and velocity Y directions are taken care off
x -= velX;
y -= velY;
//Then Stop at that prior position to make next move
velX = 0;
velY = 0;
}
I'm trying to think of a way to efficiently and neatly determine whether a valid move is being made with a bishop in chess.
The piece will be moved from srcX,srcY to dstX,dstY
This is part of one of my ideas:
if(srcX < dstX && srcY < dstY) {
// Moving towards the top right of the board
// Determine the decrease in X coordinate
int deltaX = dstX-srcX;
// If the move is valid, the Y coordinate will have decreased by the same number as X
int validY = dstY-deltaX;
if(validY == srcY) {
validMove = true;
}
}
but it's going to be a bit long winded, doing that for ever corner.. Can anyone think of a nicer way?
I would break it up into two steps.
1) Is it a valid destination?
2) Are there obstructions?
The first is easy to calculate. Since a bishop can only move diagonals the deltaX and deltaY must be equal.
So, if( abs(srcX-dstX) == abs(srcY-dstY) )
That rules out logically invalid moves.
Then it is a simple matter iterating through the positions in between as you have done to check for obstructions.
If it's a diagonal the x and y move shoudl be the same, so...
return Math.abs(srcx - dstx) == Math.abs(srcy - dsty);
The move is valid if:
Destx-Desty = SourceX - SourceY OR
16 - DestX- DestY = SourceX - SourceY