Multiple conditions in if statement - c++

No matter what number is generated here I always get the first option (penguins). I can't seem to see any problem with my code, anyone else see what's wrong?
{
srand(time(0));
prand = (rand() % 20);
if (prand == 1,5,9,10,14,15,19,20){
entity = "penguins";
srand(time(0));
pquantity = (rand() % 8) + 2;
}
else if (prand == 2,6,11,16,18){
entity = "troll";
pquantity = 1;
}
else if (prand == 3,7,12,17){
entity = "goblin";
pquantity = 1;
}
else if (prand == 4,8,13){
entity = "wizard";
pquantity = 1;
}
}

The code fragment prand == 1,5,9,10,14,15,19,20 is a sequence of expressions (the , is usually know as the comma operator), where the result of the first (or last — depending on language) expression only is used as a condition for the if statement. The remaining expressions are evaluated and their value is forgotten (please note this may lead to serious side effects in more complex situations.)
It's not very clear what language you are using, but in, say, C# you could use a switch statement to achieve what you want:
switch (prand)
{
// first set of options
case 1:
case 5:
…
case 20:
// your code here
break;
// second set of options
case 2:
case 6:
…
case 18:
// your code here
break;
default:
// all other options not listed above
break;
}
Most languages have such a statement. See this wikipedia article for a general description.

You're misusing the comma operator. The expression in the first
if is:
if ( (prand == 1), (5), (9), (10), (14), (15), (19), (20) )
with each of the commas a comma operator. The definition of
a comma operator is to evaluate the first expression (for
possible side effects), then evaluate the second; the value of
the expression is the value of the second expression. So your
if becomes the exact equivalent of:
if ( 20 )
And 20 is implicitly converted to a bool, resulting in
true.
Your compiler should have warned you about this. Something to
the effect of a useless expression.

if (prand == 1,5,9,10,14,15,19,20)
Although this is valid C++ and will compile, it does not do what you expect. You need to compare the variable to each value in turn:
if (prand == 1 || prand == 5 || prand == 9 || prand == 10 || prand == 14 || prand == 15 || prand == 19 || prand == 20)
This is because == is a binary operator which takes two values of compatible types.
In this situation, a switch...case statement is preferred as #Ondrej has explained.
I can think of at least two alternative ways to simulating a dice roll (which it appears you are trying to do:
Use consecutive values for each option:
if (prand >= 1 && prand <= 8) {
// ...
} else if (prand >= 9 && prand <= 13) {
// ...
} else if (prand >= 14 && prand <= 17) {
// ...
} else if (prand >= 18 && prand <= 20) {
// ...
} else {
// Print an error message
}
Store the different possibilities in a std::list<std::set<int>>. Then you can iterate over the sets in the list and use the std::set.contains() method to check if the current set contains the value. This has the advantage of scalability. For example, it makes it easier to code the choices for 1d100 or other dice rolls with a large number of possible values.

If it is "C" then You are testing the result of a comma operator. So the result of prand == 1,5,9,10,14,15,19,20, is the last element (BTW the first element is prand == 1). It is 20 which is always true.
I would suggest to build an array and check its elements...
enum Being_t {BEING_PENGUIN, BEING_TROLL, BEING_GOBLIN, BEING_WIZARD};
enum Being_t arr[20] = {BEING_PENGUIN, BEING_TROLL, BEING_GOBLIN, BEING_WIZARD,
BEING_PENGUIN, BEING_TROLL, BEING_GOBLIN, BEING_WIZARD, ...};
Then You can use a switch
srand(time(0));
prand = (rand() % 20);
switch (arr[prand]) {
case BEING_PENGUIN:
...
break;
...
}

You should use or's or switch statements. For example, with if
if (prand == 1 || prand == 5 || prand == 9 || prand == 10 || prand == 14|| prand == 15|| prand == 19|| prand == 20)
{
// your code here
}
and with switch
switch (prand)
{
case 1:
{
// your code here
break;
}
case 5:
{
// your code here
break;
}
case 9:
{
// your code here
break;
}
case 10:
{
// your code here
break;
}
case 14:
{
// your code here
break;
}
case 15:
{
// your code here
break;
}
case 19:
{
// your code here
break;
}
case 20:
{
// your code here
break;
}
}

Related

If statement for multiple values of same variable

I want to apply if statement to check a condition with multiple values, which I know should be something like this:
if (value == 1 || value == 2 || value == 3 || value == 4)
//Do something;
But this does not look good, isn't there any way to check like:
if(value == 1 || 2 || 3 || 4)
Note: I am not trying something in range like:
if (1 <= value && value <= 4)
No you can not write it as :
if(value==1 || 2 || 3 || 4)
You can use conditional statement for different conditions.
A possible simple alternative would be:
switch (value) { case 1: case 2: case 3: case 4: std::cout << "true"; }
Live sample
Wether it looks better or not is a matter of taste.
Another alternative would be:
switch (value) { case 1 ... 4: std::cout << "true"; }
Live sample
But this is not standard C++, I believe it's a GNU extension.
In case the range of possible values is smaller than the number of bits you can do something like this:
int value = 2;
auto values = {1,2,3,4};
int test = 0;
for(auto i : values)
test |= (1 << i);
if((1 << value) & test)
std::cout << "true" << std::endl;
If you have direct control over the possible values you can also directly set them as bitflags and skip the bitshift part.
Otherwise there is also the option of inverting the condition in case there are fewer possible values that should evaluate to false.
Also you could just loop over an array of valid values and see if any of them matches.
No you cannot write the way you have described. You still have option of switch case and ternary operators.
If you want to make it fancy you still have option like
vector<int> v = {1,2,3,4,5}; // desirable values
auto it = find(v.begin(), v.end(), value);
if(it != v.end()){
cout<<"value is equal to something!\n";
// if you want to check which value does it match to
cout<<"Matching value is at index "<<it-v.begin()<<"\n";
}else {
cout<<"Value is not equal to any number!\n";
}
For this you will need to include vector library by using #include <vector>
Well, I had the same issue and this is the solution I came up.
I created an array, with the values I want to check, and then I use the native array includes() method to check if the variable value exists on the array. Like this:
[1, 2, 3, 4].includes(value);
If the variable value exists on the array the includes() method will return a boolean with the value true. Otherwise it will return a boolean with the value false.

What does this C++ for-loop expression mean?

I am working through the "Add Binary" problem on leetcode and a solution which I found online is the following:
#include <string>
using std::string;
class Solution {
public:
string addBinary(string a, string b) {
string ret;
bool carry{false};
for (auto apos=a.size(), bpos=b.size(); apos || bpos || carry; ) {
bool abit{apos && a[--apos] == '1'};
bool bbit{bpos && b[--bpos] == '1'};
ret = (abit ^ bbit ^ carry ? "1" : "0") + ret;
carry = abit + bbit + carry >= 2;
}
return ret;
}
};
My question is regarding the for loop above. I understand that two iterations are being instantiated with the first two expressions that are separated by a comma. However, I don't understand how the three units being or'd (ie: ||) is supposed to behave. I'm also curious why it's ok to exclude the iterator expression in this instance, ie the final expression in the for-loop.
Please help me to understand how this code functions.
basically the for loop consist of 3 parts separted by ';'(semi-colon)
1)first part, this part is about initialization of variables, again you can leave it if you want
2)second part, it defines the condition on basis of which for loop will keep running, again you can leave it if you want
3) third part, this is the part where you want to do some operations, conventially iteration value is increment, but again you can leave it if you want
so if you go with this model, I think you can easily break down what is happening in the for loop that you mentioned.
Sometimes it helps to consider the equivalent while loop:
for (auto apos=a.size(), bpos=b.size(); apos || bpos || carry; /*no increment*/) {
// ...
}
->
{
auto apos = a.size();
auto bpos = b.size();
while( apos || bpos || carry ) {
bool abit{apos && a[--apos] == '1'};
bool bbit{bpos && b[--bpos] == '1'};
ret = (abit ^ bbit ^ carry ? "1" : "0") + ret;
carry = abit + bbit + carry >= 2;
/* increment would be here*/
}
}
The loop initializes apos and bpos and continues to loop as long as the condition apos || bpos || carry yields true, ie as long as apos, bpos and carry are not all 0 (0 is converted to false any other number to true).

Converting string into char

I've got a problem with converting types in C++. I've got an expression: string wholeExpression = "44*2"; and I want to separate numbers from operators.
If it is a operator, I use this part of code:
string subExpression;
char skladnik;
subExpression = wholeExpression.substr(poczatek, lenght);
skladnik = subExpression[0];
if it is a number:
subExpression = wholeExpression.substr(poczatek, lenght);
skladnik = atoi(subExpression.c_str());
#EDIT
switch (skladnik)
{
case '+':
case '-':
{
while (topOfStack > 0 && stack[topOfStack - 1] != '(')
{
outPut += stack[topOfStack - 1] + przecinek;
stack.resize(topOfStack - 1);
topOfStack--;
}
stack += skladnik;
topOfStack++;
break;
}
case '/':
case '*':
{
while (topOfStack > 0 && (stack[topOfStack - 1] == '*' || stack[topOfStack - 1] == '/'))
{
outPut += stack[topOfStack - 1] + przecinek;
stack.resize(topOfStack - 1);
topOfStack--;
}
stack += skladnik;
topOfStack++;
break;
}
case '(':
{
stack += skladnik;
topOfStack++;
break;
}
case ')':
{
while (stack[topOfStack - 1] != '(')
{
outPut += stack[topOfStack - 1] + przecinek;
stack.resize(topOfStack - 1);
topOfStack--;
}
if (stack[topOfStack - 1] == '(')
{
stack.resize(topOfStack - 1);
topOfStack--;
}
break;
}
default:
{
outPut += to_string(skladnik) + przecinek;
break;
}
}
}
But suddenly I've got problem with a numbers from 40 to 43 and 45 and 47 -> which are operators (in ASCII code). They are probably interpret by the switch not as numbers but as oparators. Another numbers work perfectly. How can i solve this problem?
You've answered your own question. The char for the number 40 doesn't exist. It's two char variables: 4 and 0. Because you are putting an int into a char with atoi, it is going to use the ASCII code. Without knowing the value of lenght, it's hard to say that this is indeed your problem, but here are two possible solutions:
Don't use atoi upfront. Instead interpret each number char into an actual integer after your switch statement (4 and 0 would be
atoi('4') * 10 + atoi('0'))
use an int orlong or double variable to hold your numbers.
You are using your variable skladnik in two different ways. In one code path it refers to a decoded integer, in the second code path it refers to a character. Once you've conflated the meaning like this, there's no way to tell once you're at the switch which meaning it has.
You should use two different variables, one for decoded numbers and one for operator characters. Then there will be no confusion.

Double scripted array as an lvalue

I was wondering, how would i express it in code?
rand() % 2 == 0 ? map[x][y] = 'm' : map[x][y] = 'M';
when I compile that line in g++, it doesn't give an error. However gcc tells me I need an lvalue left of the assignment statement. I thought maybe I should give them an integer
int i = rand() % 2 ? .......
but that also gives me an error. Can someone please help? Thanks
(See here)
From the accepted answer in that post, you can see in C it would evaluate as:
((rand() % 2 == 0) ? map[x][y] = 'm' : map[x][y]) = 'M';
And the statement on the left is not a proper L-value.
You could rewrite this as:
map[x][y] = rand() % 2 == 0 ? 'm' : 'M';
rand() % 2 == 0 ? (map[x][y] = 'm') : (map[x][y] = 'M'); // This should work in C, but I do not have gcc handy to verify
You need a lvalue to use the expression the way you did. It's used for assignment like:
bool isFull= (candiesEaten>10) ? true : false;
What you wrote is:
if(rand() % 2 == 0){
=map[x][y] = 'm';
}else{
=map[x][y] = 'M';
}
I hope you get the point. The more general format would be:
lvalue= (statement)? val1 : val2;
and it would actually be:
if(statement){
lvalue= val1;
}
else{
lvalue= val2;
}

If statement not seeming to check other && in statement

I have an if statement that looks as follows:
int count=0;
string Check;
if ((count==4 && Check!="-s")||(count==4 && Check!="-S"))
If count equals 4 and Check equals "-s" or "-S" it still enters this if statement because of the count == 4. It totally seems to ignore the second part. Is there something I'm doing wrong?
It's always going to be the case that either Check!="-s" or Check!="-S". Hence, your if statement is equivalent to if (count==4).
Well, if Check is "-S", then it will not even check the second pair of conditions, because you check with ||. The same holds true for the opposite case. If one is false, the other is true. Replace that with a &&.
int count = 4;
string Check = "-S";
if( (count == 4 && // count is 4, alright.
Check != "-s") || // Check is "-S", alright I'm done thanks to || (OR)
(count == 4 &&
Check != "-S") )
{
// ...
}
int count = 4;
string Check = "-s";
if( (count == 4 && // count is 4, alright.
Check != "-s") || // Check is "-S", time to check the other condition pair...
(count == 4 && // count is 4, alright.
Check != "-S") ) // Check is "-s", which is different from "-S", perfect.
{
// ...
}
Now the corrected version:
int count = 4;
string Check = "-S";
if( (count == 4 && // count is 4, alright.
Check != "-s") && // Check is "-S", different from "-s", now on to the other condition!
(count == 4 && // count is 4, alright.
Check != "-S") ) // Check is "-S"... oh dang! No executed code for you.
{
// ...
}
If count == 4 and Check == "-s", then the expression to the right of the || is true. If count == 4 and Check == "-S", then the expression to the left of the || is true. So you have true or true which is true. Thus, your if-block is executed.
The right statement is:
if(count==4 && (Check != "-s" || Check!="-S"))
The statement that you wrote is true if you have count = 4 and Check = "-S" because then the first part of the OR is true.
Might be more clear to use:
if (count==4 && Check!="-s" && Check!="-S")
You should use !strcmp(Check, "-s") and !strcmp(Check, "-S") instead of !=.
If you use == you compare the pointers and that is no what you want. The pointers will always be different thus your second argument will always be true.
You want to enter the if body if and only if Check is != from either -s or -S and count is = 4 right?
if ( (Check!="-s" && Check!="-S") && count==4 )
should work.
or
if ( Check.tolower() !="-s" && count==4 )
should work.
(Do not remember the name of the function to lowercase a string, you have got to look it up)
Hope this help.