# Day of the Programmer

See the original problem on HackerRank.

## Solutions

This problem seems convoluted but it can be solved very easily if decomposed in terms of simple predicates:

• if the year is 1918, we can directly return the day 26.09.1918
• otherwise we can check if the year is leap. In this case we return 12.09 and the year
• if the year is not leap, we just return 13.09 and the year

To determine if a year is leap, we have to apply either the Julian - if the year is less than 1918 - or the Gregorian rule - otherwise.

Here is an implementation in C++:

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31  bool isLeapGregorian(int year) { return year%400 == 0 || (year%4==0 && year%100!=0); } bool isLeapJulian(int year) { return year%4==0; } bool isLeap(int year) { return year < 1918 ? isLeapJulian(year) : isLeapGregorian(year); } string dayOfProgrammer(int year) { if (year == 1918) return "26.09.1918"; if (isLeap(year)) return string("12.09.") + to_string(year); return string("13.09.") + to_string(year); } int main() { int year; cin >> year; cout << dayOfProgrammer(year); } 

An alternative solution consists in calculating the number of days in February:

  1 2 3 4 5 6 7 8 9 10 11 12 13 14  // ...other functions are the same as before... bool is1918(int year) { return year == 1918; } int main() { int y; cin >> y; auto daysInFebruary = is1918(y) ? (28-13) : (isLeap(y) ? 29 : 28); int day = 256 - 31 - daysInFebruary - 31 - 30 - 31 - 30 - 31 - 31; printf("%02d.%02d.%04d", day, 9, y); } 

A step forward with this exercise is making the solution a bit more flexible. What if we want to add more rules?

An idea: we put the rules into a vector and we try them in order. The first successful rule just breaks the loop.

Here is a possible implementation using optional:

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33  optional asDefault([[maybe_unused]]int year) { return 28; } optional asLeap(int year) { return isLeap(year) ? optional{29} : nullopt; } optional as1918(int year) { return year == 1918 ? optional{28-13} : nullopt; } int main() { int year = 2016; vector rules = {as1918, asLeap, asDefault}; auto daysInFebruary = 0; for (auto rule : rules) { if (auto res = rule(year); res) { daysInFebruary = *res; break; } } int day = 256 - 31 - daysInFebruary - 31 - 30 - 31 - 30 - 31 - 31; printf("%02d.%02d.%04d", day, 9, year); } 

You can split asLeap. For example:

 1 2 3 4 5 6 7 8 9  optional asLeapJulian(int year) { return (year < 1918 && year%4 == 0) ? optional{29} : nullopt; } optional asLeapGregorian(int year) { return (year > 1918 && (year%400 == 0 || (year%4==0 && year%100!=0))) ? optional{29} : nullopt; } 

The rules are just pointer to functions. Note that thanks to automatic deduction of class templates (since C++17) we can omit tedious details about the type of vector.

We've worked on this challenge in these gyms: modena