p0019_s0.c

problem 19 · 48 lines

/* Solution to Euler Problem 19: Counting Sundays. */
#include "runner.h"

/* Gregorian leap-year rule: divisible by 4, but century years only if divisible by 400. */
static int is_leap_year(int year) {
    return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
}

/* Days in a given month (1-based), with the leap-year correction for February. */
static int days_in_month(int year, int month) {
    int days[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    if (month == 2 && is_leap_year(year)) return 29;
    return days[month - 1];
}

const char *solve(int argc, char *argv[]) {
    static char _answer[32];
    int end_year   = parse_int(argv[1]);
    int start_year = parse_int(argv[2]);

    /* Count days from 1 Jan 1900 (Monday = 1) to 1 Jan start_year,
     * then iterate over each first-of-month in [start_year, end_year]
     * checking if it's a Sunday (day_of_week == 0, where Monday=1..Sunday=7).
     * We use 0-based: Monday=0, ..., Sunday=6. */

    /* Compute day of week for 1 Jan 1900: Monday = 0 */
    int dow = 0; /* Monday */

    /* Advance from 1 Jan 1900 to 1 Jan start_year */
    for (int y = 1900; y < start_year; y++) {
        dow = (dow + (is_leap_year(y) ? 366 : 365)) % 7;
    }

    long long count = 0;

    for (int y = start_year; y <= end_year; y++) {
        for (int m = 1; m <= 12; m++) {
            /* dow is the day of week for the 1st of this month/year */
            /* Sunday = 6 (Monday=0, Tuesday=1, ..., Sunday=6) */
            if (dow == 6) count++;
            /* Advance by days in this month */
            dow = (dow + days_in_month(y, m)) % 7;
        }
    }

    { snprintf(_answer, sizeof _answer, "%lld", (long long)(count)); return _answer; }
}