DFS Path has stackoverflow Error on larger entries - java

This algorithm successfully gives me a path through a maze. The maze is a 2D binary matrix, and the target location is '9'.
The algorithm works by going through the '0' path that reaches '9' (base case) and recursively adds the previous locations to my path array.
I observed that removing the border detecting line at the top gives an index out of bounds error. but I am pretty sure this algo is breaking when the path reaches a wall.
It also works smoothly on matrices 200x200 or less and about 50% of the time at 250x250.
(As seen in the 100 width one below.)
public static boolean searchPath(int[][]maze, int x, int y, ArrayList<Integer> path){
if(x<0 || x>=maze[1].length || y<0 || y>=maze.length) return false;
if(maze[y][x] == 9){
path.add(x);
path.add(y);
return true;
}
if(maze[y][x] == 0){
maze[y][x] = 2;
int dx = -1;
int dy = 0;
if(searchPath(maze, x+dx, y+dy, path)){
path.add(x);
path.add(y);
return true;
}
dx = 1;
dy = 0;
if(searchPath(maze, x+dx, y+dy, path)){
path.add(x);
path.add(y);
return true;
}
dx = 0;
dy = -1;
if(searchPath(maze, x+dx, y+dy, path)){
path.add(x);
path.add(y);
return true;
}
dx = 0;
dy = 1;
if(searchPath(maze, x+dx, y+dy, path)){
path.add(x);
path.add(y);
return true;
}
}
return false;
}

method callings are in stack memory and after some calls it overflows. you can add -Xss12m as JVM argument (It gives 12 MB memory to your application stack memory. if it wasn't enough increase it.) and you can add this argument to the Run config in IntelliJ Idea as a JVM argument or as argument of java command in command line.

Stack space is limited, so you should only write a recursive algorithm when you know that it will use a reasonable amount of it.
Using recursive DFS to find your way out of an NxM maze can use O(N*M) stack space -- not reasonable.
You could write DFS using a separate stack data structure, but really you should use BFS with a queue. It's a little simpler, and you will get the shortest path.

Related

How do I calculate this code's time complexity? [duplicate]

This question already has answers here:
Big O, how do you calculate/approximate it?
(24 answers)
Closed 3 years ago.
I'm struggling with calculating time complexity in this code.
Only capable of simple code at the moment...
just want to try with complex one!
public static int PATHWAY = 0;
public static int WALL = 1;
public static int MARKED = 2;
public static boolean find(int x, int y) {
if(x == 7 && y == 7) return true;
maze[x][y] = MARKED;
if(x != 0 && maze[x-1][y] == PATHWAY && find(x-1, y)) return true;
if(y != 0 && maze[x][y-1] == PATHWAY && find(x, y-1)) return true;
if(x != 7 && maze[x+1][y] == PATHWAY && find(x+1, y)) return true;
if(y != 7 && maze[x][y+1] == PATHWAY && find(x, y+1)) return true;
return false;
}
Well, in each recursive call you visit a single cell in your 2D array.
Since you mark the visited cells, you can't visit the same cell twice.
Hence the total recursive calls is bound by the length of the 2D array.
Apart from the recursive call, you perform a constant amount of work in each execution of the find() method.
Therefore the time complexity is O(N*M) if N is the number of rows and M the number of columns of the 2D array.
Of course, based on your stopping condition of if(x == 7 && y == 7) return true;, it looks like the dimensions of your 2D array are 8x8, which can be seen as a constant. That would make the running time O(1).
O(N*M) is the complexity for a general input array.
Basically you can calculate assignments and operations.
Have a
int assignments = 0;
int operations = 0;
which you will increment every time you do one.
Other way in doing this is to monitor the time, but it's not the most reliable one.
You can also calculate/approximate Big-O, check Big O, how do you calculate/approximate it?
Well it's not that hard, it actually uses DFS in order to find a path. the order of DFS is O(V+E), where V is the number of vertices and E is the number of edges.
In this case you are using a adjacency matrix to represent your graph. so in worst case the time complexity would be O(M*N), where M is the number of rows and N is the number of columns.

Possible uneven distribution in Java's Random class or bad implementation?

I'm tinkering around with a cellular automaton and my movement detection function is acting really strangely. I'm 80% sure it's my implementation but I have no idea where the issue is. Could someone take a look and enlighten me since I've spent the better part of 7H trying to get it to work and it won't:
private int[] cellularSearch(short xPos, short yPos)
{
// the center position is our current position; the others are potentially free positions
byte[][] positions = new byte[][]{{0,0,0},{0,1,0},{0,0,0}};
int[] result = new int[2];
byte strike=0;
int dice0=0, dice1=0;
while(strike<9)
{
dice0 = r.nextInt(3)-1;
result[0] = xPos + dice0;
if((result[0] >= 0)
&& (result[0] < img.getWidth()))
{
dice1 = r.nextInt(3)-1;
result[1] = yPos + dice1;
if((result[1] >= 0)
&& (result[1] < img.getHeight()))
{
if((positions[dice1+1][dice0+1] != 1)) // if this isn't our own cell and wasn't tried before
{
if(img.getRGB(result[0], result[1]) == Color.white.getRGB()) // if the new cell is free
{
return result;
}
}
positions[dice1+1][dice0+1]=1; // we need to use +1 to create a correlation between the linkage in the matrix and the actual positions around our cell
strike++;
}
}
}
}
The code works and it correctly identifies when a pixel is white and returns the position for it. My problem is the distribution of the results. Given that I'm using Random both for the row and the column, I was expecting a near equal distribution over all possible locations, but what happens is that this code seems to prefer the cell right above the coordinates being fed in (it hits it ~3x as much as the other ones) and the one right below the coordinates (it hits it ~2x as much as the others).
When I start my program and all my pixels slowly move towards the top of the window on EVERY run (vs true randomness with my old lengthy code which was 3x as long), so there's gotta be an error in there somewhere. Could someone please lend a hand?
Thank you in advance!
EDIT: Thank you everyone for the effort! Sorry for the non-compiling code but I extracted the main purpose of the function while cutting out a ton of commented code (my other approaches to implementing this function). Locally the code has the return statement and it runs. I'll slowly go through all your answers in the next few hours (gonna have dinner soon).
EDIT2: I tried what #DodgyCodeException and #tevemadar suggested and made a list with all the 8 positions, then shuffle them each time I enter the function, and then iterate through them, trying each one in part. Still the position exactly above and below the current cell are selected most. I'm baffled. This is my old super-spaghetti code that I've written for this function and it worked perfectly with no errors, equal distribution, and (oddly enough) it's the most efficient implementation that I've tried out of everything mentioned here. After I'm done with lunch and filing some paperwork I'll thoroughly study it (it's been ~ 2 years since I wrote it) to see why it works so well. If anyone still has ideas, I'm fully open.
boolean allRan=false;
int lastDice=0, anteLastDice=0, dice = r.nextInt(3)+1;
//the initial dice usage is for selecting the row on which we'll operate:
//dice = 1 or 3 -> we operate above or under our current cell; dice = 2 -> we operate on the same row
while(!allRan)
{
if((dice==1) || (dice==3))
{
int i= r.nextInt(3);
if(((xPos-1+i) < img.getWidth())
&& ((xPos-1+i) >= 0))
{
if(((yPos-1) >= 0)
&& (img.getRGB(xPos-1+i, yPos-1) == Color.white.getRGB())
&& (dice==1))
{
result[0] = xPos-1+i;
result[1] = yPos-1;
above++;
endTime = (int) System.currentTimeMillis();
section4Runtime += (double) (endTime - startTime) / 1000;
return result;
}
else if(((yPos+1) < img.getHeight())
&& (img.getRGB(xPos-1+i, yPos+1) == Color.white.getRGB())
&& (dice==3))
{
result[0] = xPos-1+i;
result[1] = yPos+1;
below++;
endTime = (int) System.currentTimeMillis();
section4Runtime += (double) (endTime - startTime) / 1000;
return result;
}
}
// if this section is reached, it means that: the initial dice roll didn't find a free cell, or the position was out of bounds, or the dice rolled 2
// in this section we do a dice reroll (while remembering and avoiding our previous values) so that we cover all dice rolls
if(dice==1)
{
if(lastDice==0)
{
lastDice=dice;
dice += r.nextInt(2)+1; // we incrmeent randomly towards 2 or 3.
}
else
{
if(lastDice==2)
{
if(anteLastDice==0)
{
anteLastDice= lastDice;
lastDice=dice;
dice=3;
}
else
{
allRan=true;
}
}
else if(lastDice==3)
{
if(anteLastDice==0)
{
anteLastDice= lastDice;
lastDice=dice;
dice=2;
}
else
{
allRan=true;
}
}
}
}
else // dice is 3
{
if(lastDice==0)
{
lastDice=dice;
dice -= r.nextInt(2)+1; // we decrement randomly towards 2 or 1.
}
else
{
if(lastDice==2)
{
if(anteLastDice==0)
{
anteLastDice= lastDice;
lastDice=dice;
dice=1;
}
else
{
allRan=true;
}
}
else if(lastDice==1)
{
if(anteLastDice==0)
{
anteLastDice= lastDice;
lastDice=dice;
dice=2;
}
else
{
allRan=true;
}
}
}
}
}
if(dice==2)
{
int i=0;
i += r.nextInt(2)==0?-1:1;
if(((xPos+i) < img.getWidth())
&& ((xPos+i) >= 0)
&& (img.getRGB(xPos+i, yPos) == Color.white.getRGB()))
{
result[0] = xPos+i;
result[1] = yPos;
leveled++;
endTime = (int) System.currentTimeMillis();
section4Runtime += (double) (endTime - startTime) / 1000;
return result;
}
// same as above: a dice reroll (with constrictions)
if(lastDice==0)
{
lastDice=dice;
dice+= r.nextInt(2)==0?-1:1; // randomly chose if you decrement by 1 or increment by 1
}
else
{
if(lastDice==1)
{
if(anteLastDice==0)
{
anteLastDice= lastDice;
lastDice=dice;
dice =3;
}
else
{
allRan=true;
}
}
else if(lastDice==3)
{
if(anteLastDice==0)
{
anteLastDice= lastDice;
lastDice=dice;
dice =1;
}
else
{
allRan=true;
}
}
}
}
}
return result;
After much thought, I eventually figured it out. All the ideas that we all had were violating a fundamental "rule" of the first implementation that I was using: the first implementation was trying a random position on one of the 3 lines, then moving on to the next lines (without coming back to try the other positions on that line). Example: if the algo selected the line above, it would randomly try the top-left corner to see if it's free; if it wasn't then it would try the same line as the current cell and the line below (again, just with 1 of their possible positions) without coming back. All our ideas were iterating through all possibilities around the cell, which meant that it was inevitable to have the top and bottom line have more hits than the middle (since top and bottom have 3 possible points each while middle has only 2). Also, when there were holes in the field, the cells most likely to fill it up were the ones that were moving diagonally (which in the end is up or down) or those directly moving up or down, since those moving sideways only had the options left/ right. The only mystery that will remain unsolved is why (using our proposed implementations) the model would generally use the point exactly above our current cell. I have no idea why it loves going straight up most of the time with that implementation. Nevertheless, the new algorithm (which reflects the old one, but is much lighter) is:
boolean[] lines = new boolean[]{false, false, false};
byte checks =0;
while(checks < 3) // just 3 tries in total
{
dice = r.nextInt(3);
if(lines[dice]== false)
{
lines[dice] = true; // just 1 try per line
// calculated here since we reuse dice below
result[1] = yPos - 1 + dice; // will be above if dice==0; will be below if dice==2; same line if dice==1
if((dice == 0) || (dice == 2)) // top/bottom line
{dice = r.nextInt(3)-1;}
else if(dice == 1) // middle line
{dice = r.nextInt(2)==0?-1:1;} // we exclude the middle point since that's our current position
result[0] = xPos + dice; // logic is calculated above and just applied here
checks++;
}
if((result[0] >= 0)
&& (result[0] < img.getWidth())
&& (result[1] >= 0)
&& (result[1] < img.getHeight()))
{
if (img.getRGB(result[0], result[1]) == Color.white.getRGB()) // if the new cell is free
{
return result;
}
}
}
result[0] = -1; // in case we get here, reset the value so it's not used
This brings the code down from 167 lines to 33 lines (and makes it MUCH more readable). I have no idea who to select as the best solution. Please suggest if you have any ideas.
First, I have to admit I can't see what your algorithm is supposed to be doing -- it's not clear to me why you roll the each die when you do, other times using the existing value.
For a clear, easy to follow algorithm, I'd suggest scoping your dice variables inside the loop, rolling both at the same time, and making them final so that you know that each iteration has exactly one two-die roll:
while(strike < 9) {
final int roll1 = r.nextInt(3) - 1;
final int roll2 = r.nextInt(3) - 1;
strike += handleRoll(roll1,roll2);
}
You can prove the distribution to yourself by writing a simple counter for your handleRoll(), before later substituting your real code.
int[] counts = int[6];
void handleRoll(int roll1, int roll2) {
counts[1 + roll1] ++;
counts[4 + roll2] ++;
return 1;
}
(Increase the required strike count to get large enough samples to reason about)
Make sure you use the same instance of Random throughout the program -- don't keep making new ones.
(You could tidy this up a bit by creating a Coordinate class and a factory that creates random ones)
I simplified your code like this:
made a series of extract-method refactorings to tidy away detail
changed your rolls to use the range 0 to 2 instead of -1 to +1 -- since you use them in two places, and in one of those you add one again!
used x and y and only create result when needed
used final for the rolls and the resulting x and y, scoping them to the inside of the loop
turned nested ifs into an && logic
changed some odd type choices. The positions grid seems made for boolean. There's seldom any value in using short in Java.
So:
private int[] cellularSearch(int xPos, int yPos) {
boolean[][] positions =
new boolean[][] { { false, false, false },
{ false, true, false },
{ false, false, false } };
int strike = 0;
while (strike < 9) {
final int dice0 = r.nextInt(3);
final int dice1 = r.nextInt(3);
final int x = xPos + dice0 - 1;
final int y = yPos + dice1 - 1;
if (isInXrange(x) && isInYRange(y)) {
if (!alreadyTried(positions, dice1, dice0) && isWhite(x, y)) {
return new int[] { x, y };
}
markAsTried(positions, dice1, dice0);
strike++;
}
}
return null; // or whatever you intend to happen here
}
private boolean isInXrange(int x) {
return (x >= 0) && (x < img.getWidth());
}
private boolean isInYRange(int y) {
return (y >= 0) && (y < img.getHeight());
}
private boolean alreadyTried(boolean[][] positions, final int dice1, final int dice0) {
return positions[dice1 + 1][dice0 + 1];
}
private static void markAsTried(boolean[][] positions, int dice1, int dice0) {
positions[dice1][dice0] = true;
}
private boolean isWhite(final int x, final int y) {
return img.getRGB(x, y) == Color.white.getRGB();
}
I think this is equivalent to your code, with one exception -- yours doesn't roll the second die if the first roll takes you outside the width of the image. You could re-add this as a performance improvement later if you like.
But it exposes some issues. It looks as if the intent is to try every cell (you have a 3x3 grid, and you've chosen 9 "strikes") - but it doesn't increment strike when x,y is outside the image. It does increment strike when the position has been tried before. So you can exit the loop having not tried every cell.
I don't see a specific way that this causes the weighting you've described --
but it looks like the sort of thing that could lead to unexpected results.
(Anyway - since the code you've given doesn't compile, you didn't observe it with the code you've given us)
If the intention is to check every cell, it might be better to shuffle a list of cells to try, then test them in order:
List<Coords> coordsToTry = new ArrayList<>();
for(int x=0; x<2; x++) {
for(int y=0; y<2; y++) {
coordsToTry.add(new Coords( x, y));
}
}
Collections.shuffle(coordsToTry);
for(Coords coords : coordsToTry) {
if(isWhite(coords)) {
return coords;
}
}
return null; // or whatever is meant to happen when nothing found
The distribution of java.util.Random is not that uneven. You can confirm with the following code:
public static void main(String[] args) throws Exception {
final int N = 3;
Random r = new Random();
int[] counts = new int[N];
for (int i = 0; i <= 100_000; i++) {
counts[r.nextInt(N)]++;
}
System.out.println(Arrays.toString(counts));
}
UPDATE:
As you've said, the above code produces fairly evenly distributed values. However, add the following line at the beginning of the loop:
if (i % 6 == 0)
r = new Random(0);
And then you get [16667, 33334, 50000]. One value occurs twice as frequently, and another 3 times as frequently, as the first. This sets the random number generator to a newly created one with a constant seed. It simulates your code, in which you say you create a new Random() on entry to your function (albeit without a seed argument) and then your function calls nextInt() six times - this if (i % 6 == 0) statement ensures a new RNG is also created every 6 iterations.
Check your code and make sure you are only ever creating a RNG once in your whole program.
java.util.Random is a pseudorandom number generator (definition on wikipedia) and needs to be seeded.
From the docs:
If two instances of Random are created with the same seed, and the same sequence of method calls is made for each, they will generate and return identical sequences of numbers. In order to guarantee this property, particular algorithms are specified for the class Random.
If you want to be sure to get good random numbers, use SecureRandom, which is guaranteed to produce non-deterministic output
Since you are interested in the combined distribution of the two 'dices', on top of #DodgyCodeException's suggestion, you can check statistics like
public static void main(String[] args) {
Random r=new Random();
int stat[]=new int[9];
for(int i=0;i<9000;i++)
stat[r.nextInt(3)+r.nextInt(3)*3]++;
for (int i : stat)
System.out.println(i);
}
However it is pretty even too.
There is a minor difference between generating random numbers from a power-of-two-range and otherwise, so if you really want to do some magic, you can use the fact that you are actually picking a position out of 8 possibilities (since the middle one is ruled out at the beginning).
Something like
final int xhelper[]=new int[]{-1, 0, 1,-1, 1,-1, 0, 1};
final int yhelper[]=new int[]{-1,-1,-1, 0, 0, 1, 1, 1};
...
int dir=r.nextInt(8);
int dice0=xhelper[dir];
int dice1=yhelper[dir];
But in fact I do not think it makes a difference.

What is wrong with my Java recursive function?

I'm trying to write a relatively straightforward recursive program in Java to compute all the possible ways to traverse a 4x4 matrix (not necessarily traveling through every spot), starting at the top left and ending in the bottom right spaces. I use a 2-D array to do this, marking off visited spaces with "1"s as I go.
It's been a while since I've worked recursively and I can't seem to get the output I expect. The output from the code below is "2" - obviously, the result should be much higher. I know there's something tiny I'm overlooking. Can someone tell me what it is?
public static void main(String[] args) {
int[][] matrix = new int[4][4];
int result = moveRobot(matrix, 0, 0);
System.out.print(result + "");
}
public static int moveRobot(int[][] matrix, int x, int y) {
if (x == 3 && y == 3) {
return 1;
} else if (x < 0 || y < 0 || x > 3 || y > 3) {
return 0;
} else if (matrix[x][y] == 1) {
return 0;
} else {
matrix[x][y] = 1;
return moveRobot(matrix, x, y+1) + moveRobot(matrix, x+1, y) + moveRobot(matrix, x, y-1) +
moveRobot(matrix, x-1, y);
}
}
The problem is that the matrix is not copied but passed by value of the reference to it. Every time you modify it such in matrix[x][y] = 1 other successive code paths will see the modification instead that working on an unmodified state.
For example here:
moveRobot(matrix, x, y+1) + moveRobot(matrix, x+1, y)
Entering the first call will modify matrix, so in second moveRobot call you'd end up with 1 in matrix[x][y+1] while that's not what you want.

Collision Detection Error

I am currently working on a relatively simple platform game that has an odd bug. You start the game by falling onto the ground (you spawn a few blocks above the ground), but when you land your feet get stuck INSIDE the world and you can't move until you jump. Here's what I mean:
http://i.imgur.com/IKLZY.png
The player's feet are a few pixels below the ground level. However, this problem only occurs in 3 places throughout the map and only in those 3 select places. I'm assuming that the problem lies within my collision detection code but I'm not entirely sure, as I don't get an error when it happens.
public boolean isCollidingWithBlock(Point pt1, Point pt2) {
//Checks x
for(int x = (int) (this.x / Tile.tileSize); x < (int) (this.x / Tile.tileSize + 4); x++) {
//Checks y
for(int y = (int) (this.y / Tile.tileSize); y < (int) (this.y / Tile.tileSize + 4); y++) {
if(x >= 0 && y >= 0 && x < Component.dungeon.block.length && y < Component.dungeon.block[0].length) {
//If the block is not air
if(Component.dungeon.block[x][y].id != Tile.air) {
//If the player is in contact with point one or two on the block
if(Component.dungeon.block[x][y].contains(pt1) || Component.dungeon.block[x][y].contains(pt2)) {
//Checks for specific blocks
if(Component.dungeon.block[x][y].id == Tile.portalBlock) {
Component.isLevelDone = true;
}
if(Component.dungeon.block[x][y].id == Tile.spike) {
Health.health -= 1;
Component.isJumping = true;
if(Health.health == 0) {
Component.isDead = true;
}
}
return true;
}
}
}
}
}
return false;
}
What I'm asking is how I would fix the problem. I've looked over my code for quite a while and I'm not sure what's wrong with it. Also, if there's a more efficient way to do my collision checking then please let me know!
I hope that is enough information, if it's not just tell me what you need and I'll be sure to add it.
Thank you!
The problem probably isn't your collision check, but your logic of what to do on collision. Your character is falling into the block which once in there is always colliding with the block. So it won't be able to jump (since you check for collision when jumping I guess). When you check for collision you have to make sure your character doesn't fall into the block by pre-checking and adjusting.
if (will collide) {
put beside block
}
You're probably doing something like
if (colliding) {
stop moving
}
When putting beside though, you have to check which way you're moving and that you don't move into blocks.

2D Collision Detection between squares, simple but more specific than boolean + immune to large spacial jumps

Would like to know which direction player hits terrain tile from (just a simple up/down, left/right). Everything I find is either too simple, or is much more complex and seemingly way too much for what I need, like with AABB (granted it's hard to tell, my brain has trouble digesting what amounts to really long equations). What I've got so far is the result of spending better part of today reading and experimenting:
public int move(double toX, double toY) {
int col = COLLISION_NONE; //these are bit flags, in case I collide with a block to my right as well as below me
double nextX = mX+(toX*main.getDelta()); //delta regulates speed
double nextY = mY+(toY*main.getDelta());
if(mTerrainCollision){
int w = GameView.GameLoop.TILE_WIDTH;
int h = GameView.GameLoop.TILE_HEIGHT;
for(int i = -2; i <= 2; i++) //broad tile picking will be optimized later, better trace around players path
for(int j = -2; j <= 2; j++) {
GameTerrain.Block block = main.mTerrain.get(((int)Math.round(mX)/w)+i,((int)Math.round(mY)/h)+j);
if(block.type != GameTerrain.BLOCK_TYPE_NONE) {
if(nextX+w >= block.x() && mX+w <= block.x()){ //COLLISION ON THE RIGHT?
if(mY+h > block.y() && mY < block.y()+h) { //<THIS is a problem line, see below
nextX = block.x() - w;
xMomentum = 0;
col |= COLLISION_RIGHT;
}
}
else if(nextX < block.x()+w && mX >= block.x()+w){ //COLLISION ON THE LEFT?
if(mY+h > block.y() && mY < block.y()+h) { //same as above, make sure were on the same plane
nextX = block.x() + w;
xMomentum = 0;
col |= COLLISION_LEFT;
}
}
if(nextY+h >= block.y() && mY+h <= block.y()){ //COLLISION ON THE BOTTOM?
if(mX+w > block.x() && mX < block.x()+w) { //make sure were on the same plane
nextY = block.y() - h;
yMomentum = 0;
col |= COLLISION_DOWN;
}
}
else if(nextY < block.y()+h && mY >= block.y()+h){ //COLLISION ON THE TOP?
if(mX+w > block.x() && mX < block.x()+w) { //make sure were on the same plane
nextY = block.y() + h;
yMomentum = 0;
col |= COLLISION_UP;
}
}
}
}
}
mX = nextX;
mY = nextY;
return col;
}
It works... mostly. Player won't phase through blocks even after long sleeps making the delta skyrocket. The collision detection itself works unless the player's previous position (mX/mY) are not on the same plane as the block we're checking (see commented line with "THIS..."). Say we're perfectly diagonal to a block and moving straight for it, player will zip right through. I've been scratching my head for a while now trying to figure out how to go about solving this last issue, preferably without a major rehaul of everything, but if it had to come to that oh well! I'm only interested in simple collision data for things like "Did I touch a floor this frame? Ok I can jump", "Am I touching a wall right now? Ok I can wall jump, but not if I also touched a floor", etc.
Grow the wall's AABB by the size of the object's AABB (keeping the center of the wall's AABB fixed), construct a line segment from the object's before and after positions (use the center of the object's AABB), then do a segment-AABB intersection test.

Categories