#include #include #include // Mr. Liu, with all due respect sir I cannot take you seriously as a // programmer nor a lover of computer science when you blatantly // disregard ISO 8601 and willingly use the horrific and mangled MM DD // YYYY format. Not only does this fly in the face of good morals and // common sense and give headaches to those trying to sort through // timestamped files, it is a regressive thing to do and you should // feel absolutely ashamed. I beg of you to no longer follow the path // of nitwits. Turn towards the righteous path of international // standards, easy date sorting. Join us in using YYYY-MM-DD formats // and the world shall live together in unity forever. MM DD YYYY: Bad // for your health, bad for your code, BAD FOR AMERICA. void menuPrint(); // Printing the menu in main() is ugly & cluttered. bool checkDate(int year=1900, int month=1, int day=1); bool leapYear(int year); std::string zodiac(int year); std::string dayOfWeek(int year, int month, int day); std::vector sols(int year, int month, int day); int squareByValue(int val); int squareByReference(int & ref); int squareByPointer(int * ptr); int main() { std::string userChoice; while (true) { menuPrint(); std::cin >> userChoice; if ((userChoice == "q") || (userChoice == "-1")) { // User wants to quit; exit program. break; } else if (userChoice == "1") { // User chose the leap year program int year = 0; std::cout << std::endl << "Leap Year:" << std::endl; while (!checkDate(year)) { // Ensure they only enter a valid year. std::cout << "Please enter a year 1900 or later." << std::endl; std::cin >> year; // Every time we read from cin into an integer we will run // these two statements, because otherwise the code will // freak out if the user enters a string. clear turns off the // error flag and ignore jumps to the next newline so that // the program does not try to read any more letters into // numbers. std::cin.clear(); std::cin.ignore(100000,'\n'); } std::cout << year << " is " << (leapYear(year) ? "" : "not "); std::cout << "a leap year." << std::endl; } else if (userChoice == "2") { // User chose the zodiac program int year = 0; std::cout << "Zodiac:" << std::endl; while (!checkDate(year)) { // Ensure they only enter a valid year. std::cout << "Please enter a year 1900 or later." << std::endl; std::cin >> year; std::cin.clear(); std::cin.ignore(100000, '\n'); } std::cout << year << " is the year of the " << zodiac(year) << std::endl; } else if (userChoice == "3") { // user chose the day of the week program. std::cout << "Day of the Week:" << std::endl; int year = 0; int month = 0; int day = 0; while(!checkDate(year, month, day)) { std::cout << "Please enter a date 1900-01-01 or later. "; std::cout << "Use MM DD YYYY format." << std::endl; std::cout << "Month:" << std::endl; std::cin >> month; std::cin.clear(); std::cin.ignore(100000, '\n'); std::cout << "Day:" << std::endl; std::cin >> day; std::cin.clear(); std::cin.ignore(100000, '\n'); std::cout << "Year:" << std::endl; std::cin >> year; std::cin.clear(); std::cin.ignore(100000, '\n'); } std::cout << year << "-" << month << "-" << day << " falls on a "; std::cout << dayOfWeek(year, month, day) << std::endl; } else if (userChoice == "4") { // User chose the Martian Calendar program. std::cout << "Martian Calendar:" << std::endl; int year = 0; int month = 0; int day = 0; while(!checkDate(year, month, day)) { std::cout << "Please enter a date on or after 1900-1-1. Please "; std::cout << " use MM DD YYYY format." << std::endl << "Month:\n"; std::cin >> month; std::cin.clear(); std::cin.ignore(100000, '\n'); std::cout << "Day:\n"; std::cin >> day; std::cin.clear(); std::cin.ignore(100000, '\n'); std::cout << "Year:\n"; std::cin >> year; std::cin.clear(); std::cin.ignore(100000, '\n'); } std::vector marsDate = sols(year, month, day); std::cout << "The martian date is " << marsDate.at(1) << " "; std::cout << marsDate.at(2) << " " << marsDate.at(0) << std::endl; } else { std::cout << "\n\nFIXME\n\n"; } } return 0; } void menuPrint() { std::cout << std::endl; std::cout << "Main Menu — Enter an item's menu-number or input q or -1 to "; std::cout << "exit the program" << std::endl; std::cout << "1) Leap years" << std::endl; std::cout << "2) Zodiac" << std::endl; std::cout << "3) Day of the week" << std::endl; std::cout << "4) Martian Calendar" << std::endl; std::cout << "5) Square (by value)" << std::endl; std::cout << "6) Square (by reference)" << std::endl; std::cout << "7) Square (by pointer)" << std::endl; } bool checkDate(int year, int month, int day) { /* Returns true if the date is valid. Defaults to 1900-01-01 so you can check just a year without checking a month or a day. */ bool validYear = (year >= 1900); bool validMonth = ((month >= 1) && (month <= 12)); int monthMax; switch (month) { case 2: monthMax = (leapYear(year) ? 29 : 28); break; case 4: case 6: case 9: case 11: monthMax = 30; break; default: monthMax = 31; break; } bool validDay = ((day >= 1) && (day <= monthMax)); return (validYear && validMonth && validDay); } bool leapYear(int year) { if (year % 4 != 0) // year is not a 4th year { return false; } // any years past this point are divisible by 4 else if (year % 100 != 0) // year is a 4th year and is not divisible by 100) { return true; // all such years are leap years. } // any years past this point are divisble by 4 and divisble by 100 else if (year % 400 != 0) // year is divisible by 4 and not divisible by 400 { return false; } // any year past here must be divisible by 4 and divisible by 400 else { return true; // all such ears are leap years } } std::string zodiac(int year) { int nthYear = (year - 1900) % 12; // reduce years to 12-yr cycle starting at 1900 switch (nthYear) { case 0: return "rat"; case 1: return "ox"; case 2: return "tiger"; case 3: return "rabbit"; case 4: return "dragon"; case 5: return "snake"; case 6: return "horse"; case 7: return "goat"; case 8: return "monkey"; case 9: return "rooster"; case 10: return "dog"; case 11: return "pig"; default: return "unknown"; } } std::string dayOfWeek(int year, int month, int day) { /* Wow okay this is complicated. Basically there's 4 possible centries in the gregorian calendar, and they keep cycling over and over. Let's call one of these a maj (for major centuries). You can either have a century beginning with a common year that starts on a monday, such as 1900, a century that starts with a leap year that starts on a saturday (such as 2000), a century that begins on a common year and starts on a friday (such as 2100), or a century that begins with a common year and starts on a wednesday, such as 2200. Using this knowledge, we can just compute how many monday-saturday cycles have happened since the start of the century and then find the day of the week based on what day of the week the century started on. */ // find the number of days in february int feb = leapYear(year) ? 29 : 28; //find how many days have passed BEFORE the month you're on. int months[] = {0,31,feb,31,30,31,30,31,31,30,31,30,31}; int pastMon = 0; for(int i=0; i < month; i++) {pastMon += months[i];} // now we're calculating what we called a maj earlier. int maj = ((year - 1900) % 400) / 100; // get the last two digits of the year since this is all we care about now. year %= 100; // For calculating total # of days in the years leading up to this one. int n = year - 1; // Finding that total number of days and storing it in pastYrs. int pastYrs = (n>-1) ? ((n-(n/4))*365 + (n/4)*366 + (maj==1 ? 366 : 365)) : 0; // Add up the number of days before this month in this year, the number of days // in the years leading up to now, and the number of days since the start of // the month, and subtract 1 so that the first day is 0. int julian = pastYrs + pastMon + day - 1; // mod it by 7 to find our "naive" day of the week where every century starts on // a monday int septCycle = julian % 7; // from our naive day septCycle, shift it over by what the century ACTUALLY // started on to find the actual day of the week. int start; switch(maj) { case 0: start = 0; break; case 1: start = 5; break; case 2: start = 4; break; case 3: start = 2; break; default: start = -1000; break; } int dOW = (septCycle + start) % 7; // FINALLY return "monday" if it's 0, "tuesday" if it's 1, etc. switch(dOW) { case 0: return "monday"; case 1: return "tuesday"; case 2: return "wednesday"; case 3: return "thursday"; case 4: return "friday"; case 5: return "saturday"; case 6: return "sunday"; default: return "unknown"; } } std::vector sols(int year, int month, int day) { // You know what? The approach I took in the Days of the Week // function was too damned mathy. Lets try something a bit more loopy // here instead. // cumDays adds up the ammount of days in the preceeding months std::vector leapYrDays = {0,31,60,91,121,152,182,212,243,274,304,335,366}; std::vector commYrDays = {0,31,59,90,120,151,181,211,242,273,303,334,365}; std::vector cumDays = leapYear(year) ? leapYrDays : commYrDays; int yrsDays = 0; for (int i=1900; i < year; i++) { yrsDays += leapYear(i) ? 366 : 365; } int totalDays = yrsDays + cumDays.at(month-1) + day; // Total number of martian days since 1900-01-01 mars time. int toMartian = totalDays / 1.027; int marsYear = toMartian / 672 + 1900; int marsMonth = (toMartian - (toMartian / 672 * 672)) / 56 + 1; int marsDay = (toMartian - ((marsYear-1900)*672) - ((marsMonth-1)*56)); return { marsYear, marsMonth, marsDay }; }