#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>

bool IsLeapYear(uint16_t year)
{
    if (year % 100 == 0)
    {
        return year % 400 == 0;
    }
    else
    {
        return year % 4 == 0;
    }
}

typedef enum Month
{
    Jan = 0,
    Feb,
    Mar,
    Apr,
    May,
    Jun,
    Jul,
    Aug,
    Sep,
    Oct,
    Nov,
    Dec,
} Month;

uint16_t DaysInMonth(Month month)
{
    switch (month)
    {
        case Jan:
		{
            return 31;
		};

        case Feb:
		{
            return 28; // normally 28, leap year 29, the +1 will be handled else-where.
		};

        case Mar:
		{
            return 31;
		};

        case Apr:
		{
            return 30;
		};

        case May:
		{
            return 31;
		};

        case Jun:
		{
            return 30;
		};

        case Jul:
		{
            return 31;
		};

        case Aug:
		{
            return 31;
		};

        case Sep:
		{
            return 30;
		};

        case Oct:
		{
            return 31;
		};

        case Nov:
		{
            return 30;
		};

        case Dec:
		{
            return 31;
		};

        default:
        {
            fprintf(stderr, "Unknown month: %d\n", month);
        } break;
    }
}

typedef enum Week
{
    Sun = 0,
    Mon,
    Tue,
    Wed,
    Thu,
    Fri,
    Sat,
} Week;


// 1 Jan 1900 was a Monday, so 7 Jan 1900 is a Sunday.
// +7 every seven days is another Sunday.
// Idea: Track the first day of each month.
// From 1 Jan 1901 to 31 Dec 2000, how many first days of a month fell on a Sunday?

void Solve()
{
    uint64_t count = 0;

    Week FirstDayOfEachMonth = Mon;
    for (uint16_t year = 1900; year <= 2000; year++)
    {
        for (Month month = Jan; month <= Dec; month++)
        {
            uint16_t days = DaysInMonth(month);
            if (IsLeapYear(year) && month == Feb)
            {
                days += 1;
            }

            if (year > 1900 && FirstDayOfEachMonth == Sun)
            {
                count += 1;
            }
            FirstDayOfEachMonth = (FirstDayOfEachMonth + (days % 7)) % 7;
        }
    }

    printf("%lu\n", count);
}

int main()
{
    Solve();
    return 0;
}

; sbcl --script 19.lisp
(defun is-leap-year (year)
  (if (= (mod year 100) 0)
    (= (mod year 400) 0)
    (= (mod year 4) 0)))

(defun month-days (month)
  (cond
    ((= month 1) 31)
    ((= month 2) 28); +1 in leap year
    ((= month 3) 31)
    ((= month 4) 30)
    ((= month 5) 31)
    ((= month 6) 30)
    ((= month 7) 31)
    ((= month 8) 31)
    ((= month 9) 30)
    ((= month 10) 31)
    ((= month 11) 30)
    ((= month 12) 31)))

(defvar *count* 0)
(defvar *start-day-of-the-month* 0); 0 - Sun, 1 - Mon, ..., 6 - Sat

(defun Counting-Sundays ()
  (do ((year 1900 (+ year 1)))
      ((= year 2001))
    (do ((month 1 (+ month 1)))
        ((= month 13))
      (let ((days (month-days month)))
        (when (= month 2) (incf days 1))
        (when (and (> year 1900) (= *start-day-of-the-month* 0)) (incf *count* 1))
        (setf *start-day-of-the-month* (mod (+ *start-day-of-the-month* (mod days 7)) 7)))))
  (format t "~A~%" *count*))

(Counting-Sundays)