Why is this flood-fill algorithm not working? - java

For this question: Is there a proper algorithm for detecting the background color of a figure?, I will need to create a flood-fill algorithm to be able to separate all my pixels in groups of the same color.
I did this recursively, but it gives me a stack-overflow error. So I had to choose the iterative, queue based algorithm found here: http://en.wikipedia.org/wiki/Flood_fill#Alternative_implementations
First of all, I begin a search over all the matrix elements (elements being instances of the Pixel class).
private PixelGroup[] generatePixelGroupsFromMatrix(Pixel[][] matrix) {
PixelGroup[] tempGroups = new PixelGroups[9999999]; // Nevermind the 9999999....
int groupsFound = 0;
Pixel pixel;
for (int y = 0; y < matrix.length; ++y) {
for (int x = 0; x < matrix[0].length; ++x) {
pixel = matrix[y][x];
if (!pixel.evaluated) {
// This pixel has never been evaluated
// Therefore, it belongs to a new group
// First, we make a new group
PixelGroup newGroup = new PixelGroup();
// Begin search for connected pixels with the same color. All pixels found will belong to this new group.
findPixelsConnectedWith(pixel,newGroup);
tempGroups[groupsFound] = newGroup;
++groupsFound;
}
}
}
PixelGroup[] result = new PixelGroup[groupsFound];
for (int i = 0; i < groupsFound; ++i) {
result[i] = tempGroups[i];
}
return result;
}
So, Pixel has the following values: x, y, evaluated (boolean) and color (integer).
Then, PixelGroup is simply a class capable of holding pixels (it works).
And this is the method that is giving me trouble:
private void findPixelsConnectedWith(Pixel pixel, GroupOfPixels group) {
QueueOfPixels queue = new QueueOfPixels();
queue.add(pixel);
Pixel currentPixel;
int x,y;
Pixel neighbor;
while((currentPixel = queue.nextPixel()) != null) {
if (currentPixel.color == pixel.color && !currentPixel.evaluated) {
// This pixel has the required color, and has not been evaluated. It meets our needs.
// Add to group.
group.addPixel(currentPixel);
// Flag it as evaluated. So in the future, it will be ignored.
currentPixel.evaluated = true;
// Evaluate all 8 possible directions to find neighbor pixels
int[] xDirections = {0,1,1,1,0,-1,-1,-1};
int[] yDirections = {-1,-1,0,1,1,1,0,-1};
for (int i = 0; i < 8; ++i) {
x = xDirections[i];
y = yDirections[i];
if (pixelExists(currentPixel.y + y,currentPixel.x + x)) {
// There exists a pixel in this direction!
neighbor = getPixel(currentPixel.y + y,currentPixel.x + x);
queue.add(neighbor);
}
}
}
}
}
If you're curious, here is my QueueOfPixels class. I had to make my own with only vectors (school assignment requirement): https://codereview.stackexchange.com/questions/17823/vector-based-flood-fill-algorithm-queue-class (as far as I can tell, it simply works).
WHAT IS THE PROBLEM?
Alright, I have tested this with this image, which is 5x2 pixels (you'll need to zoom in a lot to see it): http://i.stack.imgur.com/xV0Lf.gif - the first row only has black pixels, and the second they're white. The program tells me it has found 6 pixel groups (when it should have been only 2!)
WHAT HAVE I TRIED TO DEBUG THE PROBLEM?
Well, first, before calling findPixelsConnectedWith, I placed this line:
System.out.println("The pixel (" + x + "," + y + ") has not been evaluated. Evaluating now.");
And this was the result:
The pixel (0,0) has not been evaluated. Evaluating now.
The pixel (1,0) has not been evaluated. Evaluating now.
The pixel (2,0) has not been evaluated. Evaluating now.
The pixel (3,0) has not been evaluated. Evaluating now.
The pixel (4,0) has not been evaluated. Evaluating now.
The pixel (0,1) has not been evaluated. Evaluating now.
So, as you can see, it seems like the code is unable to work with the first row (black pixels) since it thinks that every pixel in that row has not been evaluated (I expected it to say that (0,0) was not evaluated and done). But when it starts working with the second row, it does seem to work as expected (find (0,1) and then it is over).
But I still am unable to find out what is going on. Any ideas?
Edit:
My getPixel and pixelExists functions:
private boolean pixelExists(int y, int x) {
return (y > 0 && y < pixelMatrix.length) && (x > 0 && x < pixelMatrix[0].length);
}
private Pixel getPixel(int y, int x) {
return pixelMatrix[y][x];
}

Your pixelExists method should use y >= 0 and x >= 0 instead of y > 0 and x > 0.
private boolean pixelExists(int y, int x) {
return (y >= 0 && y < pixelMatrix.length) && (x >= 0 && x < pixelMatrix[0].length);
}
This may not be the only problem, but it will certainly prevent you from getting the correct answers.

Maybe pixelExists method has "y > 0" part while it should has "y>=0"?

Related

How to change RGB colour depending on mouse position in Processing3?

I am writing a little program in Processing3 that enables me to change the background to a specific colour RGB code stored in arrays. Each vale for R, G and B is stored in a separate array.
Changing the mouse horizontal position changes the colour of the background.
However this solutions code is quite repetitive, and there is a lot of if/else statements. I want to use a for() loop to simplify the code and make it less repetitive. However, i am struggling to include the mouse position variable in the for() loop. Is there to simplify this code using a for() loop and somehow map the mouse position to access array items? This is the code I have right now:
int[] r = {255,249,240,233,227};
int[] g = {115,138,157,173,187};
int[] b = {0,18,63,94,120};
void setup() {
size(500, 500);
}
void draw() {
int x = mouseX;
if(x >= 0 && x <=100) {
background(r[0], g[0], b[0]);
}
else if (x >= 101 && x <= 200){
background(r[1], g[1], b[1]);
}
else if (x >= 201 && x <= 300){
background(r[2], g[2], b[2]);
}
else if (x >= 301 && x <= 400){
background(r[3], g[3], b[3]);
}
else {
background(r[4], g[4], b[4]);
}
}
I wish to simplify the code to something more like this:
int[] r = {255,249,240,233,227};
int[] g = {115,138,157,173,187};
int[] b = {0,18,63,94,120};
void setup() {
size(500, 500);
}
void draw() {
for(int i=0; i<r.length; i++) {
background(r[i],g[i],b[i]);
}
}
However, I don't know how to change this code in a way, that the background colour would change depending on mouse horizontal position, as it is shown in the first example.
Thank you for your reply and help!
If your steps between your different values are 100, then you can just divide the input X value by 100. Integer division will take care of the rest.
The if statement is just to make sure it stays within the bounds of your array.
int mouseX = ...;
int i = mouseX / 100;
if(i < r.length && i < g.length && i < b.length)
{
background(r[i], g[i], b[i]);
}

Count the number of intersections of line segments whose endpoints are located on a circle?

The input is an array of 2n integers which defines line segments by saying how the points located on a circle are paired
and connected. (Each point has its own pair that's connected to it.)
Array [2,3,0,1] reads:
Point 0 is connected to point 2 Point 1 is connected to point 3
Point 2 is connected to point 0 Point 3 is connected to
point 1
Meaning we have line segments (0,2) and (1,3).
The points are located on a circle, in the same order that they are
located in the array. (Their exact coordinates are irrelevant.)
Here is the picture of my array example. (1 intersection occured.)
The output is the number of intersections. (Number of points where 2 line segments touch.)
What would be the best (fastest) way to calculate this?
What I've tried:
public static int count(int[] world) {
int i = 0;
int intersections = 0;
int endpoint = 0;
// run trought all points in order, find their pairs and check if the line they make is intersected
while (i < world.length - 1) {
if (world[i] == i+1) { // if 2 neighbouring points are connected, there are no intersections with the line they make
i++;
} else if (world[i] > i) { // don't need to check previously checked pairs
endpoint = world[i];
// check if any intersections with the line L(i,world[i]):
// This goes through all points that are located before the endpoint of the line defined by point i and its pair world[i]
// And checks if their pair is located after the endpoint, which means that the line they make intersects the line L(i,world[i])
for (int j = i+1; j < endpoint; j++) {
if (world[j] > endpoint) {
intersections++;
}
}
}
i++;
}
return intersections;
}
Thanks to sabys answer, I also coded this:
public static int countIntersections(int[] world) {
int intersections = 0;
for (int i = 1; i < world.length; i++) {
for (int j = 0; j < i; j++) {
if (!C(i,world[i],i-j,world[i-j])) {
intersections++;
}
}
}
return intersections;
}
public static boolean C(int a, int b, int x, int y) {
return ((a <= x && b <= x) || (a >= x && b <= y) || (a >= x && b >= x));
}
Which gives the same results as my initial code meaning they both work! But my initial code is faster than this one.
I'll be accepting his answer since both codes work and optimization questions are better suited for Codereview.
Observation: Given two segments L1: [a, b] and L2: [x, y], they DONT intersect if and only if (a < x && b > y) || (x < a && y > b).
Call this Condition C(L1, l2).
Outline of Algorithm:
Iterate over the line segments one by one
Take first line segment L1
Take segment line segment L2 and calculate Condition C(L1, L2). If it is false add 1 to your intersection count.
Take segment L3 and calculate C(L3, L1) and C(L3, L2). Add the 1s accordingly.
For segment Ln, you have to calculate C(Ln, Ln-1), C(Ln, Ln-2)...
Time Complexity: O(n^2). n being the number of segments

Sudoku backtracking algorithm (Java)

I've created a Sudoku solver that will solve a Sudoku as a human might- by checking possibilities + definite values in squares corresponding to the square being checked.
(Source: http://pastebin.com/KVrXUDBF)
However, I would like to create a random Sudoku generator (from a blank grid), and so have decided to use a backtracking algorithm. I understand the concept of backtracking, but am confused about one thing:
How do I know which previous node to return to (and change) once I know a certain solution is not allowed?
Should I simply return to the previous node and cycle through all possibilities? (And then if this yields no correct answers, return to the value before, etc.). This seems like a viable method, but also quite inefficient. Is this the correct way of implementing a backtracking method or is there a better way to go about it?
Thanks in advance.
More can be found about backtracking here: http://en.wikipedia.org/wiki/Backtracking
Sudoku Puzzle can be reduced to graph coloring problem which can be solved using simple backtracking like assigning colors to node (1-9) till the there is no violation that all directly connected nodes have no same color.
Constructing Graph from Sudoku : -
There is an direct edge between two grid points if they are in same
row or column or square.
Backtracking :-
Assign one color (1-9) to node
Check if there is no other directly connected node with same color
If valid color move to next node.
else change the color and recheck.
If all color exhausted backtrack to previous node.
Do recursion till all nodes are color.
Once You are done with it you can start removing numbers from the grid at random till you think the problem is unsolvable if any more numbers are removed.
A simple way to generate random Sudoku is that
1) generate a random completing Sudoku, that is, generate random Sudoku no square is blank.
2) Remove numbers from squares of 1).
3) Solve Sudoku of 2). If there are many solutions, then add a number removed at 2).
If there are still many solutions, then repeat 3).
1) sample source code:
public int[][] generateRandomCompleteSudoku() {
int[][] sudoku = new int[10];
for(int i = 1; i <= 9; i++) {
sudoku[i] = new int[10];
Arrays.fill(sudoku[i], 0);
}
generateRandomCompleteSudoku(sudoku, 1, 1);
return sudoku;
}
private boolean generateRandomCompleteSudoku(int[][] sudoku, int x, int y) {
if(x > 9) {
x = 1;
y++;
}
//sudoku of the argument is completing sudoku.
//so return true
if(y > 9) {
return true;
}
// enumerate the possible numbers of the pos(x,y).
List<Integer> possibleNumbers = new ArrayList<Integer>();
for(int i = 1; i <= 9; i++) {
boolean possible = true;
//check i is a possible number.
//check there isn't i in the raw of y .
for(int j = 1; j <= x - 1; j++) {
if(sudoku[j][y] == i) {
possible = false;
break;
}
}
//check there isn't i in the column of x(omitted).
//check there isn't i in the group of x,y(omitted).
if(possible) {
possibleNumbers.add(i);
}
}
//sudoku is wrong so return false.(There is no solution of sudoku)
if(possibleNumbers.size() <= 0) {
return false;
}
Collections.shuffle(possibleNumbers);// This gives sudoku randomness.
for(Integer possibleNumber : possibleNumbers) {
sudoku[x][y] = possibleNumber;
// a sudoku is generated, so return true
if(generateRandomCompleteSudoku(sudoku, x + 1, y)) {
return true;
}
}
// No sudoku is generated, so return false
return false;
}
For a backtracking solution, the first step is to define the state. So for this problem, I think the most straightforward way is (x,y, blank , num) with x , y is the position of the current state, blank is the number of blank position left, and num is the value you want to fill in that position (from 0 to 9 and 0 means blank).
And the return type should be boolean, which determine whether the move is valid or not (which means is there any valid solution for this move).
So, the state transition is column by column, row by row: x, y to x , (y + 1) or x , y to (x + 1), 0.
Similarly, the blank will be from a -> a - 1-> ... 0.
We have a draft solution here:
public boolean move(int x, int y, int blank, int num, int[][]sudoku){
sudoku[x][y] = num;
//checking condition and return if x,y is the last position, code omitted
if(y == sudoku[x].length){
x++;
y = 0;
}else{
y++;
}
for(int i = 1; i < 10; i++){
if(move(x,y,blank,i,sudoku){//Backtrack here
return true;
}
}
if(blank > 0){
if(move(x,y,blank - 1, 0, sudoku){//Backtrack here
return true;
}
}
return false;
}
So when ever there is a false return from the current state, it will backtrack to the last state , and the last state will continue to check for the next num until it find a correct solution (or return false).

Java Click on a object and output a message

Im currently making a game in my spare time to improve my java but im having trouble with one of the things i want to do. Ive made the game so i can put a item into a certain position. In this example its a tower in a certain location. When this tower is placed in this location and i click on the tower i want it to output a message. However ive tried many ways to do this and i havent been able to find a solution. The code i have for this is:
public static void click(int X, int Y){
System.out.println("X. " + X + " Y. " + Y);
if(Screen.room.block[X][Y].airID == Value.tower){
System.out.println("Tower clicked");
}
}
When the tower is placed in a location the code i use for this is:
if(holdsItem){
for(int y=0; y<Screen.room.block.length; y++){
for(int x=0; x<Screen.room.block[0].length; x++){
if(Screen.room.block[y][x].contains(Screen.mse)){
if(Screen.room.block[y][x].groundID != Value.ground && Screen.room.block[y][x].airID == Value.tower){
Screen.room.block[y][x].airID = heldID;
}
}
}
}
}
When i put down a tower by:
System.out.println(Screen.room.block[y][x]);
i get
Block[x=243,y=260,width=52,height=52]
This works fine and the tower is placed. I then wanted to use the location of what the tower is placed and then if that location is pressed the message would print in the console. However this doesnt happen. Can anyone help me fix this problem.
I use a mouse listener which is:
public void mouseClicked(MouseEvent e) {
e.getX();
e.getY();
Block.click(e.getX(), e.getY());
}
When i click on a location i get:
System.out.println("X. " + X + " Y. " + Y);
X. 257 Y. 298
if this helps.
Right now you are using pixels to get the location of your object, so you need to check more than the exact "origin" pixel for each block.
public static void click(int X, int Y){
System.out.println("X. " + X + " Y. " + Y);
//Look for every block in the matrix
for ( int i = 0; i<Screen.room.block.length; i++ ) {
for ( int j = 0; j<Screen.room.block[0].length; j++ ) {
if(Screen.room.block[i][j].airID == Value.tower){
//Check if we hit within the block's bounds
if ( X >= i && X <= i+blockWidth &&
Y >= j && Y <= j+blockHeight )
System.out.println("Tower clicked");
return;
}
}
}
}
A common practice is to store your objects in some kind of list or uni-dimensional array, so that you can avoid the
for ( int i = 0; i<Screen.room.block.length; i++ ) {
for ( int j = 0; j<Screen.room.block[0].length; j++ ) {
and just do
for ( int i = 0; i<Screen.room.blocks.length; i++ ) {
to check for every block and to avoid having such a big matrix when you must check every block anyway.
Another approach: you could give each block a place in a checkers-like matrix and then transform the mouse clicked event coordinates from pixels to "block" coordinates:
public void mouseClicked(MouseEvent e) {
int x = e.getX() / widthOfABlockInPixels;
int y = e.getY() / heightOfABlockInPixels;
Block.click(x, y);
}
Say your objects are 100x100 pixels, then this would give you the right block coordinates for
(160, 150) => (1, 1)
(60, 50) => (0, 0)
and so on.
This might sound a little over-simplified, but, then again, I'm just spit-balling here. Have you thought about implementing the message into a JOptionPane.showMessageDialog? Not sure if that would be what you're looking for.

Creating an ArrayList of objects with a loop, checking for overlapping objects

I'm making a game for a class and one element of the game is displaying a number of cabbages, which are stored in an ArrayList. This ArrayList must be a fixed number of 20, 10 of Good Cabbage and 10 of Bad Cabbage.
As the cabbages are created, I want to make sure they don't overlap when they are displayed. Where I'm running into trouble with this is that when I find a cabbage that overlaps, I'm not sure how to go back and create a new cabbage in its place. So far when the code finds an overlap, it just stops the loop. I guess I'm having trouble properly breaking out of a loop and restarting at the index that goes unfilled.
Here's what I have so far for this. Any suggestions would be much appreciated.
// Initialize the elements of the ArrayList = cabbages
// (they should not overlap and be in the garden) ....
int minX = 170 ;
int maxX = 480;
int minY = 15;
int maxY = 480;
boolean r = false;
Cabbage cabbage;
for (int i = 0; i < N_GOOD_CABBAGES + N_BAD_CABBAGES; i++){
if (i % 2 == 0){
cabbage = new GoodCabbage((int)(Math.random()* (maxX-minX + 1))+ minX,
(int)(Math.random()*(maxY-minY + 1))+ minY,window);
}
else {
cabbage = new BadCabbage((int)(Math.random()* (maxX-minX + 1))+ minX,
(int)(Math.random()*(maxY-minY + 1))+ minY,window);
}
if (i >= cabbages.size()){
// compares the distance between two cabbages
for (int j = 0; j < cabbages.size(); j++){
Point c1 = cabbage.getLocation();
Cabbage y = (Cabbage) cabbages.get(j);
Point c2 = y.getLocation();
int distance = (int) Math.sqrt((Math.pow((c1.x - c2.x), 2) + Math.pow((c1.y - c2.y),2)));
if (distance <= (CABBAGE_RADIUS*2) && !(i == j)){
r = true;
}
}
if (r){
break;
}
cabbage.draw();
cabbages.add(i, cabbage);
}
}
The easiest way to do this is probably to add another loop.
A do...while loop is suited to cases where you always need at least one iteration. Something like:
boolean overlapped;
do {
// create your new cabbage here
overlapped = /* check whether it overlaps another cabbage here */;
} while (overlapped);
cabbage.draw();
cabbages.add(i, cabbage);
It looks like you are making cabbage objects and then throwing them away, which is a (trivial) waste.
Why not pick the random X and Y, check if there is room at that spot, then make the cabbage when you have a good spot? You'll just churn through numbers, rather than making and discarding entire Objects. Plus you won't have to repeat the random location code for good and bad cabbages.
int x, y
do {
// pick x and y
} while (cabbageOverlaps(x,y,list)
// create a cabbage at that x,y, and add it to list
boolean cabbageOverlaps(int x, int y, ArrayList existingCabbages)

Categories

Resources