How can I optimize my code that uses nested for loops? - java

I am working to solve a problem where I need to determine if a Point lies on a line connecting two other Points. For example, if I have Point a, b, c, I want to determine if c is on the line segment connecting a and b. In my code, I have a point, me (a in the example) and two lists of points, hits (b in the example) and reachable (c in the example). For each point in hits, I want to determine if there is any point in reachable that is on the line segment that connects me and the point in hits. If there is a point on that line segment, then numHits needs to be decremented. Here is my code:
Point me; //Point a from the example above
ArrayList<Point> hits = new ArrayList<>(); //a list of Point b's from the example above
ArrayList<Point> reachable = new ArrayList<>(); //a list of point c's from the example above
for(Point hit : hits) {
for(Point p : reachable) {
if(!hit.equals(p) && !me.equals(p)) {
//find the equation of a line from me to hit
if(hit.x - me.x == 0) { //if the line has an undefined slope... if the line is vertical
if( (((p.y <= hit.y) && (p.y >= me.y)) || ((p.y >= hit.y) && (p.y <= me.y))) && p.x - me.x == 0) { //if there is any occupied point on that line in between me and the hit, that point blocks the hit
numHits--;
break;
}
} else {
//create a line from me to the hit... if there is any occupied point on that line in between me and the hit, that point blocks the hit
double deltaY = hit.y - me.y;
double deltaX = hit.x - me.x;
double m = deltaY / deltaX; //slope
double b = me.y - (double)(m*me.x); //y intercept
if((double) p.y == ((double)(m * p.x) + b)) { //if this point is on the same line
if( ((p.x <= hit.x && p.x >= me.x) && (p.y <= hit.y && p.y >= me.y)) ||
((p.x <= hit.x && p.x >= me.x) && (p.y >= hit.y && p.y <= me.y)) ||
((p.x >= hit.x && p.x <= me.x) && (p.y >= hit.y && p.y <= me.y)) ||
((p.x >= hit.x && p.x <= me.x) && (p.y <= hit.y && p.y >= me.y))) { //if the point is in between me and the hit
numHits--;
break;
}
}
}
}
}
}
My code works to determine if there is any point in reachable between me and each point in hits, it just gets incredibly slow the larger hits and reachable get. For example, if hits has a size of 780,000 and reachable has a size of 1,500,000 the code takes a very long time to run. I was wondering how I may be able to optimize this to run more quickly. I'm not sure if the bottleneck issue lies in the loops themselves or in the code within the loops. Any help or optimization ideas are greatly appreciated. Thank you!

I recommend you look at Line2D.Double. It has many methods including ones to determine if a point or even a line is on a given line segment.
I would also suggest that you use a map to memoize existing points and other information that you may have already encountered. That way you won't keep repeating calculations. Because floating point operations can result in miniscule differences you will probably have to use some acceptable error to determine the validity of the result.

One way you can optimise the code is by shifting the point me to origin, after that divide all points to respective quadrants, so now you only have to compare the points which are in same quadrants.
I will write a rough algorithm below.
1. Shift the point me to origin
2. Shift all other points, ie hits and reachable to origin ( this can be done by subtracting X and Y of point me from all other X and Y )
3. Now divide hits and reachable to 4 quadrants based on their X and Y components, now you will have 4 arrays for hits and 4 arrays for reachable
4. You can also reduce the number of points in reachable by comparing them against the greatest point in hits like below, do this for all quadrants
a. find greatest |X| (mode(X)) and greatest |Y| of hits in each quadrant, lets call it me.|x| and me.|y|
b. for(Point p : reachable) {
if(p.|x| > me.|x| or p.|y| > me.|y|) then remove p from reachable }
since these points will be outside of the line segment formed by me and hits
5. Now you can compare the values, using nested for loops as you did, you will have to use different conditions for each quadrant
Don't forget to add edge conditions and to shift back from origin

Project each line ac to x = 0 or y = 0, whichever is of smaller magnitude (so as to minimize rounding errors). Sort or hash these intercepts, keeping a reference to each c, making sure to preserve duplicates.
Then for each line ab, project that also to x = 0 or y = 0, whichever is of smaller magnitude, and search a matching intercept in your sorted or hashed collection. This gives you a small number of candidate line segments which all lie on the same line through a, b and c; you only need to check that the point lies within the endpoints (a.x < c.x < b.x or a.x > c.x > b.x and again for y).
Be careful about rounding errors.

Related

More efficient way to check if a value is included in an array?

Writing a game that does lots of comparisons, and it's lagging. I'm trying to speed it up, and this particular chunk of code is run thousands of times every frame, for different values of x y and z. Is there a better way to check if the values of x y and z are valid in the array? (java)
if (x >= 0 && x < blocksArr.length && y >= 0 && y < blocksArr[x].length && z >= 0 && z < blocksArr[x][y].length && blocksArr[x][y][z])
I've tried checking if blocksArr[x][y][z] != null and checking if blocksArr[x][y][z] != undefined but neither give results.
In general, the most efficient way of doing t >= 0 && t < u with u known to be positive is to compare the unsigned value of t and u using Integer.compareUnsigned(t, u) < 0. As a result, your if can be more efficiently expressed as
if (Integer.compareUnsigned(x, blocksArr.length) < 0 &&
Integer.compareUnsigned(y, blocksArr[x].length) < 0 &&
Integer.compareUnsigned(z, blocksArr[x][y].length) < 0 &&
blocksArr[x][y][z])
However, I think your representation of blocksArr as a 3-dimensional array is really inefficient and results in a lot of indirections, which greatly hinders the potential performance. A more logical approach is to represent it as a single array and have length, width, height being stored separately. This would result in your code looks something like this:
if (Integer.compareUnsigned(x, length) < 0 &&
Integer.compareUnsigned(y, width) < 0 &&
Integer.compareUnsigned(z, height) < 0 &&
blocksArr[x * (width * height) + y * height + z])
This however limits your block to around 2 billion elements, to overcome this limitation, you need to resort to the Memory Access API, which is currently in preview. It has an important advantage that it allows the allocation and deallocation of memory blocks to be deterministic, which is much more desirable for too large memory pieces. Using a memory segment to represent the blocksArr, your code would become:
if (Long.compareUnsigned(x, length) < 0 &&
Long.compareUnsigned(y, width) < 0 &&
Long.compareUnsigned(z, height) < 0 &&
blocksArr.get(ValueLayout.JAVA_BOOLEAN, x * (width * height) + y * height + z))
Moreover, since blocksArr is a block of boolean values, packing them so that each element occupies only 1 bit will improve the memory consumption and cache pressure greatly. The check now can be expressed as:
long index = x * (width * height) + y * height + z;
long byteIndex = index >>> 3;
int shift = (int)(index & 7);
if (Long.compareUnsigned(x, length) < 0 &&
Long.compareUnsigned(y, width) < 0 &&
Long.compareUnsigned(z, height) < 0 &&
blocksArr.get(ValueLayout.JAVA_BYTE, byteIndex) & (1 << shift) != 0)
I don't know java but in general, I would expect the following to be at least as fast, possibly faster.
Your compiler may do something like this anyway so it might not be faster. You can split the 'If' statement up so that it will do fewer lookups. Sorry, but I'll have to write it as c code. You can get the idea and translate to java.
if (x >= 0 && y >= 0 && z >= 0 && x < blocksArr.length) {
if (y < blocksArr[x].length && z < blocksArr[x][y].length && blocksArr[x][y][z]) {
.....
}
}
Assuming user16320675 is correct about the evaluation order, you could use one 'if' statement. I don't know how the java compiler works.
if (x >= 0 && y >= 0 && z >= 0 && x < blocksArr.length && y < blocksArr[x].length && z < blocksArr[x][y].length && blocksArr[x][y][z]) .....
What you are doing is a bounds check, to make sure that the indexes x, y, and z are valid indices in the blocksArr[][][] array. In C, this is necessary as C allows you to go outside the array.
Java, however, does a bounds check every time you access the array. So you are doing a manual bounds check, then another check, plus Java is doing a check on two dimensions, and finally Java does another check on three dimensions.
All you really need to do is access the array, let Java do the bounds check, and catch an exception if any of the indices are out of bounds.
boolean value;
try
{
value = blocksArr[x][y][z];
}
catch (ArrayIndexOutOfBoundsException e )
{
value = false;
}
There is some overhead in setting up a try/catch block, but overall it should be faster.
You have a box determined by three dimensions, x, y, and z.
If any of those indices are outside the boundaries of the box, then the entire if() statement is false. So there is no need to walk through things like blocksArr[x].length
Also, think about what is actually going on under the hood. The variable x is in fact a pointer to a location in memory which holds the value. To process a statement like x >= 0, the computer must locate the memory location for x, fetch that value and put it into one of its internal registers, say register A. It then takes that value 0 and puts it into register B. It compares Register A to register B. if A > B, then it goes on to the next operation, otherwise it compares A to B again. If the comparison is zero, then it goes to the next operation, otherwise it move the operation pointer past the if() statement.
For comparing x < blocksArr.length, it again fetches x, then fetches blocksArr calculates the offset to the length value, then fetches that into the register, where it does the comparison.
You can shorten all of this by using some static constants.
Consider that x >= 0 can be re-written as x > -1. This can potentially reduce 2 comparisons to 1, so a few CPU cycles saved.
An array construct is an immutable object, that is it cannot be changed after being created. So an array's length will never be different. So if you created an array with size 5, blocksArr.length will always return 5. in the comparison x < blocksArr.length you could substitute x < 5, which means the CPU does not need to fetch blocksArr.length, which saves CPU cycles.
So you could re-write the array creation, and your if statement to:
public static final int MAX_X = 10;
public static final int MAX_Y = 15;
public static final int MAX_Z = 20;
public boolean blocksArr[][][] = new boolean[MAX_X][MAX_Y][MAX_Z];
.
.
.
if ( ( x > -1 && x < MAX_X ) && // validate for X dimension
( y > -1 && y < MAX_Y ) && // validate for Y dimension
( z > -1 && z < MAX_Z ) && // validate for Z dimension
blocksArr[x][y][z] ) // check value
I think this is the least CPU intensive way of doing this.

Line and point collision in java

I'm making a tron game and have everything except for the collision. Currently making it through MVC (required as it is an AP Compsci project) and I am having trouble with the collision between the trail and the bike. My idea is to have a point on the racer to which it collides with (the front point). The light trails are drawn with a list of points, the first point being the start point and each point after are added when the racer turns. The last point is the current location of the bike. It draws a line between each point in paintComponent, and also uses a method in the Line class (which contains the arraylist of points) to check collision. So far I have tried to see if the front point is on any of the axis (that is, if the x or y value is equal to any of the corresponding x or y pvalues on the line) and then check the opposite coordinate and check if the x or y is in between the x or y of two points on that axis, and return true or false if they are. Here is what I mean:
public boolean checkPoint(Point p)
{
for(int k = points.size() - 1; k > 0;k -= 2)
{
//if the x's are the same ( vertical ), check if within y's
if(p.getX() == points.get(k).getX() && p.getX() == points.get(k - 1).getX())
{
if(points.get(k).getY() > points.get(k - 1).getY()){
if(p.getY() < points.get(k).getY() && p.getY() > points.get(k-1).getY())
return true;
}
if(points.get(k).getY() < points.get(k - 1).getY()){
if(p.getY() > points.get(k).getY() && p.getY() < points.get(k-1).getY())
return true;
}
}
// if the y's are the same (horizontal), check if within x's
if(p.getY() == points.get(k).getY() && p.getY() == points.get(k - 1).getY())
{
if(points.get(k).getX() > points.get(k - 1).getX()){
if(p.getX() < points.get(k).getX() && p.getX() > points.get(k-1).getX())
return true;
}
if(points.get(k).getX() < points.get(k - 1).getX()){
if(p.getX() > points.get(k).getX() && p.getX() < points.get(k-1).getX())
return true;
}
}
}
}
The game either runs really slowly after a few seconds and works, or doesn't work at all. Am I going in the right direction, how should I go about this?

Finding smallest neighbour in a 2D array

I have some code that is supposed to find the smallest of the 8 neighboring cells in a 2D array. When this code runs, the smallest is then moved to, and the code run again in a loop. However when it is run the code ends up giving a stack overflow error as it keeps jumping between two points. This seems to be a logical paradox as if Y < X then X !< Y. So it think it is my code at fault, rather than my logic. Here's my code:
private Point findLowestWeight(Point current) {
float lowest = Float.MAX_VALUE;
Point ret = new Point(-1, -1);
LinkedList<Point> pointList = new LinkedList<Point>();
for (int i = -1; i <= 1; i++) {
for (int j = -1; j <= 1; j++) {
if (!(i == 0 && j == 0)) {
if ((current.x + i >= 0 && current.x + i <= imageX - 2)
&& (current.y + j >= 0 && current.y + j <= imageY - 2)) {
pointList.add(new Point(current.x + i, current.y + j));
}
}
}
}
for (Point p : pointList){
if (map[p.x][p.y] < lowest){
lowest = map[p.x][p.y];
ret = p;
}
}
return ret;
}
You need a stopping case.
find the smallest of the 8 neighboring cells in a 2D array. When this code runs, the smallest is then moved to, and the code run again in a loop
is a fine way to start but says nothing about stopping.
Do you care about the value of the current cell? If so you need to check 9 not 8. If you simply want to move down hill then you need to check where you've been or any flat multi-cell valley will put you into an infinite loop. Consider only moving if moving down.
If you truly don't care where you are then even a single cell valley will put you into an infinite loop as you bounce in and out of it. In which case you'd need some other stopping condition. Consider stopping after imageX * imageY iterations.
Do you move even if the smallest neighbour is greater than the value in the center?
Example:
2 2 2 2
2 0 1 2
2 2 2 2
You start with center cell 0. The smallest neighbour is 1. If you move to 1, the smallest neighbour is 0. You can continue endless.
Probably you should not move, if the smallest neighbour is greater than the current cell.

Players appear to be colliding with air?

(Will be putting a bounty on this - Also, I'm not 100% sure what tags are relevant for this)
I'm incredibly confused here. I am attempting to use this (simplified) model for my archers to collide with:
However, as you can see, my archers appear to be colliding in mid-air! I would understand if they fell through (e.g. I had not put enough "points" in my collision model), but to actually appear to be colliding with NOTHING is absolutely baffling me.
I'm loading the model on the server with the same code that I'm displaying it there in the client, so that can't be the issue. I've pastebinned it here anyway.
Then, I'm adding it to three int[] arrays, like this:
coordsx = new int[80 * 10];
coordsy = new int[80 * 10];
coordsz = new int[80 * 10];
for (javax.vecmath.Vector3f vec : m.getVertices()){ //Quick note: M is a model. As you can see, I'm just going through all the vertex positions.
coordsx[DELTA+(int) vec.x] = 1;
coordsy[DELTA+(int) vec.y] = 1;
coordsz[DELTA+(int) vec.z] = 1;
}
Quick note: DELTA is the value of ((80 * 10) / 2) or to save you the math, 400. Also, I used three int[]'s and not an int[][][] because an int[][][] caused an OutOfMemory which I couldn't fix.
Now that I have got these arrays of coordinates, I'm using this code to check it:
for (int x = (int) (location.x + 1); x > location.x - 1; x--){
for (int y = (int) (location.y + 1); y > location.y - 1; y--){
for (int z = (int) (location.z + 1); z > location.z - 1; z--){
distancex = x;
distancez = z;
distancey = y;
try{
int i = 0;
if (owner.type == 0){
if (GameServer.DELTA + distancex > 0 && GameServer.DELTA + distancex < 800 && GameServer.coordsx[(int) (GameServer.DELTA + distancex)] == 1){
if (GameServer.DELTA + distancey > 0 && GameServer.DELTA + distancey < 800 && GameServer.coordsy[(int) (GameServer.DELTA + distancey)] == 1){
if (GameServer.DELTA + distancez > 0 && GameServer.DELTA + distancez < 800 && GameServer.coordsz[(int) (GameServer.DELTA + distancez)] == 1){
i = 1;
}
}
}
}
if (i == 1){
collision = true;
YDown = 0;
}
}catch (ArrayIndexOutOfBoundsException e1){
e1.printStackTrace();
}
}
}
}
if (collision){
System.out.println("Collision!");
}else{
System.out.println("No Collision!");
location.y = location.y-=YDown;
}
location is a Vector3f of the archers' X, Y, and Z relative to the ship's location - I've checked this using de-bug messages, and the location is indeed returning correctly.
As you can see, the variable i is only being set to 1 if there is a coordinate at both the X, Y, and Z location of the point that is being checked. Obviously, I am iterating through all the nearby coordinates as well, since my player is not just a single point.
Since the player appears to be colliding with air, then there is obviously something wrong. But I cannot find what.
Am I on the right track here, or am I doing everything entirely wrong? And if I am on the right track, then what is going wrong here and how can I fix it?
There is a problem with your model. Using three arrays may save memory, but it also changes the model, creating "shadows" that your archers can collide with.
Let's say that you have vertices in (1,1,1) and (2,2,2).
Using your model, there will also a vertex at (1,2,2) and any other combination where all coordinates is either 1 or 2.
So, back to the drawing board.
Maybe you can save memory by using a single bit instead of a 32 bit int for each coordinate?
Or you could change the way you store the model. What if you use a 2-dimensional array of int and store the z-coordinate(s) of the floor. This would limit your world to one (or just a few) floors at each x,y-coordinate but would save a huge amount of memory.

Java logical test questions

I've been solving a few problems about logic tests for AP Computer Science but I happened to get stuck on a few questions.
Here are the directions from the website: Translate each of the following English statements into logical tests that could be used in an if/else statement. Write the appropriate logical test for each statement below. Assume that three int variables, x, y, and z, have already been declared.
These are the 2 questions I have problems with:
Either x or y is even, and the other is odd.
x and z are of opposite signs.
I've been trying to find these answers out for a couple of hours and I still have no clue. I would appreciate it if someone could guide me in the right direction. I understand this is "homework" but some definitive help would be very helpful.
For the first question: x % 2 != y % 2
Second question: x * z < 0
You'll need to use and (&&) and or (||) to make a logic formula. I'm not going to do yours, but here's another one:
x is bigger than both y and z or x is less than both y and z.
Translates to:
((x > y) && (x > z)) || ((x < y) && (x < z))
You just need to figure out a formula for odd/even (hint - the low order bit) and for positive/negative (hint - compare with 0), and combine those with and/or.
For the first question, if x (or y)* is odd, y (or x) must be even, and vice versa. Checking for odd values implies that the modulo of x and 2 is 1 - from there, you would have to assert if y (or x) modulo 2 is 0 (to check for evenness).
For the second question, you would need to follow a chain of logic as such:
X is positive (or greater than 0), which implies Z must be negative (or less than 0).
Z is positive, which implies that X must be negative.
*: This is an exclusive or - I mean that you're either checking x or y, but not both at the same time.
First you have to fully understand the statement in order to put it into the language of a computer. For example,
x and y have the same sign
What this really means is:
( x is greater than or equal to 0 and y is greater than or equal to 0 ) or ( x is less than 0 and y is less than 0 )
Now it is easy to put this into Java:
(x >= 0 && y >= 0) || (x < 0 && y < 0)
Of course, your questions can be solved via a similar method.
Either x or y is even, and the other is odd.
The sum of an odd and even number is odd. The sum of two odd numbers is even and the sum of two even numbers are even.
So (x+y)%2!=0.
x and z are of opposite signs
This one is similar, you can do:
x*z<0
Since 0 is neither negative or positive and
neg * pos = neg
neg * neg = pos
pos * pos = pos
If you want to consider 0 and a negative number of opposite signs you can use (x >= 0) == (z < 0)
Putting it in plain english, for me anyhow.
If ((x is even AND y is odd) OR (x is odd AND y is even))
For the other
If ((x gt or eq 0 AND y lt 0) OR (y gt or eq 0 AND x lt 0))
Assuming 0 is positive.

Categories