I am having some stackoverflow issues and hopefully someone can give me some insight into a non/less-recursive solution.
Ident[][] map = ...
private int explore(Ident item, int xcoord, int ycoord) {
if ((map[xcoord][ycoord] == null) || !map[xcoord][ycoord].equals(item))
return 0;
map[xcoord][ycoord] = null;
int sumX, sumY, counter = 1;
item.translate(xcoord, ycoord);
for (int y = -1; y <= 1; y++)
for (int x = -1; x <= 1; x++) {
sumX = x + xcoord;
sumY = y + ycoord;
if (((y != 0) || (x != 0)) && (sumX >= 0) && (sumX < map.length) &&
(sumY >= 0) && (sumY < map.[0].length))
counter += explore(item, sumX, sumY);
}
}
}
return counter;
}
This method is given a 2-dimensional array of Ident Objects, a target Ident and a starting position within the array. It recursively traverses the array
counting how large of a continuous area the Ident occupies. It also centers the inputted Ident item in the middle of the area.
By looping through the map array and calling the explore method on any non null elements I can construct an array of Ident items centered in their areas, and with sizes relative to their areas.
One can see that with anything but small maps, the stack will overflow.
Anyone have an alternate method of accomplishing the same task? Or some insight to help me find one?
To eliminate recursion, make a list of coordinates to explore and loop while it contains any items; in your loop, build a new list of coordinates to explore, and at the end of the loop, replace the old list with the new list.
This take me back to the mid-80's. Any flood fill algorithm is going to require a certain amount of state. I unfortunately don't remember the algorithms. What's efficient for a large expanse probably isn't going to efficient for a maze.
To avoid recursion, instead of recursing, just add the data that you would have called to a stack. Loop around popping the next unexplored coordinate from the top of the stack. Using a stack rather than a FIFO queue improves locality a bit, although it probably isn't going to make a huge difference here.
private int explore(Ident item, int xcoord, int ycoord) {
int counter = 0;
Queue<Point> stack = Collections.asLifoQueue(new ArrayDeque<Point>());
stack.add(new Point(xcoord, ycoord));
while (!stack.isEmpty()) {
Point point = stack.remove();
xcoord = point.x;
ycoord = point.y;
if (!item.equals(map[xcoord][ycoord])) {
continue;
}
++counter;
map[xcoord][ycoord] = null;
item.translate(xcoord, ycoord);
for (int y = -1; y <= 1; y++)
for (int x = -1; x <= 1; x++) {
int sumX = x + xcoord;
int sumY = y + ycoord;
if (
!(x == 0 && y == 0) &&
0 <= sumX && sumX < map.length &&
0 <= sumY && sumY < map[0].length
) {
stack.add(new Point(sumX, sumY));
}
}
}
}
return counter;
}
In the best traditions of stackoverflow this has not seen a compiler. (It's also retains much of the original algorithm.)
Related
This question already has answers here:
How do I do a deep copy of a 2d array in Java?
(7 answers)
Closed 8 years ago.
So I am trying to make an algorithm for finding full paths in NxN grid. For example in 1x1 grid there is 1 possible path, in 2x2 grid there is 1, in 3x3 there is 2 and in 4x4 there is 8. The idea is to find scenarios where we can fill every spot of the grid by moving.
I have made a recursive function for the job and here is the code:
public static int getRoutesHelp(int[][] table, int x, int y)
{
if(x > table.length-1 || x < 0 || y < 0 || y > table.length-1)
return 0;
if(table[x][y] == 1)
return 0;
table[x][y] = 1;
if(isDeadEnd(table, x, y))
{
if(isTableFull(table))
return 1;
}
else
{
int a = getRoutesHelp(table, x-1, y);
int d = getRoutesHelp(table, x, y+1);
int b = getRoutesHelp(table, x+1, y);
int c = getRoutesHelp(table, x, y-1);
return a+b+c+d;
}
return 0;
}
public static int getRoutes(int size)
{
int[][] table = new int[size][size];
// init table
for(int i = 0; i < size; i++)
{
for(int a = 0; a < size; a++)
{
table[i][a] = 0;
}
}
return getRoutesHelp(table, 0 ,0);
}
So basically I start from 0.0 and start moving to all possible directions and by repeating this I get the amount of successful routes. The problem is that after the assignment of int d the original table is somehow filled with 1 but it should be empty as far as I understand because java passes a copy of the table right? I've been fighting with this for like 4 hours and can't really find the problem so any help is appreciated. Empty slots in table are marked with 0 and filled slots with 1.
EDIT: I managed to fix the issue I had with the copying and now my other problem is that with 5x5 grid my algorithm returns 52 routes and it should be 86. So it works with 4x4 grid okay, but once I move further it breaks.
Added the isDeadEnd function here
public static boolean isDeadEnd(int[][] table, int x, int y)
{
int toCheck[] = new int[4];
toCheck[0] = x-1; // left
toCheck[1] = y-1; // top
toCheck[2] = x+1; // right
toCheck[3] = y+1; // bottom
int valuesOfDirections[] = new int[4]; // left, top, right, bottom
for(int i = 0; i < 4; i++)
{
int tarkastettava = toCheck[i];
if(tarkastettava > table.length-1 || tarkastettava < 0)
{
valuesOfDirections[i] = 1;
}
else
{
if(i == 0 || i == 2)
{
valuesOfDirections[i] = table[tarkastettava][y];
}
else
{
valuesOfDirections[i] = table[x][tarkastettava];
}
}
}
for(int i = 0; i < 4; i++)
{
if(valuesOfDirections[i] == 0)
{
return false;
}
}
return true;
}
Come to think of it, you probably can do a simple backtrack here:
table[x][y] = 1;
if(isDeadEnd(table, x, y)) {
if(isTableFull(table))
return 1;
}
table[x][y] = 0;
}
And later:
int res = a + b + c + d;
if (res == 0) {
// backtrack here too
table[x][y] = 0;
}
return res;
I have been looking over this flood fill implementation for some time now and keep running into the dreaded stack overflow. I am dropping pieces randomly on a 12x10 grid and calling the checkMatches method after each random piece drop to check for groups of three or more, hence the flood fill use.
EDIT: See comment
public void checkMatches(int x, int y, int type)
{
if (x < 0 || x >= PIECES_WIDE || y < 0 || y >= PIECES_TALL || type == 0)
return;
if (grid[x][y].getType() != type)
return;
int checkL = x;
while (checkL >= 0 && grid[checkL][y].getType() == type)
{
grid[checkL][y].setDestroy(true);
numMatches++;
checkL--;
}
checkL++;
int checkR = x;
while (checkR < PIECES_WIDE - 1 && grid[checkR][y].getType() == type)
{
grid[checkR][y].setDestroy(true);
numMatches++;
checkR++;
}
checkR--;
for (int i = checkL; i <= checkR; i++)
{
if (y > 0 && grid[i][y - 1].getType() == type)
checkMatches(i, y - 1, type);
if (y < PIECES_TALL - 1 && grid[i][y + 1].getType() == type)
checkMatches(i, y + 1, type);
}
}
Then the relevant code to call the method and destroy the pieces if there have been three matched pieces:
checkMatches(x, y, type);
if (numMatches >= 3)
{
for (int i = 0; i < PIECES_WIDE; i++)
{
for (int j = 0; j < PIECES_TALL; j++)
{
if (grid[i][j].isDestroy())
destroyPiece(grid[i][j]);
}
}
} else
{
numMatches = 0;
for (int i = 0; i < PIECES_WIDE; i++)
{
for (int j = 0; j < PIECES_TALL; j++)
{
grid[i][j].setDestroy(false);
}
}
}
My eyes and brain hurt. I know that the recursion is causing the overflow, but I also know that this implementation is possible in some form. Therefore I'm doing something wrong. Thanks in advance.
You need to put a mark on the pieces that you have already found matching. Then you can make a loop to extend your matchings, until you notice that no more pieces have been marked. Then you can stop.
Im stuck on this part of a school project where I have to get the shortest route between two co-ordinates (Traveling Salesman Problem). I made a litle something here to get the co-ords of the nearest neighbour, but a few co-ords have the same closest neighbour, and I dont want that.
I thought of something to clear that issue, but it isn't working, and I can't figure out why.
distance is the current distance between the current position and every other. shortestDistance kind of speaks for itself I think.
locations[20][3] is a 2D array in which I store the Xco-ord, the Yco-ord and the nearest neighbour for each co-ord. X is in [x][0], Y in [x][1] and neighbour in [x][2]
for(int i = 0; i < 20; i++){
int shortestDistance = 100;
int distance;
//Looking for nearest neighbour 20 times
for(int j = 0; j < 20; j++){
//Looking for the closest neighbour here
distanceX = locations[i][0] - locations[j][0];
distanceY = locations[i][1] - locations[j][1];
//To prevent a negative distance:
if(distanceX < 0){
distanceX = distanceX * -1;
}
if(distanceY < 0){
distanceY = distanceY * -1;
}
//Add distance
distance = distanceX + distanceY;
//If current distance is shorter then the shortestdistance, to prevent it does'nt see itself as 'neighbour' and to prevent another co-ord has the same neighbour, which happens in isOk();
if(distance < shortestDistance && distanceX + distanceY != 0 && isOk(j)){
shortestDistance = distance;
locations[i][2] = j;
}
}
}
Function isOk is:
private boolean isOk(int j){
boolean result = false;
for(int i = 0; i < 20; i++){
if(locations[i][2] == j){
result = false;
}
else{
result = true;
}
}
return result;
}
So, I what I'm asking is what I am doing wrong? I still get some items(in 20 * 10 storage) that have the same item as its nearest neighbour.
You probably have to initialize the neighbors to something that will be ok for your isOK method. A such value is, for instance, -1.
for(int i = 0; i < 20; i++) locations[i][2] = -1;
The isOk contains also a small mistake. The loop should be stopped when j has been found as neighbor of another location:
private boolean isOk(int j){
for(int i = 0; i < 20; i++){
if (locations[i][2] == j) return false;
}
return true;
}
I'm not a great programmer so I was wondering if someone could help me. In my battleships game I have ships made from the Rect class, but I need to check if they are overlapping. This is what I have so far.
EDIT: What exactly is wrong: I have two ships one of size 2 and 5. So say ship 1 has (0,0)(0,1) coordinates and ship 2 has (0,1) to (5,1).It works great for checking both coordinates of ship one on point(0,1), but that is it. I hope this make sense. so if I check (0,0) and (0,1) on (1,1) it shows no eror
public boolean contains(Ship ship) {
int currentX = ship.getX();
int currentY = ship.getY();
int testX = xCoord;
int testY = yCoord;
if (rotated) { //if ship is horizontal enter
for (int j = 0; j < sizeOfShip; j++) {
for (int k = 0; k < ship.getSize(); k++) {
if (testX == currentX && testY == currentY) {
return false;
}
testX++;
}
if (ship.rotated)
currentX++;
else {
currentY++;
}
}
}
//
if (!rotated) {
for (int j = 0; j < sizeOfShip; j++) {
for (int k = 0; k < ship.getSize(); k++) {
if (testX == currentX && testY == currentY) {
return false;
}
testY++;
}
if (ship.rotated)
currentX++;
else {
currentY++;
} }
}
return true;
}
I think the problem lies here (the same goes for the other if):
...
testX++;
}
if (ship.rotated)
currentX++;
else {
currentY++;
}
...
I assume testX is this ships x value. You are incrementing testX in every iteration in the inner loop and the input parameters value (currentX) in the outer loop. At the same time you are never resetting the value. Lets say this ship have a length of 5 and the input parameter a length of 2 and both are horizontal. After 3 iterations of the outer loop testX have been incremented by 6.
I think you want to swap the increments around and reset the currentX/Y value after each inner iteration:
for (int j = 0; j < sizeOfShip; j++) {
for (int k = 0; k < ship.getSize(); k++) {
if (testX == currentX && testY == currentY) {
return false;
}
if (ship.rotated)
currentX++;
else {
currentY++;
}
}
currentX = ship.getX();
currentY = ship.getY();
testX++;
}
This have to be done for both ifs. I cannot try this, so try it out and tell me if I have made a mistake. :)
On a different note. You can replace
}
//
if (!rotated) {
...
with
}
else {
...
The problem is that e.g. for a ship (0,1)(5,1) you need to check all the values (0,1)(1,1)(2,1)(3,1)(4,1)(5,1) against the all the other ship's similar values e.g. (0,0)(0,1) (no more since it's the small ship).
You need to modify your for-loops to do this for you. I suggest printing out those currentX/currentY values to make sure that they are doing this. In particular I don't think you want to be incrementing currentX/Y every iteration but rather currentX in one for-loop and currentY in the other.
Cheers.
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Looping in a spiral
I'm creating a program to populate a 3 by 3 matrix. I want to result in something looking like this
5 4 3
6 1 2
7 8 9
As you have probably noticed it is a spiral.
Now the algorithm I'm using is this: I have a 2-d array where the values represent the coordinates of the number. First I assign that every number coordinate in this array will have a value of 10. Then starting at 9 I decrease my x coordinate and assign the value of the coordinate to currentnum - 1 until it reaches the end or its value is not 10; Then I do the same thing except I increase the value of Y; Then decrease the value of x; Then of Y;
The reason I assign 10 to every number is so like it acts as a road for my program. Since current num will never exceed 9. If the value of a square is 10 it is like a green light. If it is not 10 meaning a value has been assigned to that square it breaks out of it.
Here is my code, please note it is written in Java
public class spiral {
/**
* #param args
*/
public static void main(String[] args) {
int spiral [] [] = new int[3][3];
for(int i = 0; i <= 2; i++){
for(int j = 0; j <= 2; j++){
spiral[i][j] = 10;
}
}
//0 is x value, 1 is y value
spiral[0][0] = 9;
int x = 1;
int y = 1;
int counter = 1;
int currentnum = 9;
int gridsquare = 3;
for(int i = 0; i <= 8; i++){
if(counter == 5){
counter = 1;
}
if(counter == 1){
System.out.println(x + " " + y);
for(int j = 0;j <= 1;j++){
if(spiral[x][y] == 10){
spiral[x][y] = currentnum;
currentnum--;
x += 1;
}
else{
y += 1;
break;
}
}
}
if(counter == 2){
for(int k = 0; k <= 0; k++){
System.out.print(x + " " + y);
if(spiral[x][y] == 10){
spiral[x][y] = currentnum;
currentnum--;
y += 1;
}
else{
x -= 1;
break;
}
}
}
if(counter == 3){
for(int z = 0; z <= 0; z++){
if(spiral[x][y] == 10){
spiral[x][y] = currentnum;
currentnum--;
x -= 1;
}
else{
y -= 1;
break;
}
}
}
if(counter == 4){
for(int b = 0; b <= 0; b++){
if(spiral[x][y] == 10){
spiral[x][y] = currentnum;
currentnum--;
y -= 1;
}
else{
x += 1;
break;
}
}
}
counter++;
}
System.out.print(currentnum);
}
}
I'm getting this error
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 3
at spiral.main(spiral.java:44)
Since I'm new to Java would someone please suggest a posible fix for this. Also if you see any problems with my algorithm please do inform me.
You do not need to pre-fill with 10: zero works just as well.
I think the best approach to solving the spiral is to think of how you do it manually: start in a corner, and go horizontally until you hit non-zero or an edge of the array. Then you turn right. Stop when the current number goes past N*N.
Now let's look at what each part of the algorithm means:
Starting in the corner means setting x=0 and y=0.
Going in a straight line means x=x+dx, y=y+dy, where either dx or dy is zero, and dy or dx is 1 or -1.
Turning right means assigning dx to dy and -dy to dx.
Here is how it looks in the code:
int current = 1;
// Start in the corner
int x = 0, y = 0, dx = 1, dy = 0;
while (current <= N*N) {
// Go in a straight line
spiral[x][y] = current++;
int nx = x + dx, ny = y + dy;
// When you hit the edge...
if (nx < 0 || nx == N || ny < 0 || ny == N || spiral[nx][ny] != 0) {
// ...turn right
int t = dy;
dy = dx;
dx = -t;
}
x += dx;
y += dy;
}
You've incremented x or y to 3 which is past the end of one of your arrays.
Step through your program with the debugger or add System.out.println statements before each if (counter) to find out where you're doing this.