简体   繁体   中英

Co-ordinate proximity in a 2-dimensional array

I have a 2-dimensional array of type Animal (user defined type). I have the array set up so that it is randomly populated with either a Prey or Pred of type Animal or nothing (it is left null ).

My question is about proximity , I want to know whether a Prey is in a space next to a Pred (including diagonals). Say I had this:

{null, null, null,    
 null, Prey, null,
 Pred, null, null}

Assuming I use:

Animal[][] grid = new Animal[3][3];

If I simply say:

for (int i = 0; i < 3; i++){
    for(int j = 0; j <  3; j++){
        if (grid[i+1][j] == Pred || grid[i+1][j+1] == Pred || grid[i+1][j+1] == Pred
        || grid[i][j+1] == Pred || grid[i-1][j+1] == Pred || grid[i+1][j] == Pred
        || grid[i-1][j] == Pred || grid[i-1][j-1]) == Pred) // Then proximity = true.
    }
}

Would this be horribly inefficient? Would the entire array have to be searched through 8 times to check if the if statement returns true?

I need to scale up the array to perhaps a few thousand "spaces" and I would like a method that won't take too much time.

If this way is inefficient, can anybody suggest a better (maybe cleaner) approach?

It seems you'll have to do a n^2 algorithm if you want to check every possible index in the 2D array.

You want to make sure these 4 conditions are true in this priority for every if statement:

  1. i+1 < grid.length
  2. i-1 >= 0
  3. j+1 < grid[i].length
  4. j-1 >= 0

Follow this pseudo code to avoid errors:

boolean proximity = false;
for (int i = 0; i < grid.length; i++){
    for(int j = 0; j <  grid[i].length; j++){
        if(grid[i][j] == Pred){  //only care if its a Pred
            //now check for Prey
            //make sure youre not out of bounds!
            if(i+1 < grid.length && grid[i+1][j] == Prey) proximity = true;
            else if(i+1 < grid.length && j+1 < grid[i].length && grid[i+1][j+1] == Prey) proximity = true;
            //do for rest etc.
        }
        if(proximity) break;//once found, youre done.
    }
}

Yo can use this aproach if many positions are null. You can walk through the matrix from left to right and top-down. Only check the 8 comparations when you found a Pred. Also, as you have looked at current cell when you were checking the previous cell (west) and the cells on the row above (north-west, north and north-east), yo do not need to check the 8 positions, only this four: the East, South-East, South and South-West cells of the current cell if this contains a Pred

for (int i = 0; i < 3; i++){
    for(int j = 0; i <  3; j++){
       if(grid[i][j] == Pred)
       {
          if (grid[i][j+1] == Prey || grid[i+1][j-1] == Prey || grid[i+1][j] == Prey
            || grid[i+1][j+1] == Prey ) // Then proximity = true.
       }
       if(grid[i][j] == Prey)
       {
          if (grid[i][j+1] == Pred || grid[i+1][j-1] == Pred || grid[i+1][j] == Pred
            || grid[i+1][j+1] == Pred ) // Then proximity = true.
       }
    }
}

Note the proximity es bilateral, if grid[i][j] has proximity with grid[i+1][j+1], for example, then grid[i+1][j+1] has proximity with grid[i][j].

Also, you must have in mind the matrix's bounds. Don't check de row below if you are in the last, don't check the column on the left if you are on the first column, and don't check the column on the right if you are on the last column. (With this aproach, you are never going to check on the row above so don't worry about the top bound)

Edited and corrected. You also have to note the bilareal proximity.

you could make a function like the following:

public boolean containsPreditor(int x, int y, Animal[] grid)
{
    boolean outOfBounds = false;
    if(x < 0 || x >= grid[0].length)
    {
         outOfBounds = true;
    }
    if(y < 0 || y >= grid.length)
    {
         outOfBounds = true;
    }

     if(!outOfBounds)
     {
      return grid[y][x] == Pred;
     }
     else
     {
      //space does not exist
      return false;
     }

}

then you could run the method for the 3x3 grid, or however big you want it by modifying the loop size

    boolean proximity = false;
    int xIndex; //assign this
    int yIndex; //assign this too
 for(int i = (yIndex - 1); i <= (yIndex + 1); i++)
 {
      for(int j = (xIndex - 1); j <= (xIndex + 1); j++)
       {
          proximity = proximity || containsPreditor(j, i, Animals);
       }
 }

Essentially the same thing, but easier to understand and debug

I had a think overnight on this for you, and realized that one can go a lot faster by representing the board as a bit set, and then using bit logic to combine. This approach is exceptionally CPU and CPU cache friendly, but it does need a bit of upfront computation and ideally a change in how you store the board. If you cannot do that, then there will be some overhead to overcome. However it will be worth the effort!

The basic algorithm is:

preyAtRisk = bitCount( squaresAtRisk.bitAnd(squaresWithPrey) )

This algorithm can be implemented with very few conditional jumps, modern CPUs can perform 64 bit ands in a single cpu cycle and most JVMs provide an intrinsic for Integer.bitCount and Long.bitCount which replaces them with an assembly instruction. Thus a lot of the looping can be done in parallel, in hardware. That is, FAST!

This algorithm requires representing the board as a bit set. So for a 3x3 board, the first square would be the first bit and so on up to the ninth square being the ninth bit.

Thus your example of

{null, null, null,    
 null, Prey, null,
 Pred, null, null}

would be represented by the following two bit sets

prey  = 000 010 000
preds = 000 000 100

We then need to convert the preds bit set, into a bitset that represents which squares are at risk. This can be done by precomputing a bitset of which squares would be at risk for each individual square. Which would look something like this:

dangerZones[0] = 010 110 000
dangerZones[1] = 101 111 000
dangerZones[2] = 010 011 000
...

Then as the preds are added to the collection, or in its own iteration squaresAtRisk can be built up:

public void setPred( x, y ) {
  bitIndex       = toBitIndex(x,y)
  squaresAtRisk &= dangerZones[bitIndex]
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM