I am working with the library JInput to detect controller input in a java game. However, in order to get the direction the axis is moving, I use this:
gamePadContr.getComponent(Identifier.Axis.X).getPollData();
This gives me a decimal between -1 and 1, which tell the direction. I want the player to be able to move in more than just up, down, left, and right, so there are 40 if statements in my gameloop that check if the number is a certain set of numbers, and increasing the x and y coordinates accordingly. Here is an example:
if(x > .1 && x < .2 && y == 1){
// do stuff
} else
if(x > .2 && x < .3 && y == 1{
// do stuff
}
I have to check each one to make sure that most directions are accounted for.
My point is, 40 if statements is lagging. Is there anything I can do to optimize this?
A few edits to answer questions:
Didn't think it was relevant, but the reason increments of .1 have 40 different if statements is because I am checking the X and Y axis of the joystick. The possible combinations are (1, -1) (1, 1) (-1, 1) (-1, -1), giving me negatives and positives in 40 different combinations at increments of .1. (I don't know if that made sense.
//do stuff is just increasing the x and y coordinates of the player by certain amounts.
The best approach might be to discover a rule whereby you can directly compute the player's coordinate change directly from the joystick coordinates. For that, we would need details of what // do stuff is for each branch.
Another possibility, which is good if you don't have a simple relationship, is to convert your tests to a look-up by transforming the x and y values to array indexes
int xIndex = (int) (10 * x + 10); // an int between 0 and 20
int yIndex = (int) (10 * y + 10); // ditto
Then you can look up the player's coordinate changes in a 2-D array that you compute once ahead of time. More generally, you could have an array of Runnable objects, look up the appropriate Runnable based on the indexes, and run() it.
P.S. If each joystick coordinate can fall into any of 20 different ranges, then you have 400 cases, not 40. That is, unless you are always ignoring one or the other of the axes.
One thing you can do is nest your conditions. Instead of
if (x > .1 && x < .2 && y == 1){doStuff();}
else if (x > .2 && x < .3 && y == 1){doStuff();}
else if (x > .1 && x < .2 && y == 2){doStuff();}
else if (x > .2 && x < .3 && y == 2){doStuff();}
you may want to consider:
if (y == 1){
if (x > .1 && x < .2){doStuff();}
else if (x > .2 && x < .3){doStuff();}
}
else if (y == 2)
{
if (x > .1 && x < .2){doStuff();}
else if (x > .2 && x < .3){doStuff();}
}
Now your code can skip all the if checks that it knows aren't true. Instead of having to check up to 20*20 = 400 if statements, the program only has to check up to 20+20=40 if statements in any given loop. You will still HAVE a ton of if statements - in fact, you'll have slightly more than you had before - but 90% of them will be skipped, and they'll each be shorter, so the program will run faster.
You can also reduce the number of checks in each if statement with clever ordering. If you already checked x < .5 and it was false, then you already know that x < .4 is false. For example:
if (y == 1){
if (x > .9 ){doStuff();}
else if (x > .8){doStuff();} // no need to check if it's less than .9 since the previous line covered that case
}
Related
Can any kind soul please explain why
! (x < 0 && y < 0)
is not equivalent to the following two expressions
!(x < 0) && ! (y < 0) AND x > 0 && y > 0
In the first code doesn't it imply that, x is not less than 0 and y is not less than 0? and does it also not mean that x and y should be more than 0?
Any help is much appreciated!
In your two rewritten versions, you'd need OR (||) rather than AND (&&). This is true any time you invert an AND condition's component parts.
! (x < 0 && y < 0) is true if x is >= 0 and y is < 0. To get that same result in the other form, you'd need x >= 0 || y >= 0. (Note that it's >=, not just >, but the main point was the || rather than &&.)
As ernest_k points out, this is one specific application of De Morgan's laws.
Let's calculate the equivalent expression for ! (x < 0 && y < 0)
Note that if negation comes before &&, it becomes || and vice versa. so your expression would be equal to :
! (x < 0 && y < 0) ---> !(x<0) || !(y<0) ---> x>=0 || y>=0
it's like the figure bellow, colored area is the result of your expression :
In the first example both of the expressions in brackets ("(x < 0)" and "(y < 0)") have to be equal to "true" for the whole expression to become "false".
In the second example the first two expressions contain each one of the expressions, which are inside the brackets of the first example ("(x < 0)" and "(y < 0)"). So only one of these expressions being "true", can cause the whole expression to become "false" since everything is connected with AND operators.
You can set x=0 and y=-1 and try it out manually.
You also might be interested in having a look at https://en.wikipedia.org/wiki/De_Morgan's_laws
I have this problem: I want to check if an int is bigger than 10, if not than if he is bigger then 100..and so on.
Is there a better way than just doing this:
public void multipleIf(int x){
if(x > 10){
...
} else if(x > 100){
...
} else if(...
}
Thanks.
A number that is greater than 100 is always greater than 10.
If you want only numbers in the range 10-100 exclusive, you can use operators. You could test for a number that is greater than 10 but less than 100 by using logical operators:
if(x > 10 && x < 100) {
/* Body */
} else if(x > 100 && x < ....) {
/* Body */
}
The && is a logical AND operator that checks if both conditions are true. So, it checks if x is inside the range, exclusive.
If you want only numbers greater than 100, use separate if statements.
You can also use a switch statement.
Actually, if you know what your limit is (say 10,000), you can simply start from the top.
if(x > 10000)
....statement 1
else if (x > 1000) // using this else here is important
....statement 2
else if (x > 100)
....statement 3
else if (x > 10)
....statement 4
The else is important because it only executes if the previous if (or else if) is not executed (the statement is false). Thus we can see that statement 1 executes for any x greater than 10,000. If it's not greater than 10,000, but greater than 1000, then statement 2 executes. If x is not greater than 1,000, but greater than 100, then statement 3 executes. And at the end, depending on your code, you can just put an else statement somewhere.
I want to make a method that will return me a value (let's call it "z"). Its value is dictated by one other value(let's call this "y"). Basically what I want is to make it so that the following conditions are met:
As x approaches 0, z approaches 100.
As x approaches infinity, z approaches 0.
So far I have this as my code:
if(x == 0){
z = 100;
} else if(x1 > 0){
//Code for what happens otherwise.
}
else if(x1 < 0){
z = 100;
}
I'm really stuck on what to do otherwise. If anybody could lend their math/java expertise, I'd appreciate it.
z = 100.0 / (1 + x)
Remember to declare x and z as doubles if you want non-integer values.
Is this possible guys? This is homework I have, and my teacher obviously believes it is, but it seems to me that it's impossible not to use addition or multiplication outside of the short-multiplication method.
Write (and provide a tester for) a recursive algorithm:
int multiply(int x, int y)
to multiply two positive integers together without using the *
operator. Do not just add x to itself y times!!!
(Hint: Write a recursive method that will multiply an integer by a
value in the range 0 .. 10. Then write a second recursive method to
implement the multiplication algorithm you learned to multiply
multi-digit numbers in elementary school.)
My issue is that once you break down any multi digit number and starting adding those together you have to use multiplication of numbers greater than 10, i.e 22 * 6 is 2 * 6 + 20 * 6 ... so am I totally missing something?
EDIT
I guess I should have added this is the code I have,
public int mult(int x, int y){
return x == 0 ? 0 : (mult(x-1, y) + y);
}
which is perfect, but as far as I understand the instructions, that's breaking do not just add x to itself y times. I personally believe it isn't, but my teacher hasn't been very clear, and I'd like to know if there's some other way that I havn't thought of, sorry for the confusion.
Yes, it's possible. Yes, I think you're missing something. Try writing down the steps you'd follow to manually multiply two numbers, the way you learned in elementary school.
Then turn those steps into code.
My interpretation of the assignment is that the teacher would like the student to implement a recursive algorithm to perform Grid method multiplication (the kind we learn in elementary school).
For example, multiplying 34 x 13 would be done like so...
34
* 13
====
12
90
40
+300
====
442
I didn't have easy access to a Java development environment, so I wrote the code in C# but the algorithm should be simple enough to convert into Java.
public int Multiply(int x, int y)
{
if (x < 0) throw new ArgumentException("must be positive integer", "x");
if (y < 0) throw new ArgumentException("must be positive integer", "y");
if (x == 0 || y == 0) return 0; // obvious quick-exit condition
// integer division
int xDivBy10 = x / 10;
int yDivBy10 = y / 10;
bool xIsSingleDigit = xDivBy10 == 0;
bool yIsSingleDigit = yDivBy10 == 0;
// base case
if (xIsSingleDigit && yIsSingleDigit)
{
return MultiplySingleDigits(x, y);
}
// otherwise, use grid multiplication recursively
// http://en.wikipedia.org/wiki/Grid_method_multiplication
if (xIsSingleDigit) // y must not be a single digit
{
return (Multiply(x, yDivBy10) * 10) + Multiply(x, y % 10);
}
if (yIsSingleDigit) // x must not be a single digit
{
return (Multiply(xDivBy10, y) * 10) + Multiply(x % 10, y);
}
// else - x and y are both numbers which are not single digits
return (Multiply(x, yDivBy10) * 10) + Multiply(x, y % 10); // the same code as the "if (xIsSingleDigit)" case
}
// technically, this algorith can multiply any positive integers
// but I have restricted it to only single digits as per the assignment's requirements/hint
private int MultiplySingleDigits(int x, int y)
{
if (x < 0 || x > 9) throw new ArgumentException("must be in range 0 - 9 (inclusive)", "x");
if (y < 0 || y > 9) throw new ArgumentException("must be in range 0 - 9 (inclusive)", "y");
if (x == 0 || y == 0) return 0; // base case
return x + MultiplySingleDigits(x, y - 1);
}
NOTES:
This approach still uses the * operator but not for actually multiplying x and y, it is used to increase other sub-products by multiples of 10
Many parts of this code could be simplified/refactored but I specifically left them expanded to make the steps more obvious
Of course you can do it.
First of all, think about the condition. If some number is 0, then the result is? Right.. zero.
So.. You'll have if x is zero or y is zero return 0
Now.. saying X * Y is like saying "X, Y times", which is like writing: X + .... + X (Y times).
So, you'll have something like:
x + multiply(x, y - 1);
You'll have to consider the case in which one of the numbers is negative (But if you understand the basic, I believe you can easily do it).
This solution will work for both when y>=0 and y<0
public int multiply(final int x, final int y) {
if (y != 0 && x != 0) {
if (y > 0) {
return multiply(x, y - 1) + x;
} else {
return multiply(x, y + 1) - x;
}
}
return 0;
}
Easily possible.
int multiply(int x, int y) {
if(y == 0) {
return 0;
}
return x + multiply(x, y - 1);
}
The above fails to take into account the case where y is negative, but you wouldn't want me to do all your work for you . . .
static int Multiply(int x, int y)
{
if (y > 0 && x > 0)
return (x + Multiply(x, y - 1));
if (y < 0 && x > 0)
return -Multiply(x, -y);
if (x < 0 && y > 0)
return -Multiply(-x, y);
if (x < 0 && y < 0)
return Multiply(-x, -y);
return 0;
}
I'm working on a small game which has a graph. The idea is I do an action whilst the target location (designated by upper and lower bounds) has no been met (within 0.5). For example, if I target (7,7), the loop should stop when x and y are (both in this case) between 6.5 and 7.5.
However, having something such as the following condition has presented me with a problem when presented with negative numbers:
while ((X < tarX-0.5 || X > tarX+0.5) && (Y < tarY-0.5 || Y > tarY+0.5))
For example: if I have the target (-7,-7) then the loop will stop when ONE of the x or y values is in the range, not both.
Basically, I had the idea of having four different loops depending on whether x or y was positive. But I'm wondering if there's an easier way? (I did try to use Math.abs() to counteract the negative numbers, which worked but something destined for (-3,-3) could still then stop at (3,3))
loop should stop when x and y are (both in this case) between 6.5 and 7.5.
while (!(x >= 6.5 && x <= 7.5 && y >= 6.5 && y <= 7.5)) {
...
}
Applying De Morgan's Law, the above is equivalent to
while (x < 6.5 || x > 7.5 || y < 6.5 || y > 7.5) {
...
}