Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
174 views
in Technique[技术] by (71.8m points)

c++ - How can I find how many times Friday the 13th appears in a year?

Like the title says, I'm trying to find out how many times Friday the 13th appears in a given year. I have to use a date class and somehow write code to figure it out.

Date.h

#ifndef DATE_H
#define DATE_H
#include <string>
#include <iostream>
using namespace std;

string Month[] = { "", "January", "February", "March", "April", "May", "June", "July",
"August", "September", "October", "November", "December" };

int daysInMonth[2][13] = { { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
                           { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } };
string DOW[] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "" };
class Date {
private:
    int *month;
    int *day;
    int *year;
public:
    // constructors
    Date(int month, int day, int year);
    Date(); // default constructor

    Date(Date &other);  // copy constructor
    Date(string mmddyyyy);  // constructor that takes a string as parameter e.g "10/31/2012"

    ~Date();

    // overload assignment operator 

    Date & operator=(Date & rhs);
    Date & operator++();
    Date & operator++(int);
    Date & operator--();
    Date & operator--(int);
    bool operator ==(Date & rhs);
    bool operator != (Date & rhs);
    bool operator > (Date & rhs);
    bool operator < (Date & rhs);

    int operator-(Date & rhs);
    Date & operator+(int);

    // accessors

    int getDay() {
        return *this->day;
    }

    int getMonth() {
        return *this->month;
    }

    int getYear() {
        return *this->year;
    }

    static Date toDate(int doy, int yr) {
        int dayOfMonth = doy;
        int month = 1;
        int isleap = isLeap(yr);

        for (int i = 1; i < 13; i++) {
            int daysThisMonth = daysInMonth[isleap][i];
            if (dayOfMonth <= daysThisMonth) {
                break;
            }
            else {
                month++;
                dayOfMonth -= daysThisMonth;
            }
        }
        return *new Date(month, dayOfMonth, yr);
    }

    // display date in the format of mm/day/year e.g. 10/31/2012
    void display() {
        cout << *this->month << "/" << *this->day << "/" << *this->year;
    }

    // returns true if the given year is a leap year and false otherwise
    static int isLeap(int year) {
        return ((year % 400 == 0) || (year % 4 == 0 && year % 100 != 0));
    }

    // returns the day code the the new year day of the given year
    static int get_day_code(int year) {
        return (year + (year - 1) / 4 - (year - 1) / 100
            + (year - 1) / 400) % 7;
    }

    // overloading get_day_code that returns the day code of the specific day
    static int get_day_code(int year, int month, int day) {
        int dayCodeForYear = get_day_code(year);
        Date temp(month, day, year);
        int doy = temp.dayOfYear() - 1;
        int dayCode = (dayCodeForYear + doy) % 7;
        return dayCode;
    }

    int dayOfWeek() { // return the day code of this day
        int dayOfYear = this->dayOfYear() - 1;
        int firstDayOfTheYear = Date::get_day_code(*this->year);
        dayOfYear += firstDayOfTheYear;
        return dayOfYear % 7;
    }

    int dayOfYear() {  // returns the day of the year, eg,  the day of year for Feb 28 is 59.
        int doy = 0;
        int isleap = isLeap(*year);
        for (int i = 1; i < *month; i++) {
            doy += daysInMonth[isleap][i];
        }
        doy += *day;
        return doy;
    }
};

Date::Date(int month, int day, int year) {
    this->month = new int(month);
    this->day = new int(day);
    this->year = new int(year);
}

Date::Date() {
    this->month = new int(1);
    this->day = new int(1);
    this->year = new int(2000);
}

Date::Date(Date &other) {
    this->month = new int(*(other.month));
    this->day = new int(*(other.day));
    this->year = new int(*(other.year));
}

Date::Date(string mmddyyyy) {
    string mm = mmddyyyy.substr(0, 2);
    string dd = mmddyyyy.substr(2, 2);
    string yyyy = mmddyyyy.substr(4, 4);

    this->month = new int(atoi(mm.c_str()));
    this->day = new int(atoi(dd.c_str()));
    this->year = new int(atoi(yyyy.c_str()));
}

Date::~Date() {
    if (month) delete month;
    if (day) delete day;
    if (year) delete year;
}

bool Date::operator == (Date & rhs) {
    return (*year == *(rhs.year) && *month == *(rhs.month) && *day == *(rhs.day));
}

bool Date::operator != (Date & rhs) {
    return !(*this == rhs);
}

bool Date::operator > (Date & rhs) {
    if (*year > *(rhs.year)) return true;
    else if (*year < *(rhs.year)) return false;
    else if (*month > *(rhs.month)) return true;
    else if (*month < *(rhs.month)) return false;
    else if (*day > *(rhs.day)) return true;
    return false;
}

bool Date::operator < (Date & rhs) {
    if (*year < *(rhs.year)) return true;
    else if (*year > *(rhs.year)) return false;
    else if (*month < *(rhs.month)) return true;
    else if (*month > *(rhs.month)) return false;
    else if (*day < *(rhs.day)) return true;
    return false;
}

Date & Date::operator=(Date & rhs) {
    *this->month = *rhs.month;
    *this->day = *rhs.day;
    *this->year = *rhs.year;
    return *this;
}

Date & Date::operator++() {
    Date tmp = *this + 1;
    *this->month = *tmp.month;
    *this->day = *tmp.day;
    *this->year = *tmp.year;
    return *this;
}
Date & Date::operator++(int) {
    Date tmp = *this + 1;
    Date * output = new Date(tmp);
    *this->month = *tmp.month;
    *this->day = *tmp.day;
    *this->year = *tmp.year;
    return *output;
}

Date & Date::operator--() {
    Date tmp = *this + -1;
    *this->month = *tmp.month;
    *this->day = *tmp.day;
    *this->year = *tmp.year;
    return *this;
}

Date & Date::operator--(int) {
    Date tmp = *this + -1;
    Date * output = new Date(tmp);
    *this->month = *tmp.month;
    *this->day = *tmp.day;
    *this->year = *tmp.year;
    return *output;
}

int Date::operator-(Date & rhs) {
    int yearsDiff = *this->year - *rhs.year;
    int daysDiff = this->dayOfYear() - rhs.dayOfYear();
    daysDiff += yearsDiff * 365;
    return daysDiff;
}

Date & Date::operator+(int) {
    int n = 0;
    int doy = dayOfYear();
    int newDoy = doy + n;
    int yearsDiff = newDoy / 365;
    newDoy = newDoy % 365;
    int newYear = *this->year + yearsDiff;
    Date newDate = Date::toDate(newDoy, newYear);
    return *new Date(newDate);
}
#endif

This is the code I've been messing with for a while:

Source.cpp

#include <iostream>
#include <iomanip>
#include "Date.h"

using namespace std;

void iterateMonth(int);
bool isFriday13th();
string dayofweek[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "" };
string month[] = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December", "" };
//int dayInMonth[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
//int dayInMonthLeap[13] = { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };


void iterateMonth(int year) {
    int dayCode, month, daysInMonth, day, u;
    bool leapYear;
    cout << year;

    // returns the day on which January 1 of year begins.
    dayCode = Date::getDayCode(year);
    // returns true if year is a leap year, false otherwise
    leapYear = Date::isLeap(year);

    // month is 0 for Jan, 1 for Feb, etc.
    for (month = 1; month <= 12; month++)
    {
        switch (month)
        {
        case 1:
            cout << "

January
";
            daysInMonth = 31;
            break;
        case 2:
            cout << "

February
";
            if (leapYear)
                daysInMonth = 29;
            else
                daysInMonth = 28;
            break;
        case 3:
            cout << "

March
";
            daysInMonth = 31;
            break;
        case 4:
            cout << "

April
";
            daysInMonth = 30;
            break;
        case 5:
            cout << "

May
";
            daysInMonth = 31;
            break;
        case 6:
            cout << "

June
";
            daysInMonth = 30;
            break;
        case 7:
            cout << "

July
";
            daysInMonth = 31;
            break;
        case 8:
            cout << "

August
";
            daysInMonth = 31;
            break;
        case 9:
            cout << "

September
";
            daysInMonth = 30;
            break;
        case 10:
            cout << "

October
";
            daysInMonth = 31;
            break;
        case 11:
            cout << "

November
";
            daysInMonth = 30;
            break;
        case 12:
            cout << "

December
";
            daysInMonth = 31;
            break;
        }
        //cout << "

Sun  Mon  Tue  Wed  Thu  Fri  Sat
";
        for (int i = 0; i < (sizeof(dayofweek) / sizeof(dayofweek[0])); i++)
        {
            cout << dayofweek[i] << "  ";
        }
        cout << endl;
        for (day = 1; day <= dayCode * 5; day++)
        {
            cout << " ";
        }
        for (day = 1; day <= daysInMonth; day++)
        {
            cout << setw(3) << day;
            if ((day + dayCode) % 7 > 0)
            {
                cout << "  ";
            }
            else
                cout << endl;
        }
        dayCode = (dayCode + daysInMonth) % 7;
   }
}
//bool isFriday13th() {
//
//}

int main() {
    int year;
    //cout << "Please enter a year: ";
    cout << "Final ";
    cin >> year;
    iterateMonth(year);
}

One idea I got from someone was to create a Date object for January 13th, use the dayOfWeek method to check if it's Friday, and if not, increment until I reach Friday, then jump ahead 7 and use getDay to check if it's 13. I tried this out with this:

Date tmp(1, 13, year);
int dc = tmp.dayOfWeek(); // return day code

tmp.display();
cout << endl;
++tmp;
tmp.display();
cout << endl;

I expected the tmp.display(); line to show 1/13/2013 (giving 2013 as the year), which it did, but the ++tmp line gave the same result. I also thought that I would have to somehow find the day code that corresponds to Friday (right now dc is 0), but I couldn't figure that out.

Also, another post related to the same problem said that every month that begins in Sunday will have Friday the 13th, so I tried thinking of how to implement that. Maybe somewhere in the first for loop (above the switch statement) I could check something like if (firstDay = Sunday) { cout << "Friday13th exists in " << month << endl; }

That's kinda horrible pseudo-code, but it was the idea I had going. Anyone have ideas? Any help would be appreciated, and thank you in advance.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You can do this without having to do a bunch of calls to a function that gets the day of the year. If you know the date of the first Sunday in January, then there's nothing to it. Just some basic math.

For 2013, the first Sunday in January was the 6th. So the 13th was a Sunday. We know that if the first Sunday in January is the 6th, then the first Sunday in February is the 3rd. Add 10 days for the 13th. That's a Wednesday.

How do I know that the first Sunday in February is the 3rd? Because the that's how the calendar works. If you take the date of the first Sunday in January, add 4 and mod 7, that'll give you the date of the first Sunday in February. The calendar is fixed that way; given the first Sunday in January, you can easily compute the first Sunday of any month using modulo 7 arithmetic.

The offsets are:

Normal Year: 0 4 4 1 6 3 1 5 2 0 4 2 
Leap Year:   0 4 3 0 5 2 0 4 1 6 3 1 

If you want to know what months have Friday fall on the 13th, then the next Sunday is the 15th, meaning that the first Sunday of the month has to be the 1st.

Given the table above, if the first Sunday in January is the 1st, then in a normal year you'll have two months with Friday the 13th: January and October. If it's a leap year, then you'll have January, April, and July. This year the first Sunday was the 6th, so you need months with an offset of 2. So September and December.

If the month offset plus the date of the first Sunday in January is equal to 8, then the month has a Friday the 13th.

I played with this as a memory trick some time ago. See Now what day is that? for a longer explanation.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...