Best way to format the conditional checks in "if" statement - c++

This code looks dirty and I can't figure out how to format it so that I can read it, understand it, and look clean at the same time.
if(center==2 && ((((y-height/2)==j) && ((x+width/2)==i)) || (((y+height/2)==j) && ((x+width/2)==i))))
regenerateDot(i+1, j, dots);
Any suggestions?

I would break down the boolean expressions into variables named for readability. Something like:
bool isCentered = center == 2;
bool inLowerRegion = (y-height/2) == j && (x+width/2) == i;
bool inUpperRegion = (y+height/2) == j && (x+width/2) == i;
bool inEitherRegion = inLowerRegion || inUpperRegion;
if (isCentered && inEitherRegion) {
regenerateDot(i+1, j, dots);
}

Consider refactoring. You could put sub expressions into their own functions, thus naming their purpose.
For example:
if (IsCentered(center) && IsInsideLower(y, j, i) && IsInsideUpper(y, j, i))
regenerateDot(i + 1, j, dots);
Note that in the above example the function names might be bogus (I haven't really attempted to understand what the purpose of the code is), but you should get the picture.

Almost all the parenthesis are redundant... and adding some whitespace it becomes:
if(center == 2 &&
(y - height/2 == j && x + width/2 == i ||
y + height/2 == j && x + width/2 == i))
regenerateDot(i+1, j, dots);

For something complicated I'd probably break it down into what each condition (grouped by shared &&) is trying to signify and assign it to a sensible variable name.

At most you can remove extra braces, add some spaces and put the logical partitions in different lines as,
if(center == 2 &&
(((y - height/2) == j || (y + height/2) == j) && (x + width/2) == i))
{
regenerateDot(i+1, j, dots);
}
Edit: You have one redundant condition (x + width/2) == i which I have optimized here.

This is the same as the code you posted:
if( center == 2 )
{
if( (x+width/2) == i )
{
if( (y-height/2) == j ) || (y+height/2) == j ) )
{
regenerateDot(i+1, j, dots);
}
}
}

Re-ordering it would give something like :
if (center==2 && (i-x)==(width/2) && abs(j-y)==(height/2))
regenerateDot(i+1, j, dots);

I would do it like this
if (2 == center &&
(((y - height/2) == j && (x + width/2) == i) ||
((y + height/2) == j && (x + width/2) == i))
)
{
regenerateDot(i + 1, j, dots);
}

Related

How to make a loop to determine if 2 numbers belong in a given range

I am having problems making a loop which stops when both x and y are in the range/interval [0,1] in c++.
double x;
double y;
while(condition)
{
if(x < 0)
{
x = -x;
}
else
{
x = 2 - x;
}
if(y < 0)
{
y = -y;
}
else
{
y = 2 - y;
}
}
This method with 2 loops works:
while((x < 0) || (x > 1)) {do sth}
while((y < 0) || (y > 1)) {do sth}
This doesn't work:
while(!((x >= 0) && (x <= 1)) && !((y >= 0) && (y <= 1))) {do sth}
And this doesn't work either:
while(((x < 0) || (x > 1)) && ((y < 0) || (y > 1))) {do sth}
This makes an infinite loop (in my case):
while(((x < 0) || (x > 1)) || ((y < 0) || (y > 1))) {do sth}
Note: {do sth} changes x and y if needed so they will eventually go in that interval (same as in the first block of code).
Note 2: By doesn't work I mean it never goes in the loop when x is in the interval and y < 0 (and some other cases).
while ( !( (x>=0 && x<=1) && (y>=0 && y<=1) ) ) should be the combined conditional check.
I'd go for a dedicated function with a speaking name: so you can still understand your code in a couple of weeks :-), e.g.
auto check_outside_interval_0_1 = [] (double const a) {
return a < 0.0 or 1.0 < a;
};
while( check_outside_interval_0_1(x) or
check_outside_interval_0_1(y) ) {
// ... do your things here
}

Doing the same thing inside various 'if' statements, can be improved?

I was coding when i faced this problem and i would like to know if this is correct or it can be improved for performance reasons:
if (color == 0) {
if (c.val[0] >= 0 && c.val[0] <= 64) {
//Black
Paint(cursor.x + x, cursor.y + y);
}
}
else if (color == 1) {
if (c.val[0] >= 64 && c.val[0] <= 128) {
//Grey
Paint(cursor.x + x, cursor.y + y);
}
}
else if (color == 2) {
if (c.val[0] >= 128 && c.val[0] <= 192) {
//White Gray
Paint(cursor.x + x, cursor.y + y);
}
}
As you can see im doing the exact same thing inside all IF statements and it looks kind weird, the program works as i want but i really think im missing something..
Thanks!
Because of the structure,
if (color >= 0 && color <= 2) {
if (c.val[0] >= 64*color && c.val[0] <= 64*(color+1)) {
Paint(cursor.x + x, cursor.y + y);
}
}
A few logical operations make it more compact.
if ((color == 0 && c.val[0] >= 0 && c.val[0] <= 64) ||
(color == 1 && c.val[0] >= 64 && c.val[0] <= 128) ||
(color == 2 && c.val[0] >= 128 && c.val[0] <= 192)) {
Paint(cursor.x + x, cursor.y + y);
}
This isn't too terrible with such a short piece of code repeated, but in the interest of Don't Repeat Yourself, and in case more code is needed later, you could simply separate the testing for whether something will be done from the actual doing it, using a flag.
bool need_Paint = false;
if (color == 0) {
// Black?
need_Paint = (c.val[0] >= 0 && c.val[0] <= 64);
}
else if (color == 1) {
// Grey?
need_Paint = (c.val[0] >= 64 && c.val[0] <= 128);
}
else if (color == 2) {
// White Gray?
need_Paint = (c.val[0] >= 128 && c.val[0] <= 192);
}
if (need_Paint)
Paint(cursor.x + x, cursor.y + y);
(Note a compiler's optimizations can possibly handle this sort of thing without actually putting a bool in memory, just jumping to the function call statement if the appropriate condition is true.)
(This also looks like the sort of pattern often written as a switch. You could consider using that syntax instead of all the ifs.)
But in fact this particular code can get even simpler, because there's a straightforward mathematical pattern to the three different tests you're doing:
if (color >= 0 && color <= 2 && // (if these aren't already guaranteed)
c.val[0] >= 64*color && c.val[0] <= 64*(color+1)) {
Paint(cursor.x + x, cursor.y + y);
}
(Another thing to consider might be using enum ColorType { BLACK=0, GREY=1, WHITE_GRAY=2 }; instead of just writing the "magic numbers" 0, 1, and 2 directly. But if you use both an enum and the mathematical version of this code, I'd recommend you specify the exact values as shown, even though the default for an enum is always consecutive counting from zero, to make it clear you're counting on those values.)
I like your original post more than the selection.
Here is a another approach with about the same number of lines ... but I find more readable.
void yourSnippet() {
switch (color) {
case 0: { PaintIf( 0, 64); } break; // black
case 1: { PaintIf( 64, 128); } break; // Grey
case 2: { PaintIf(128, 192); } break; // White Gray
} // switch
}
void PaintIf(int min, int max) {
if ((c.val[0] >= min) && (c.val[0] <= max))
Paint(cursor.x + x, cursor.y + y);
}
Another solution that closely follows the lines of 2785528's answer but uses a lambda to avoid passing additional arguments to PaintIf:
const auto PaintIf = [&](int min, int max)
{
if (min <= c.val[0] && c.val[0] <= max)
Paint(cursor.x + x, cursor.y + y);
};
switch (color)
{
case 0: PaintIf( 0, 64); break;
case 1: PaintIf( 64, 128); break;
case 2: PaintIf(128, 192);
}
Lambdas are (as of c++17) guaranteed to be constexpr (i.e. zero cost abstractions) if possible.
They can sometimes allow more succinct and maintainable expressions of logic:
auto range = [](int color)
{
auto min = color * 64;
auto max = min + 64;
return std::make_tuple(min, max);
};
auto in_range = [](auto val, auto tuple)
{
auto [min, max] = tuple;
return val >= min && val <= max;
};
if (in_range(c.val[0], range(color)))
Paint(cursor.x + x, cursor.y + y);

Is there a better way of selecting a random element from an array of variable size than this?

I'm very new to C++ and was wondering if if there is a better way of doing this. It's going to run on an Arduino so I can't use ArrayLists or anything.
byte GetFreeCell(short x, short y)
{
byte possibleMoves[4] = {0,0,0,0};
if (y - 2 >= 0 && _grid[y - 2][x] == 0)
possibleMoves[0] = 1;
if (x + 2 < WIDTH && _grid[y][x + 2] == 0)
possibleMoves[1] = 2;
if (y + 2 < HEIGHT && _grid[y + 2][x] == 0)
possibleMoves[2] = 3;
if (x - 2 >= 0 && _grid[y][x - 2] == 0)
possibleMoves[3] = 4;
if (possibleMoves[0] == 0 && possibleMoves[1] == 0 && possibleMoves[2] == 0 && possibleMoves[3] == 0) {
return 0;
}
byte move = 0;
while(move == 0){
move = possibleMoves[random(4)];
}
return move;
}
Thanks,
Joe
byte GetFreeCell(short x, short y)
{
byte possibleMoves[4];
byte index = 0;
if (y - 2 >= 0 && _grid[y - 2][x] == 0)
possibleMoves[index++] = 1;
if (x + 2 < WIDTH && _grid[y][x + 2] == 0)
possibleMoves[index++] = 2;
if (y + 2 < HEIGHT && _grid[y + 2][x] == 0)
possibleMoves[index++] = 3;
if (x - 2 >= 0 && _grid[y][x - 2] == 0)
possibleMoves[index++] = 4;
return index ? possibleMoves[random(index)] : 0;
}
You can do yourself a favor and use this:
https://github.com/maniacbug/StandardCplusplus/#readme
Then you can sanitize your code by using standard containers.
Also, there's no ArrayList in C++. That's Java. With the above library, you can use std::vector instead.

How to reduce logic expressions?

{
ans += (a[i] > a[j]) != (b[i] > b[j]);
//ans += ((a[i] > a[j]) && (b[j] > b[i])) || ((a[j] > a[i]) && (b[i] > b[j]));
}
What you see above is a snippet I took from some where. There are two logic expressions. Supposedly, the one commented out is the same as the one not commented out.
How do you get from:
((a[i] > a[j]) && (b[j] > b[i])) || ((a[j] > a[i]) && (b[i] > b[j]))
to something like this
(a[i] > a[j]) != (b[i] > b[j])
Are there any guides or books for these kind of logic expression simplifications?
This is actually very simple.
With (a[i] > a[j]) != (b[i] > b[j]), what we're saying is that this will only be true when the relationship to a[i] and a[j] is the opposite of the relationship from b[i] to b[j]. For this to hold then, if a[i]>a[j] is true, then b[i]>b[j] is false, which means that b[j]>b[i] is true. This means that when a[i]>a[j] is true, b[j]>b[i] is true, and it also means the inverse - when a[j]>a[i] is true, then b[i]>a[j] as well.
Another way of saying all of that is ( (a[i]>a[j]) && (b[j]>a[i]) ) || ( (a[j]>a[i]) && (b[i]>b[j]) . That boolean logic will be true only in the same cases where ( (a[i] > a[j]) ) != (b[i] > b[j]) is true.
As another example, consider when both a[i] > a[j] and b[i] > a[j] . You'll see that the first you posted is false in this condition, because the two terms on either side of the != evaluate to true, meaning the != evaluates to false. This case also causes the second statement to resolve to false because you don't have either of the two terms around the || evaluating to true, they both evaluate to false.
Lastly, this question looks like homework to me - if it is you should use the appropriate tag.
However, this all ignores the possibilities of a[i] == a[j] or b[i] == b[j], which another answer to this question demonstrates can cause the two statements to not evaluate to the same thing. But if you assume that the two cannot be equal, then the two statements from your question will be the same, following the logic demonstrated above.
The code you posted is right if you assume that
!(p > q) == (p < q)
Meaning that for some reason, you're ignoring equality.
With this in mind, let's say that:
a1 = a[i]
a2 = a[j]
b1 = b[i]
b2 = b[j]
Then you have:
ans += ((a1 > a2) && (b2 > b1)) || ((a2 > a1) && (b1 > b2));
Which, since we're ignoring equality, is the same as:
ans += ((a1 > a2) && !(b1 > b2)) || (!(a1 > a2) && (b1 > b2));
If you take a closer look, you'll see that the expressions are repeated, so they can be simplified:
A = a1 > a2
B = b1 > b2
Then:
ans += (A && !B) || (!A && B);
Which means either A or B, but no both
This is a known boolean operation called XOR, which in your case is the same as different (!=)
Therefore:
ans += A != B;
And expanding:
ans += (a1 > a2) != (b1 > b2)
So:
ans += (a[i] > a[j]) != (b[i] > b[j])
Hope it's clear now.
These expressions are not equivalent.
For example, when a[i] == a[j] and b[i] > b[j], the first expression gives...
(a[i] > a[j]) != (b[i] > b[j]);
false != true
true
...while the second one gives:
((a[i] > a[j]) && (b[j] > b[i])) || ((a[j] > a[i]) && (b[i] > b[j]));
(false && false) || (false && true)
false || false
false
Let's take this:
((a[i] > a[j]) && (b[j] > b[i])) || ((a[j] > a[i]) && (b[i] > b[j]))
and call it this, for simplicity:
(w > x) && (y > z) || (x > w) && (z > y)
which is NOT logically equivalent to:
(w > x) && (y > z) || !(w > x) && !(y > z)
because they could be equal, but it is to:
(w > x) && (y > z) || !(w >= x) && !(y >= z)
So you could simplify it to (w > x) == (y > z) or, alternatively, to (w > x) != (z >= y).

What is wrong with my logic?

if(location[0] <= 'H' || location[0] >= 'A'
&& location[1] <= 8 || location[1] >= 1)
I am checking to see if the first indice is between 'A' and 'H' and the second indice is between 1 - 8.
so the argument would = 1 if the user entered { A, 1 }
-1 if the user entered { J, 1 }
And (&&) has higher precedence than or (||), so to express what you want you need:
if ((location[0] <= 'H' || location[0] >= 'A') && (location[1] <= 8 || location[1] >= 1))
Otherwise what's happening is that it does the equivalent of this:
if (location[0] <= 'H' || (location[0] >= 'A' && location[1] <= 8) || location[1] >= 1)
Which is clearly not what you intended.
You can put as many expressions in the condition as you want, but you must remember the precedence rules; I suggest always using extra parentheses for clarity.
As Jeremiah has pointed out in the comments, the condition still wouldn't be doing what you wanted -- you are asking if something is in a given range by checking if it's either less than the upper bound or greater than the lower bound (this covers all input), when you intended to check whether the input was both larger than the lower bound and smaller than the upper:
if (location[0] <= 'H' && location[0] >= 'A' && location[1] <= 8 && location[1] >= 1)
In this case, since the operators are all &&, no extra parentheses are needed, though you can add them for extra clarity.
You need &&s not ||s. For example: 'Z' >= 'A' || 'Z' <= 'H' is true.
if(location[0] <= 'H' && location[0] >= 'A' && location[1] <= 8 && location[1] >= 1)
While not necessary in this case, you should group your logic together with parenthesis (and if they were ||s you would have to for it to work as expected):
if((location[0] <= 'H' && location[0] >= 'A') && (location[1] <= 8 && location[1] >= 1))
Add parenthesis to group the conditions:
if( (location[0] <= 'H' || location[0] >= 'A') && (location[1] <= 8 || location[1] >= 1))
If location[0] was equal to 'J' (definitely NOT between 'A' and 'H'), your if-clause would be TRUE because even though location[0] <= 'H' is FALSE, location[0] >= 'A' is TRUE and you are using || (OR). The problem is that you are using || (OR) instead of && (AND). You need to use all && (AND) in the if-clause.
&& has higher precedence than ||. So, you may want to write it as
if((location[0] <= 'H' || location[0] >= 'A') && (location[1] <= 8 || location[1] >= 1))
If you already tried this, please tell what error you got
Sorry guys, new here. I should have posted my entire method. Thank you for explaining the precedence of the operators, but my issue was that I was comparing a char with an int. All I needed to do was put ' ' around my numbers.
void GameBoard::enterShips()
{
char location[2];
int ships = 0;
int count = 1;
while( ships < NUM_SHIPS )
{
cout << "Enter a location for Ship " << count << ": ";
cin >> location[0];
cin >> location[1];
cout << endl;
if((location[0] <= 'H' && location[0] >= 'A') && (location[1] <= '8' && location[1] >= '1'))
{
location[0] = location[0] - 64;
location[1]--;
Grid[location[0]][location[1]] = SHIP;
ships++;
count++;
}
else
{
cout << "Wrong coordinates entered. Try again." << endl << endl;
}
}
}
As you can see in this operator precedence table, && is #13. It's higher up than ||, which is #14.
Therefore:
if(location[0] <= 'H' || location[0] >= 'A'
&& location[1] <= 8 || location[1] >= 1)
Is equivalent to:
if(location[0] <= 'H' || (location[0] >= 'A'
&& location[1] <= 8) || location[1] >= 1)
You want:
if((location[0] <= 'H' || location[0] >= 'A') &&
(location[1] <= 8 || location[1] >= 1))
Or even better:
if(((location[0] <= 'H') || (location[0] >= 'A')) &&
((location[1] <= 8) || (location[1] >= 1)))
I always put brackets around everything except when */ and +- are concerned. Even if you memorize the table, you shouldn't assume others do.
It helps code readability and helps prevent bugs... even compiler bugs! Triple bonus. :)
EDIT: Ah, you want ALL of them to be true. Just use all &&s, then! This works:
if(((location[0] <= 'H') && (location[0] >= 'A')) &&
((location[1] <= 8) && (location[1] >= 1)))