Simplifying an if-statment - java

I have a program with a few if-statements similar to the one I'm about to present to you. I was wondering if you guys could help me simplify this equation in any way. The reason why I ask is because in my Notepad++, it continues on for 443 columns and it's just really frustrating to edit if needed, and just keeps getting longer as I keep adding variables. Basically, for this example of one of my many similar if statements, I just want to do an action when ANY of my SliderBars try to raise in value when an int (rpg.StatisticPoints) is equal to, or less then 0. The method I'm using to find out if the sliders are rising in value is to just compare its current value to an int associated with the slider, and check if the result is positive.
if (rpg.StatisticPoints <= 0 &&
((rpg.WillSlider.getValue() - rpg.Will) < 0) &&
((rpg.PerceptionSlider.getValue() - rpg.Perception) < 0) &&
((rpg.StrengthSlider.getValue() - rpg.Strength) < 0) &&
((rpg.DexteritySlider.getValue() - rpg.Dexterity) < 0) &&
((rpg.ConstitutionSlider.getValue() - rpg.Constitution) < 0) &&
((rpg.CharismaSlider.getValue() - rpg.Charisma) < 0) &&
((rpg.IntelligenceSlider.getValue() - rpg.Intelligence) < 0))
{
//Do actions
}
I understand there are a lot of variables here you're not familiar with because you didn't see my full code, but my full source is 100's of lines long and my question is just based on logistics, and not really issues with the syntax.

The problem with your current solution isn't just a long line, is that it's hard for someone to read and understand what is actually being validated.
Instead of using all the conditions in an if statement, you can create an auxiliary method that build the boolean value of that validation, and at the same time give it a meaningful name.
For instance:
private boolean isValidSomething(){
boolean result = firstCondition;
result &= secondCondition;
...
return result;
}
This way all your checks will be concentrated in one place, AND it will be a lot more readable, since your if will become:
if(isValidSomething()) {...}
Of course, create the method with a name that makes sense in your application.
In case you're validating several different conditions that make sense to be separated, go the extra mile and factor them out in to their own methods.
The main thing is to break that logic into pieces that make sense together, like:
private boolean validStatistics() {
return statistics > 0;
}
private boolean validWill() {
return will > 0;
}
....
And your main validation would be something like:
private boolean validCharacter() {
boolean valid = validStatistics();
valid &= validWill();
...
return valid;
}

What about
if (rpg.StatisticPoints <= 0 &&
(rpg.WillSlider.getValue() < rpg.Will) &&
(rpg.PerceptionSlider.getValue() < rpg.Perception) &&
(rpg.StrengthSlider.getValue() < rpg.Strength) &&
(rpg.DexteritySlider.getValue() < rpg.Dexterity) &&
(rpg.ConstitutionSlider.getValue() < rpg.Constitution) &&
(rpg.CharismaSlider.getValue() < rpg.Charisma) &&
(rpg.IntelligenceSlider.getValue() < rpg.Intelligence))
{
//Do actions
}
Furthermore, you could move some code to a seperate function:
bool CheckSliderValue(TypeOfSlider slider, TypeOfSliderValue value)
{
return slider.getValue() < value;
}
and call this by CheckSliderValue(rpg.WillSlider, rpg.Will) a.s.o. Such you could extent the check with a minimum value or easily change "<" to "<=" or alike.

You can create new variables like:
int will = rpg.WillSlider.getValue() - rpg.Will;
Then your test will be shorter:
if ( ( rpg.StatisticPoints <= 0 ) && ( will < 0 ) && ( Perception < 0 ) ... ) {}
Also you can separate test to the new lines:
if ( ( rpg.StatisticPoints <= 0 )
&& ( will < 0 )
&& ( perception < 0 ) ... ) {}

if (rpg.StatisticPoints <= 0
&& ((rpg.WillSlider.getValue() - rpg.Will) < 0)
&& ((rpg.PerceptionSlider.getValue() - rpg.Perception) < 0)
&& ((rpg.StrengthSlider.getValue() - rpg.Strength) < 0)
&& ((rpg.DexteritySlider.getValue() - rpg.Dexterity) < 0)
&& ((rpg.ConstitutionSlider.getValue() - rpg.Constitution) < 0)
&& ((rpg.CharismaSlider.getValue() - rpg.Charisma) < 0)
&& ((rpg.IntelligenceSlider.getValue() - rpg.Intelligence) < 0)){
//Do actions
}

You can remove most of the ()s:
rpg.StatisticPoints <= 0 &&
rpg.WillSlider.getValue() - rpg.Will < 0 &&
rpg.PerceptionSlider.getValue() - rpg.Perception < 0 &&
rpg.StrengthSlider.getValue() - rpg.Strength < 0 &&
rpg.DexteritySlider.getValue() - rpg.Dexterity < 0 &&
rpg.ConstitutionSlider.getValue() - rpg.Constitution < 0 &&
rpg.CharismaSlider.getValue() - rpg.Charisma < 0 &&
rpg.IntelligenceSlider.getValue() - rpg.Intelligence < 0
Edit
See the Java Tutorial about Operator Precendce.

boolean state= (rpg.StatisticPoints <= 0 && ((rpg.WillSlider.getValue() - rpg.Will) < 0) && ((rpg.PerceptionSlider.getValue() - rpg.Perception) < 0) && ((rpg.StrengthSlider.getValue() - rpg.Strength) < 0) && ((rpg.DexteritySlider.getValue() - rpg.Dexterity) < 0) && ((rpg.ConstitutionSlider.getValue() - rpg.Constitution) < 0) && ((rpg.CharismaSlider.getValue() - rpg.Charisma) < 0) && ((rpg.IntelligenceSlider.getValue() - rpg.Intelligence) < 0));
if(state){/*do actions*/}
or
s1=(rpg.StatisticPoints <= 0);
s2=((rpg.WillSlider.getValue() - rpg.Will) < 0);
...
...
if(s1&&s2&&s3...){/* work*/}

In your case you need more than just "inlining" the conditions.
Somewhere, usual programming isn't the right thing to do in your case.
Maybe you could use the Observer pattern. If you structure well your classes and add a signal that will raise a flag. For exemple : One of the condition is false.
This will be brought back to your main conditions which will check if one flag is ever raised by the Observer pattern.
Check about the Observer pattern. If your project is going to be huge, I think this could help a lot.
If you only add one variable, then you will only need to write the condition for the new one in a very simple way.

Related

Avoid a lot of conditions inside an If Statement

I have an if statement like this
if(areEqual(a,ax) && areEqual(b,bx) && areEqual(c,cx) && areEqual(d,dx) && areEqual(e,ex) && areEqual(f,fx) && areEqual(g,gx) && areEqual(h,hx) && areEqual(i,ix) && areEqual(j,jx) && areEqual(k,kx)
This if the statement includes lots of conditions and it is not readable. How can I avoid this situation? Is there any pipeline pattern for if conditions?
Assuming you are using Python, you can store all check in a list(say list1) and check
if sum(list1)==len(list1):
do something
In javascript, if you add true and true together you get 2. Using this information you could put all the conditions in an array and get the sum of it.
var conditions = [condition1, condition2, ... ]; -- all conditions go here
var sum = 0; -- works out the sum
for (var i = 0; i < conditions.length; i++) {
sum += conditions[i];
}
if (sum === conditions.length) {
console.log("success")
}

How to stop Java recursion in Finding Peak inside 2D Array

so I've been trying to perfect this method for a good amount of time now but I cannot make it work. What I'm trying to do is find a peak number in a 2D array of different integers using recursion only in Java.
Basically what my method does it check if the indexes are inside the array and if the numbers above,below,left and right to it are bigger than the current number.
If they are, the recursion prints the current point and continues. However, with the code I have written, the method finds the first path and then for some reason goes back and finds a different path which generates problems, I want only one path to be printed and then the method needs to stop.
I have tried putting a boolean to check if there is a peak and then return true but it still goes back and prints the other paths. If you guys could help me, it would be amazing.
This is the code:
private static void printPath (int[][] mat, int i, int j) {
System.out.println("("+i+","+j+")");
if (i >=0 && i < mat.length-1 && mat[i][j] < mat[i+1][j]){
printPath(mat,i+1,j);
}
if (j >=0 && j < mat[0].length-1 && mat[i][j] < mat[i][j+1]){
printPath(mat,i,j+1);
}
if (i>0 && i < mat.length-1 && mat[i][j] < mat[i-1][j]){
printPath(mat,i-1,j);
}
if (j>0 && j < mat[0].length-1 && mat[i][j] < mat[i][j-1]){
printPath(mat,i,j-1);
}
}
Why don't you change the whole algorithm?
Flatten the matrix into a 1D array of m*n size by appending m arrays of n items one after another.
Use simple max algorithm to find the index of the peak in the flattened array.
Convert the index in the flattened array to the point in original matrix:
i = index / m
j = index % m
EDIT
Try putting else keywords between those ifs:
private static void printPath (int[][] mat, int i, int j) {
System.out.println("("+i+","+j+")");
if (i >=0 && i < mat.length-1 && mat[i][j] < mat[i+1][j]){
printPath(mat,i+1,j);
} else if (j >=0 && j < mat[0].length-1 && mat[i][j] < mat[i][j+1]){
printPath(mat,i,j+1);
} else if (i>0 && i < mat.length-1 && mat[i][j] < mat[i-1][j]){
printPath(mat,i-1,j);
} else if (j>0 && j < mat[0].length-1 && mat[i][j] < mat[i][j-1]){
printPath(mat,i,j-1);
}
}
But I am still not sure of the algorithm - this will be able to find a local peak, but not global - imagine there is an item that has all the neighbours lower than itself, but somewhere else in the matrix there might be even bigger number. Your alogrithm will stop at this item, even though it is not the biggest one of all.
If you are looking for any one of the possible paths and not the path that has the largest values, I have a simple solution.
Just make the remaining if statements as else if statements. You enforce the program to only follow one path in each call of your recursive function
The reason it "goes back" is that you have potentially 4 branches on each recursion call. Let's consider an example:
First condition is true so the first path begins
At some point there is no condition fulfilled and the path ends
Program returns to last frame (info) and executes the code from where it ended <- this causes your problem
So when the first execution is complete it starts its way back to the start with the possibility to branch again. To fix this you would have to join your condition to one statement so only one recursive call can be fired from your function.
If the branching you have in your function now is desired (I didn't quite get it from the description) you would have to pass additional boolean method parameter indicating if the further search is needed. You will have to check the endConditon somehow in your method and pass the value accordingly. Of course add this to your method:
if (endCondition) return;
Well... I do not recomend you to just use else statements in this case, because with this you will only show the very first high path found. I've rewrited your code to find the highest matrix path. Obviously, it became more complex, but you can assure that the highest path will be found.
private static void printPath (int[][] mat, int i, int j) {
if (mat.length == 0 || mat[0].length == 0) {
System.out.println("Empty matrix");
return;
}
System.out.println("("+i+","+j+")");
int rightValue = i >=0 && i < mat.length-1 && mat[i][j] < mat[i+1][j] ? mat[i+1][j] : mat[i][j];
int belowValue = j >=0 && j < mat[0].length-1 && mat[i][j] < mat[i][j+1] ? mat[i][j+1] : mat[i][j];
int aboveValue = i>0 && i < mat.length-1 && mat[i][j] < mat[i-1][j] ? mat[i-1][j] : mat[i][j];
int leftValue = j>0 && j < mat[0].length-1 && mat[i][j] < mat[i][j-1] ? mat[i][j-1] : mat[i][j];
// now you need to iterate over the four values to check wich one is the highest value
// this way, you will get the highest path...
if (rightValue > leftValue) {
if (rightValue > belowValue) {
if (rightValue > aboveValue) {
printPath(mat,i+1,j);
} else {
printPath(mat,i,j+1);
}
} else {
if (belowValue > aboveValue) {
printPath(mat,i-1,j);
} else {
printPath(mat,i,j+1);
}
}
} else {
if (leftValue > belowValue) {
if (leftValue > aboveValue) {
printPath(mat,i-1,j);
} else {
printPath(mat,i,j+1);
}
} else {
if (belowValue > aboveValue) {
printPath(mat,i-1,j);
} else {
printPath(mat,i,j+1);
}
}
}
}
If you need to find the path that contains the highest values, this will give you the correct output. Hope it helps.

Struggling With Btree Algorithm

I've tried using Java to implement algorithms from the textbook Introduction to Algorithms, 3rd edition, without a lot of success. Almost every time I try to implement them I encounter a multitude of errors, to the point where I'm not sure if the authors themselves have tried implementing their own pseudocode. But specifically, in this case, I'm having problems with the Btree algorithm. I think the problem lies somewhere in the B-Tree-Insert-Nonfull method. When I try to run the program, this line causes a Null Pointer Exception:
int i = x.totalKeys - 1;
However, that doesn't make any sense. All Nodes, like x in this case, are initialized with a value of 0 in their constructors, so how is his error even occurring? I'm going to enclose the function below:
public void bTreeInsertNonfull(Node x, Integer k)
{
int i = x.totalKeys - 1;
if (x.leaf || (x.children[i] == null))
{
while( (i >= 0) && (k < x.keys[i]) )
{
x.keys[i+1] = x.keys[i];
i = i - 1;
}
x.keys[i+1] = k;
x.totalKeys = x.totalKeys + 1;
}
else
{
while ( (i >= 0) && x.keys[i] != null)
{
if (k < x.keys[i])
{
i = i - 1;
}
}
i = i + 1;
if ((x.children[i] != null) && (x.children[i].totalKeys == tUpper))
{
bTreeSplitChild( x, i, x.children[i] );
if (k > x.keys[i])
{
i = i + 1;
}
}
bTreeInsertNonfull(x.children[i], k);
}
}
Elaborating on the idea from Alex: if you look at the last part of the algorithm, there is a line that says:
if ((x.children[i] != null) && (x.children[i].totalKeys == tUpper))
That hints that x.children[i] == null is a possibility. The last line of the algorithm calls bTreeInsertNonfull(x.children[i], k); without checking if the first parameter is null.

Why isn't my if-else block ever getting hit, even though it should be? (Just need another pair of eyes.)

I am making a Falling Sand style game in Java, and I'm having weird issues with an if-else block that I have. In my doGravity() method, I have an various blocks of conditions that will cause different things to happen, and for some odd reason, one block is NEVER getting hit.
When I have this block count how many times each condition is hit, the left and right blocks are hit almost evenly:
else if(world[x][y+1]==EMPTY && (x-1 >= 0) && world[x-1][y+1] == EMPTY && (x+1 < world.length) && world[x+1][y+1]==EMPTY) {
int r = rand.nextInt(50);
if(r == 0) {
world[x-1][y+1] = world[x][y];
//System.out.println("GO: right");
countRight++;
}
else if(r == 1) {
world[x+1][y+1] = world[x][y];
//System.out.println("GO: left");
countLeft++;
}
else {
world[x][y+1] = world[x][y];
countCenter++;
}
world[x][y] = EMPTY;
}
Next comes this condition, which also equally distributes left and right.
else if((x-1 >= 0) && world[x-1][y+1] == EMPTY && (x+1 < world.length) && world[x+1][y+1]==EMPTY) {
if(rand.nextBoolean()) {
world[x-1][y+1] = world[x][y];
//countLeft++;
}
else {
world[x+1][y+1] = world[x][y];
//countRight++;
}
world[x][y] = EMPTY;
}
But when I count these blocks, the left block NEVER gets hit, even when the space to the left is open. I feel like its probably just some stupid typo that I can't see for some reason.
else if((x-1 >= 0) && world[x-1][y+1] == EMPTY) {
world[x-1][y+1] = world[x][y];
world[x][y] = EMPTY;
countLeft++;
System.out.println("Hit Left");
}
else if((x+1 < world.length) && world[x+1][y+1] == EMPTY) {
world[x+1][y+1] = world[x][y];
world[x][y] = EMPTY;
countRight++;
System.out.println("Hit Right");
}
UPDATE: If I remark out the left block at the end, absolutely nothing changes. The sand acts exactly the same. If I remark out the right block at the end, it acts the same as if I remark out both blocks. I cannot figure this out. It should work... but it doesn't.
UPDATE: Here's the full source code. I have no idea what this could possibly be. It will, in fact, drive me insane. http://pastebin.com/mXCbCvmb
Your pastebin code does show "Hit left", you just need to change the creation of world (line 65 pastebin) to
world = new Color[worldWidth][worldHeight+1];
Because of the y+1 part i would suppose. Other than that it grows both to the left and to the right.
EDIT: http://pastebin.com/GVmSzN4z I twiddled a little with your doGravity to make the drops a little more symmetric.
I dont see anything strange in the posted code... however the "else" at the beginning of the second block makes me think that probably the above condition is being executed in cases that insted you would like to be handled by the "left" case.
What is the condition in the if before that part?
EDIT
After checking your full source code I finally found where the problem is. Your doGravity update function always goes left->right and this introduces the asymmetry. By changing it so that the update direction is alternating between left->right and right->left for odd/even scanlines the asymmetry disappears.
private void doGravity() {
for(int i = worldHeight - 1; i >= 0; i--) {
if (i % 2 == 0)
{
for(int j = 0; j < worldWidth; j++) {
if(world[j][i] != EMPTY) {
if(hasGravity(world[j][i])) {
dropParticle(j, i);
}
}
}
}
else
{
for(int j = worldWidth-1; j >= 0; --j) {
if(world[j][i] != EMPTY) {
if(hasGravity(world[j][i])) {
dropParticle(j, i);
}
}
}
}
}
}
I downloaded your code from paste bin the first thing I did was extract this method and use it instead of all the embedded array cell checking so I could set a break point and see what the values for x and y and what the contents of that indexed cell was.
private boolean isEmpty(final int x, final int y)
{
return world[x][y] == EMPTY;
}
I would extract all the EMPTY checks to something more readable, such as isLeftEmpty(x,y) and isRightEmpty(x,y) and isNextLeftEmpty(x,y) it will help you reason about the correctness of your logic in your code.
I would also extract the (x + 1 < world.length) to isNextXOutsideWorld(x), this will help document your intentions and help with reasoning about the logic you intend as well.
This also has a side effect of simplifying the logic in the if/elseif/else statements.
I did some brief debugging and I let it run for a few minutes and came to the conclusion that the following line matches always and supersedes the next else if statement.
else if ((x + 1 < world.length) && isEmpty(x + 1, y + 1) &&
(x - 1 >= 0) && isEmpty(x - 1,y + 1))
is always true when I run it, so it never reaches the next statement
else if ((x - 1 >= 0) && isEmpty(x - 1,y + 1))
I would try and break each of the else/if statements out to method calls with descriptive names and just all them all in order using a Strategy pattern since they are all mutually exclusive. That large of a method is definitely a code smell, compounded with all those else/if blocks, the stinky factor is high.
It is very hard to extrapolate what your intended behavior is from all the noise in the if/elseif/else blocks.

When there is two for() loop, the second one doesn't work

Here are my for() loops :
public void showMovementCase(){
int movePlusAttack = moveAllowed+attackDistance;
int twiceMoveAllowed = (moveAllowed)*2;
for(int i = 0; i <= movePlusAttack*2; i++){
for(int j = 0; j <= movePlusAttack*2;j++){
boolean a = movePlusAttack <= j+i && movePlusAttack >= j-i && i <= movePlusAttack;
boolean b = movePlusAttack <= j+i && movePlusAttack >= i-j && i > movePlusAttack && j <= movePlusAttack;
boolean c = movePlusAttack*3 >= j+i && movePlusAttack >= j-i && i > movePlusAttack && j >= movePlusAttack;
if(a || b || c){
try{
actionSquare[i][j] = new JLabel();
actionSquare[i][j].setIcon(redsquare);
actionSquare[i][j].setBounds(sprite.getX()+(i-movePlusAttack)*16,sprite.getY()+(j-movePlusAttack)*16, 16, 16);
panel.add(actionSquare[i][j], new Integer(1));
}
catch(ArrayIndexOutOfBoundsException e){System.out.println("red :" + e);}
}
}
}
for(int x = 0; x <= twiceMoveAllowed; x++){
for(int y = 0; y <= twiceMoveAllowed;y++){
boolean a = moveAllowed <= y+x && moveAllowed >= y-x && x <= moveAllowed;
boolean b = moveAllowed <= y+x && moveAllowed >= x-y && x > moveAllowed && y <= moveAllowed;
boolean c = moveAllowed*3 >= y+x && moveAllowed >= y-x && x > moveAllowed && y >= moveAllowed;
if(a || b || c){
try{
actionSquare[x][y].setIcon(bluesquare);
System.out.println("Coucou !");
actionSquare[x][y].addMouseListener(mouse);
panel.repaint();
panel.revalidate();
}
catch(ArrayIndexOutOfBoundsException e){System.out.println("blue :" + e); }
}
}
}
}
if this.attackDistance is different of 0, then the second loop doesn't work (it seems to stop at the .setIcon() command).
Do you know a way to fix this ?
Thanks for reading.
Edit:
with :
try{
actionSquare[x][y].setIcon(bluesquare);
System.out.println("Coucou !");
[...]
}
On the second loop, nothing is printed.
but with :
try{
System.out.println("Coucou !");
actionSquare[x][y].setIcon(bluesquare);
[...]
}
"Coucou !" is printed once.
That's why I said that "it seems to stop at the .setIcon() command" I should have said that sooner, sorry.
Here are a few tips:
don't catch exceptions and do nothing with them. That's what you are doing here in both loops, and so it's normal you don't see the error message.
anytime you see long statements like you have, it should be a hint that you could refactor it. For example, create a separate method that validates whether or not you're going to do something in your loop, and then inside the main method you'd call it like if(shouldPerformAction())
consider using less than 8 spaces for indentation. This just eats up your screen real estate.
consider making computations before the loops instead of inside the loop conditions, if the computation is supposed to be fixed (for example this.moveAllowed*2)
imho, no point in prefixing all your methods/fields with this, it just clutters everything. Just call the methods directly.
This is a very, very bad idea:
catch(ArrayIndexOutOfBoundsException e){}
You effectively tell the JVM to ignore any problems with your arrays that it detects. And worse than that: you don't even print anything when that happens.
Put at least a e.printStackTrace() in there to see if a problem occurs and where.
And as a further step: fix your array access to not exceed any limits. Catching an ArrayIndexOutOfBoundsException is a terribly bad idea. Avoid having it thrown at all!
Hmmm... where to begin...
I would first suggest putting something (System.err.println(...)?) inside of your catch blocks. Or just commenting them out entirely so you'd see the full stacktrace. What if you're hitting an exception and just not seeing it?
catch(ArrayIndexOutOfBoundsException e){}
This is a bad practice for two reasons:
You should never catch RuntimeException. It is just a very helpful indicator for errors in code logic (i.e. developer errors) which ought be solved by writing good code.
You should never ignore e unless you know perfectly what you're doing. Add at least an e.printStackTrace() so that you at least know that something failed.
I cleaned up your code for you. Generally, when you have two sections of code that are supposed to be doing the exact same thing, but are not, then rolling them into one method can eliminate that possibility.public void showMovementCase(){
// probably want to remove anything left over from the last invocation
panel.removeAll();
for (JLabel[] array : actionSquare) Arrays.fill(array, null);
colorSquares(moveAllowed + attackDistance, redsquare, null);
colorSquares(moveAllowed * 2, bluesquare, mouse);
for (int x = 0; x < actionSquare.length; x++)
for (int y = 0; y < actionSquare[x].length; y++)
if (actionSquare[x][y] != null) panel.add(actionSquare[x][y], 1);
}
private void colorSquares(int move, Icon color, MouseListener mouse) {
int xMax = Math.min(2 * move, actionSquare.length);
int yMax = Math.min(2 * move, actionSquare[0].length);
for (int x = 0; x < xMax; x++) {
for (int y = 0; y < yMax; y++) {
if (isLegal(x, y, move)) {
if (actionSquare[x][y] == null)
actionSquare[x][y] = new JLabel();
actionSquare[x][y].setIcon(color);
actionSquare[x][y].setBounds(
sprite.getX() + (x - move) * 16,
sprite.getY() + (y - move) * 16, 16, 16 );
if (mouse != null) actionSquare[x][y].addMouseListener(mouse);
}
}
}
}
private static boolean isLegal(int x, int y, int move) {
// informative comment explaining why this mess makes sense
if (move <= y+x && move >= y-x && x <= move) return true;
// informative comment explaining why this mess makes sense
if (move <= y+x && move >= x-y && x > move && y <= move) return true;
// informative comment explaining why this mess makes sense
if (move * 3 >= y+x && move >= y-x && x > move && y >= move) return true;
return false;
}

Categories

Resources