#include <iostream>
#include <vector>
#include <string>
// 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<int> 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<int> 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<int> 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<int> leapYrDays = {0,31,60,91,121,152,182,212,243,274,304,335,366};
std::vector<int> commYrDays = {0,31,59,90,120,151,181,211,242,273,303,334,365};
std::vector<int> 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 };
}
Comments