This is my first mini project (I'm intermediate c programmer)
I wanted to practice using if statements because I wanted to find the extent of the command, and what I could use it for.
However, throughout my program, I constantly became very annoyed that I'm having to write all this code, to perform a simple task.
The basics of the code is that the user inputs their birth month, and the program outputs their astrology related sign and meaning. My question is, Is there a way, that I could perform the same task, but in less code? Is there a command I could use, or something?
------extra-------------------------------------
In my cs1 class, we recently learned about switch cases. I was thinking that I could use switch cases to fix 1 problem I had, accuracy
Improving the accuracy of the users b-day. Instead of using tons of if statements which can only look for a specific month (or with even more if's month and day) I could use a case that said "1. January 1-20th" However, now this just makes me want to be more accurate about the month. ***Could I possible use more if statements or perhaps something in the case that basically says if the user says <20 then they are Aquarius?
Is there also a different way I could do the program other than switch cases?
string user_month;
cout << "This program currently accepts these months in this spelling\n";
cout << "january, february, march\n\n";
cout << "Whats the month of your birthday? (lowercase)\n";
getline(cin, user_month);
cout << endl;
cout << user_name << " ... You are about to see your astrological sign and its qualities.\n";
cout << "Know that they might not be truly accurate and this is just for fun.\n\n";
if (user_month == "january")
{
;
cout << endl;
cout << "You are a Capricorn.\n";
cout << "Capricorns are usually hardworking, tenacious, diligent, and responsible\n";
cout << "No matter what the job is, you'll get it done to the best of your ability.\n";
cout << "Even if you don t have a natural aptitude for a skill, you won t stop working until you ve mastered "
"it\n.";
}
if (user_month == "february")
{
cout << endl;
cout << "You are a Aqaurius.\n";
cout << "An Aquarius ascribes to a progressive ideology. \n";
cout << "Because of this you are willing to let go of ";
cout << "past traditions that no longer serve the people of the future.\n";
cout << "You aren t content with the answer 'but that s the way it s always been done.' \n";
cout << "You are willing to try new things, because you know that even if they fail, \n";
cout << "you know that your getting closer to the right solution.\n";
}
if (user_month == "march")
{
cout << endl;
cout << "You are an Aries.\n";
cout << "At your core, you do what they want and do things your way.\n";
cout << "You are unafraid of conflict, highly competitive, honest and direct.\n";
cout << "An Aries is not weighed down by the freedom of choice, and is the sign that is least conflicted about "
"what they want.\n";
cout << "You might throw themselves at the world eagerly and without fear.\n";
cout << "It is one of your most commendable qualities, but also what causes you a great deal of pain and "
"grief.\n";
}
// yes I'm aware my code does not include all the months
return 0;
}
CodePudding user response:
Sometimes, when you have to handle n different values in different ways, you end up with a switch or if-cascade with n branches.
But often, when you perform the same action (with different data) in all branches, there are other ways, e.g., a look-up table.
What are you trying to do? For each month, print a text. So the same action, different data.
Before we look at more complicated solutions, let's improve what you have with the stuff you have learned so far.
First off, you don't need to repeat cout every time, you can chain the stream operator <<:
std::cout << "Hello\n" << "My name is Bob.\n" << "I like potatoes.\n";
Even better, C will merge string literals "that are" "adjacent":
std::cout << "Hello\n"
"My name is Bob.\n"
"I like potatoes.\n";
You can also put these large text blocks into variables outside of your main, so you have them out of sight:
const char *capricorn = "You are a Capricorn.\n"
"Capricorns are hard...";
So you end up with code like:
string user_month;
getline(cin, user_month);
if (user_month == "january") {
cout << capricorn;
} else if (user_month == "february") {
cout << aquarius;
} else if (// etc...
A bit easier to read. Now we see the structure of our program much clearer. We just want to cout something depending on month.
Now, there are things you haven't learned about. E.g., using a "map" (a lookup table):
#include <unordered_map>
// In your function
// Map of key-value pairs
std::unordered_map<std::string, std::string> um =
{ {"january", "You are a Capricorn\n etc etc\n"} };
// Read month, then:
auto res = um.find(user_month);
if (res != um.end()) {
// Found in map. res->first is key, res->second is value.
std::cout << res->second;
} else {
// Invalid month
std::cout << "Error: invalid input";
}
Another way would be to store the strings in an array and map the months to array indices (0-11). But you'd need an if-cascade for that too, so maybe that defeats the purpose.
Note that for actual zodiac signs, the task would be a bit more difficult, because they are not about months, but date ranges (e.g., march 21. - april 19.).
CodePudding user response:
Here's how I would set this up.
I would use a std::map to map from month names to the output you want to associate with it.
std::map::find will perform a lookup and return an iterator for a key-value pair of month and associated output, or an end iterator if it is not found.
A std::optional is a nice way of either having a value or not and it a little less heavy-handed than throwing an exception.
And finally, make good use of functions to describe your program in understandable pieces.
#include <optional>
#include <string>
#include <iostream>
#include <map>
std::map<std::string, std::string> signs = {
{ "january", "You are a capricorn..." },
{ "february", "You are an Aquarius..." },
// ...
};
std::string getUserInput() {
std::string input;
getline(std::cin, input);
return input;
}
std::optional<std::string> tryGetOutput(const std::string& month) {
auto it = signs.find(month);
if (it == signs.end()) return {};
return it->second;
}
int main() {
std::string input = getUserInput();
std::optional<std::string> output = tryGetOutput(input);
if (!output.has_value()) {
std::cout << "unknown month" << std::endl;
return -1;
}
std::cout << output.value() << std::endl;
}
