I am trying to create a complex if statement in C++ that will save me from writing a whole bunch of if statements, I am wondering if this code below actually makes sense or I am overlooking an error.
if(input==choice) {
cout << "Tie!" << endl;
}else if(input=="rock" && choice=="scissors"
|| input=="scissors" && choice=="paper"
|| input="paper" && choice=="rock") {
cout << input " beats " << choice << ", you win!" << endl;
}else if(input=="rock" && choice=="paper"
|| input=="scissors" && choice=="rock"
|| input=="paper" && choice=="scissors"){
cout << choice << " beats " << input << ", you lose!" << endl;
}
What I am trying to achieve is:
"if input is x AND choice is y, OR if...."
Basically I'm testing multiple "if-and" conditions so that a single line of code will execute if it hits any of the if-and conditions. The output throws a "no match for 'operator||'" error.
You have a typo in input="paper" && choice=="rock"), but instead of fixing the typo I would suggest you to fix the code. No wonder you made a typo in this giant block of conditions. You have lots of repetion and mixing logic with output. If you spend some lines on includes, you can save some on code...
#include <iostream>
#include <string>
#include <vector>
#include <utility>
#include <algorithm>
bool win(const std::string& input, const std::string& choice) {
static const std::vector<std::pair<std::string, std::string>> wins =
{ { "rock", "scissors" },
{ "scissors", "paper" },
{ "paper", "rock" }
};
return std::find(wins.begin(), wins.end(), std::make_pair(input, choice))
!= wins.end();
}
int main() {
std::string choice = "paper";
std::string input = "scissors";
if (win(choice, input)) { std::cout << "you win! \n"; }
else { std::cout << "you lose! \n"; }
}
As next step you should eliminate all that strings, eg by using enums as discussed in the comments.
Related
Here is my code:
bool isNotValid (char a) {
if (isalpha(a) || a == '_')
{
cout << "\n- isalpha";
return 0;
}
else
{
cout << "\n- notalpha";
return 1;
}
}
bool test123(const string& test)
{
return find_if(test.begin(), test.end(), isNotValid) != test.end();
}
int main()
{
string test;
cout << "Test input: ";
cin >> test;
if (!test123(test))
cout << "\n- Valid\n";
else
cout << "\n- Not Valid\n";
return 0;
}
This is part of my code to check the validity of username in my program. I don't really understand what exactly I am iterating through when I insert the string into my function as address of the string. CPP reference states that find_if iterates from first to last position of a sequence.
Poked through the code with cout at different location, still didn't quite catch what is going on.
You are iterating your string. You did not pass the address of the string. The function takes the string as a reference to const, meaning it passes the actual string (no copy is made) and the function is not allowed to modify the string. You are iterating character by character in your string and calling your function isNotValid() on each character.
Notes:
Instead of returning 1 or 0 from isNotValid(), return true or false.
Consider flipping your logic and renaming the function to isValid() instead. You would also have to change test123() to use std::find_if_not(). Finally, you would check if the returned iterator is end() and not if it's not.
But, if you do change isNotValid() to isValid(), you'd be better off switching from std::find_if() entirely to to std::all_of(). It makes more sense, is more readable, and returns a bool directly (No need to compare against end()).
But if you want to keep your function isNotValid(), the comment that suggests using std::any_of() is what I would recommend for the same reasons.
Here's my take on your code:
#include <algorithm>
#include <cctype>
#include <iostream>
#include <string>
bool isValid(char a) {
return std::isalpha(static_cast<unsigned char>(a)) || a == '_'; // !
}
bool test123(const std::string& test) {
return std::all_of(test.begin(), test.end(), isValid); // !
}
int main() {
std::string testOne{"i_am_valid"};
std::string testTwo{"i_am_invalid_123"};
std::cout << "Testing: " << testOne << " : " << std::boolalpha
<< test123(testOne) << '\n';
std::cout << "Testing: " << testTwo << " : " << std::boolalpha
<< test123(testTwo) << '\n';
}
Output:
❯ ./a.out
Testing: i_am_valid : true
Testing: i_am_invalid_123 : false
I would argue that readability has stayed largely the same, but the mental load has been shifted; the Boolean flips make a bit more sense.
As you progress in your learning, you might not even want to have the function isValid() if it's a one-off thing. C++11 introduced lambdas, or functions as objects. C++20 also introduced ranges, so you don't have to pass a pair of iterators if you intend to iterate the whole container anyway.
#include <algorithm>
#include <cctype>
#include <iostream>
#include <string>
bool test123(const std::string& test) {
return std::ranges::all_of(test, [](const auto& c) {
return std::isalpha(static_cast<unsigned char>(c)) || c == '_';
}); // !
}
int main() {
std::string testOne{"i_am_valid"};
std::string testTwo{"i_am_invalid_123"};
std::cout << "Testing: " << testOne << " : " << std::boolalpha
<< test123(testOne) << '\n';
std::cout << "Testing: " << testTwo << " : " << std::boolalpha
<< test123(testTwo) << '\n';
}
That's a bit hairy to read if you're not familiar with lambdas, but I find lambdas useful for checks like this where you're just doing it the one time.
I'm starting to learn C++, and something useful from my main language Lua, is the ability to say:
print(true/false and 1 or 0)
1 or 0 being anything but it seems in c++ it doesnt work the same way?
What I tried for C++ was
cout << (score == 0) and "Valid";
But only a true if check seems to work
if (score == 0) {
cout << "Valid";
} else {
cout << "A";
}
std::cout << ((score == 0) ? "Valid" : "A");
The << in your code isn't simply a syntax, it's an operator:
std::basic_ostream<CharT,Traits>::operator<<
Your attempt will not produce any compilation errors (assuming you have using namespace std;):
cout << (score == 0) and "Valid";
// ^^ T/F ^^ ^^ T ^^
Apply some boolean algebra and that's equivalent to:
cout << true; // if score is 0
cout << false; // if score is not 0
That's certainly not what you are trying to acheive.
Are there ways to do if statements inside a cout line?
if (score == 0)
cout << "Valid";
else
cout << "A";
You can do that using the conditional operator ?:
cout << (score == 0 ? "Valid" : "A");
But this approach is not guaranteed to work always. For example:
cout << (condition ? "String" : 1234);
Reason: Why in conditional operator (?:), second and third operands must have the same type?
Rearranging it like this will work:
condition ? cout << "String" : cout << 1234;
Now, talking about your Lua style:
print(true/false and 1 or 0)
I don't know Lua but that looks like a function. If you are looking for some template like that, try this:
template <typename T, typename U>
void conditionalPrint(const bool& condition, const T& arg1, const U& arg2)
{
condition ? cout << arg1 : cout << arg2;
}
You can use it like this:
conditionalPrint(score == 0, "Valid", "A");
conditionalPrint(someCondition, "String", 1234);
Of course, I'm not going to explain how that works because you're new to C++. I would still recommend the if-else way of doing it. Readability of your code is very important:
if (condition)
{
cout << "true block";
}
else
{
cout << "false block";
}
"Lot can be learned by comparing two lanugages and try to see if what can be done in one can also be done in the other, but usually what is idiomatic in one can be crap in the other. Anyhow, I had my fun with exploring the issue, but imho the conclusion is as important as the rest of the answer" - idclev
This is gonna be laughed at because I'm probably very stupid, but can I use more than one string as a condition in an if statement?
#pragma once
#include <iostream>
#include <string>
#include "Baxter.h"
#include "Inventory.h"
#include "Room1Items.h"
int woman = 6;
int children = 5;
int inputNumberOfAnimalsToSave;
int numberOfAnimals;
int numberOfAnimalsToKill;
int numberOfAnimalToTakeHome;
std::string Yes;
std::string firstAction;
bool killRemainingAnimals;
int playerSaidYes;
int AddNumber()
{
numberOfAnimals = woman + children;
return numberOfAnimals;
}
int RemoveNumber()
{
numberOfAnimalsToKill = numberOfAnimalToTakeHome - numberOfAnimals;
return numberOfAnimalsToKill;
}
int InputNumber()
{
std::cout << " Comrade Kurchenko: Well, they are irridiated and will most likely end up poisioning \n";
std::cout << " your family, but sure, why not! How many animals Shall we Save ?\n ";
std::cin >> inputNumberOfAnimalsToSave;
numberOfAnimalToTakeHome = numberOfAnimals - inputNumberOfAnimalsToSave;
return numberOfAnimalToTakeHome;
}
int DoYouWantToKillTheRest()
{
std::cout << " Comrade Kurchenko: Fair Enough Comrade! Do you want to move on? \n\n";
std::cout << " Private Lenin: "; std::cin >> Yes;
while (Yes == "No")
{
//std::cout << " Comrade Kurchenko: So, you want the remaining " << numberOfAnimalToTakeHome << " Put The sleep do you?\n\n";
//std::cout << " Private Lenin: Im afraid so sir!\n\n";
//std::cout << " Comrade Kurchenko: Then so be it. They will be better off dead by our hands, than starving to death.\n\n\n\n";
//std::cout << " *** Loud Bangs and Then Silence....\n\n\n ***";
std::cout << " Comrade Kurchenko: What do you want to do?\n";
std::cout << " Private Lenin: "; std::cin >> firstAction; std::cout << "\n";
while (firstAction != "MoveOn")
{
if (firstAction == "Take food" || "Recover Meal" )
{
if (canTakeFood)
{
TakeFood();
std::cout << " You have taken a peice of food \n";
DoYouWantToKillTheRest();
}
if (canTakeFood == false)
{
std::cout << " There is no more food to take \n";
DoYouWantToKillTheRest();
}
}
if (firstAction == "Eatfood")
{
EatFood();
DoYouWantToKillTheRest();
}
if (firstAction == "Inventory")
{
ShowInventory();
DoYouWantToKillTheRest();
}
if (firstAction == "Ouch")
{
JabAFingerInYourEye();
std::cout << " Comrade Kurchenko : Why the hell did you stab yourself in the eye?\n\n";
std::cout << " Private Lenin : I dont know sir, its like someone was controlling my arm!\n";
DoYouWantToKillTheRest();
}
if (firstAction == "Look")
{
Look();
DoYouWantToKillTheRest();
}
if( firstAction == "Help")
{
WhatCanIDo();
DoYouWantToKillTheRest();
}
if (firstAction == "Baxter")
{
ShowBaxter();
std::cout << "Here is baxter";
DoYouWantToKillTheRest();
}
}
return 0;
}
return 0;
}
I've tried it and get no bugs when I run it. It just doesn't work.
I have tried to google it but I can't seem to find the right way to word it to get results. Messing around with a console based text adventure.
I've googled as many different ways of asking this question and can't get any results that help me.
I get no error messages. It runs fine, it just doesn't work.
"Can I compare with more than one string in an if statement?" - Sure you can (I'm assuming we are talking about std::strings here).
You are doing
if (firstAction == "Take food")
If you wanted to test against two strings you could do:
if (firstAction == "Take food" or firstAction == "Drop food")
You could change that or to || which is more conventional, but both are valid and do the same thing.
In C++ (and most other programming languages) you usually can't compare one thing (a string variable) to multiple others in one operation because of the way operator precedence is defined:
// Does not work!!
if (firstAction == "Take food" || "Recover Meal" )
// Because it will evaluate to (firstAction == "Take food") || "Recover Meal"
Rather you use logical operators to combine the result of one comparison with another comparison:
if (firstAction == "Take food" || firstAction == "Recover Meal")
{
You should read up on logical operators in C++ to learn more, for instance here: https://www.learncpp.com/cpp-tutorial/36-logical-operators/
If you want to dynamically compare to a whole list of strings, then you can do so of course as well:
std::set<std::string> validActions = {"Take food", "Recover meal"};
if (validActions.find(firstAction) != validActions.end())
{
// ... found a valid action ...
This is not how you compare c-strings in C++. That type of string is just an array of characters and operator == tells if it is the same array, not if it has the same content.
To compare strings properly use function strcmp from <cstring>.
firstAction == "Take food"; // bad
strcmp(firstAction, "Take food") == 0; // good
Better yet solution would be using class std::string which allows to use normal operators.
std::string(firstAction) == "Take food"; // good
std::string(firstAction) == std::string("Take food"); // also good
firstAction == std::string("Take food"); // also good
Or, like #JVApen has hinted, maybe even better solution would be to use std::string_view.
firstAction == std::string_view("Take food"); // good
firstAction == "Take food"sv; // the same meaning as above but written shorter
You just need to remember to insert line using std::operator""sv; before that. (using namespace std; would also do.)
If you comparing string properly (let's say using the std::string_view) then of course you can use || (or) or && (and) or any other operator to make multiple comparisons in a single if.
if (firstAction == "Take food"sv || firstAction == "Take water"sv)
{
// do stuff
}
if (firstAction == "Take food"sv && !canTakeFood)
std::cout << " There is no more food to take \n";
LoopAndDoAction();
}
(This code probably doesn't make sense but it's just an example.)
Depending on what are you trying to do, consider using enum instead of string constants. Enums are faster, more readable, take less memory and there is harder to make mistake like a type when using it. Actually, only situation I can think of when you would not want to use enum would be parsing user input.
The second if is with who you can compare strings a lot of strings if you find some condition true on these if, the entire condition will be true.
I exaplained all on code //comments
Documentation: http://www.cplusplus.com/reference/string/string/compare/
#include <iostream>
#include <string>
using namespace std;
int main()
{
string str1ok = "Im a string";
string str2ok = "Im a string";
string str3ok = "Im a string different";
//First condition with and operator (&&) you can compare with a lot && operators
if(str1ok.compare(str2ok) == 0 && str3ok.compare(str2ok) == 0){ //First condition is true, second false, this condition is false because have true and false, need have true and true for be true
cout << "1st condition" << endl;
}
//Another condition with or operator (||) one condition need be true, if not is false
if(str1ok.compare(str2ok) == 0 || str3ok.compare(str2ok) == 0){ //First condition is true, only for this this condition is true, second condition is false.
cout << "2nd condition" << endl;
}
//You can make a mixed the operators like this some condition && (anothercondition || condition)
return 0;
}
Ouptput: https://onlinegdb.com/By39WpOGS
I'm working on my C++ assignment. I'm having an issue with string comparison.
I'm comparing two apparently identical strings using == operating but the condition returns false. The debugger also shows that both strings (stored in different variables) are identical. I must be missing something.
Here is my code:
void classCounter() {
ifstream fread;
string linetxt;
char *records[50];
char myLine[100];
char delims[] = "|";
int btotal=0,etotal=0,total=0;
fread.open("F:\\myfile.txt");
while(!fread.eof()) {
getline(fread,linetxt,'\n');
int i = 0;
strcpy(myLine, linetxt.c_str());
records[i] = strtok( myLine, delims );
while( records[i] != NULL )
{
cout << records[i] << "|";
char *bu = "Business";
if(records[i] == bu) {
btotal++;
}
if(records[i] == "Economy") {
etotal++;
}
//printf("%d '%s'\n", i, records[i]);
records[++i] = strtok( NULL, delims );
break;
}
total++;
}
cout << "Total number of booked Business seats: " << btotal << endl;
cout << "Total number of booked Economy seats: " << etotal << endl;
cout << "Total number of booked seats: " << total << endl << endl;
}
Here is what debugger shows:
Both if conditions are returning false.
Please suggest what could be the issue.
You are comparing two pointers, and they will never be the same. Either heed the advice to use std::string (what I recommend too) or you use strcmp to compare strings.
if(records[i] == bu) {
and
if(records[i] == "Economy") {
compare two char*, not strings.
You can compare them as strings by using std::string or using the function strcmp.
Option 1: Use std::string
std::string records[50];
With that change,
if(records[i] == bu) {
and
if(records[i] == "Economy") {
should work.
Option 2: Use strcmp
if( strcmp(records[i], bu) == 0) {
and
if( strcmp(records[i], "Economy") == 0) {
Your debugger is telling you what you need to know.. You're using char* instead of String so your char* are pointers. Your program is comparing two pointers and 0x00c93bc0 != 0x002af824.
Use strcmp in the future to avoid this problem
So I'm going to assume your input file looks something like:
Business|Economy|Economy|Economy|Business
Economy|Economy|Economy|Business|Economy
...and so on. Correct? And you're trying to count up how many of each kind of ticket was sold?
If so, I'd write the code quite a bit differently. I'd probably do something like this:
std::map<std::string, int> tickets;
std::string name;
std::ifstream in("f:/myfile.txt");
int total = 0;
while (std::getline(in, name, '|')) {
++tickets[name];
++total;
}
for (auto t : tickets)
std::cout << "Total number of booked " << t.first << " seats is: " << t.second "\n";
std::cout << "Total number of booked tickets: " << total << "\n";
So I have this code here:
std::cout << "Here's Question 2 now for " << char(156) << "200" << endl;
Sleep(2000);
PlaySound(TEXT("Millionaire/£100Play.wav"), NULL, SND_FILENAME | SND_ASYNC | SND_LOOP);
std::cout << "In maths, which of these numbers is not referred to as a square number?" << endl;
Sleep(2000);
std::cout << "A: 0" << endl;
Sleep(2000);
std::cout << "B: 1" << endl;
Sleep(2000);
std::cout << "C: 2" << endl;
Sleep(2000);
std::cout << "D: 4" << endl;
Sleep(2000);
answerQues2:
std::cout << "So, A, B, C or D?";
std::cin >> answer2;
if (answer2 == "C" || answer2 == "c")
{
std::cout << "That's correct, you've won " << char(156) << "200!" << endl;
PlaySound(TEXT("Millionaire/£100correct.wav"), NULL, SND_FILENAME);
Sleep(2000);
}
Now, the code itself is not the problem. What this is essentially is a quiz with a question and then 4 answers (A, B, C and D). Now in order to actually make up more questions, you'd have to go into the code itself and go through a lengthy process to edit everything. I want to make a text file that you can edit the questions and answers inside the text file, hence replacing everything in the code (So for example, if I wanted to change Q1, I could open the text file, replace the question and when I load up the program, the question will be changed). How would I be able to do this?
This is a full solution, though you must fill in the rest of your existing code. I personally use the below function, GetFileLines, to load lines from a file into a vector. Easy to work with that way. I took the time to adapt it to char/string since that is what you are using, though I default to wstring/wchar_t.
#include <string>
#include <vector>
#include <fstream>
#include <iostream>
#include <Windows.h>
using namespace std;
bool FileExists(const std::string& name) {
FILE * file;
errno_t result = fopen_s(&file, name.c_str(), "r");
if (result == static_cast<errno_t>(0)) {
fclose(file);
return true;
}
else {
return false;
}
}
std::vector<std::string> GetFileLines(std::string filePath)
{
vector<string> lines;
if (!FileExists(filePath))
return lines;
ifstream input(filePath);
if (!input.is_open() || input.fail())
return lines;
string line;
do {
std::getline(input, line);
lines.push_back(line);
} while (!input.eof() && !input.fail() && !input.bad());
if (!input.eof() && (input.fail() || input.bad()))
throw exception("GetFileLines failure");
return lines;
}
int wmain() {
vector<string> quizLines = GetFileLines("c:\\quiz.txt"); // replace with path to your file
if (quizLines.size() == 5) {
string question = quizLines[0];
string answer1 = quizLines[1];
string answer2 = quizLines[2];
string answer3 = quizLines[2];
string answer4 = quizLines[2];
// Your code begins here
std::cout << "Here's Question 2 now for " << char(156) << "200" << endl;
Sleep(2000);
PlaySound(TEXT("Millionaire/£100Play.wav"), NULL, SND_FILENAME | SND_ASYNC | SND_LOOP);
std::cout << question << endl;
Sleep(2000);
std::cout << "A: " << answer1 << endl;
// Rest of your code with changes to use answer# variables should follow
}
else {
std::cout << "Could not load quiz from external file. Cannot continue." << endl;
}
}
I recommend you read some documentation on this standard library elements I used that you are not familiar with. Any of these links, ordered by most common use first, may be useful to you for that:
http://www.cplusplus.com/reference/string/string/
http://www.cplusplus.com/reference/vector/vector/
http://www.cplusplus.com/reference/fstream/ifstream/
And don't pay attention to people down rating an honest question. Some were born into this world doing headstands it seems.
And also, for the record, this was an exceedingly ~easy~ question to answer. Why? Not because it was a dumb question, but because imagine how common it must be to try to access file contents. So if you ask a fundamental question like how do I get at that file content, you should expect a lot of quick full answers, because like in my case, they should be on hand. Could it be figured out using online searches, of course, though it's not always easy to figure out the pieces whose documentation you should be reading.