Analysis for bday

by Rob Kolstad

Writing contest solutions differs greatly from writing computer programs to be used in a production environment (like MSWord or Doom). The goal is to write a program that solves the problem, runs in the time limit, and with any luck runs first time.

This problem gave us the lengths of the months, saving a bit of research, though it didn't tell us that January 1, 1800 was a Wednesday. That simplifies the program a bit. The first thing to code is the leap year function: it yields true (=1)if a year is a leap year ( see the code below).

Then, it's a simple matter to count through the years and months adding to a counter whose mod 7 value is the day number. It doesn't matter which value we choose as '0'; many students chose "monday".

Thus the program:

The program works the first time because no given step is complex at all. If it didn't work first time, it would be easy to debug since it successively hones in on the proper answer. Testing it with a dozen test cases by hand would verify its correctness to a great level. If one were obsessive, testing 400 years of test cases would not take long and would be easily verifiable.

#include <stdio.h>
char *daynames[7] = {"monday", "tuesday", "wednesday", "thursday",
		     "friday", "saturday", "sunday"};
int monthdays[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

int leapyear(yr) {
    int leap = (yr%4) == 0;
    if ((yr%100) == 0) leap = 0;
    if ((yr%400) == 0) leap = 1;
    return leap;
}

int main() {
    int y, m, d, i, j, day;
    freopen("bday.in", "r", stdin);
    freopen("bday.out", "w", stdout);
    day = 2;			/* 1/1/1800 = 2 */
    scanf("%d %d %d", &y, &m, &d);
    for (i = 1800; i < y; i++) 
	day += 365 + leapyear (i);
    if (leapyear (y)) monthdays[1]++;
    for (i = 0; i < m-1; i++)
	day += monthdays[i];
    day += d-1;
    printf ("%s\n", daynames[day%7]);
    exit (0);
}

Other solutions are below.

Sample bday solutions

Here is Poland junior Tomasz Kulczynski's C++ solution for bday:

#include <cstdio>
using namespace std;

int main() {
    freopen("bday.in", "r", stdin);
    freopen("bday.out", "w", stdout);
    int x, y, m, d, i, mies[13] = {0, 0, 31, 59, 90, 120, 151, 181,
    					212, 243, 273, 304, 334};
    char s[7][20] = {"monday", "tuesday", "wednesday", "thursday",
    				"friday", "saturday", "sunday"};
    scanf("%d %d %d", &y, &m, &d);
    x = 0;
    if (y < 1900) {
        for (i = y; i < 1900; i++)
            x = (x+700-365-((i%4 || (!(i%100) && i%400))?0:1))%7;
    } else {
        for (i = 1900; i < y; i++)
            x = (x + 365 + ((i%4 || (!(i%100) && i%400))?0:1))%7;
    }
    x += mies[m] + d - 1 + ((y%4 || (!(y%100) && y%400) || m<3)?0:1);
    printf ("%s\n", s[x%7]);
    return 0;
}

This is USA sophomore Robert Mitchell Burke's Java solution for bday:

import java.io.*;
import java.util.*;

public class bday {
    public static void main(String[] NEVAR_USE_THIS_VARIABLE353512) throws Throwable {
        BufferedReader in = new BufferedReader(new FileReader("bday.in"));
        PrintWriter out = new PrintWriter("bday.out");

        int[] normalL = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, 
              leapL   = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
        int year=1900, day=0, month=0, dayOfWeek=0;
        String[] sa = in.readLine().split("\\s");
        int oYear = Integer.parseInt(sa[0]),oMonth=Integer.parseInt(sa[1])-1,
            oDay = Integer.parseInt(sa[2])-1;
        while (year < oYear) {
            dayOfWeek = (dayOfWeek + 365) % 7;
            if (isLeap (year))
                dayOfWeek = (dayOfWeek+1)%7;
            year++;
        }
        while (year> oYear) {
            dayOfWeek = (((dayOfWeek-365)%7)+7)%7;
            if (isLeap(year-1))
                dayOfWeek=(((dayOfWeek-1)%7)+7)%7;
            year--;
        }
        //We are now at January 1 on the correct year.
        while (month<oMonth)
            dayOfWeek = (dayOfWeek + (isLeap(year) ? leapL[month++] : normalL[month++])) % 7;
        dayOfWeek = (dayOfWeek + oDay)%7;
	out.println (new String[]{"monday", "tuesday", "wednesday",
				"thursday", "friday", "saturday", "sunday"}[dayOfWeek]);
        out.close ();
        System.exit (0);
    }
    static boolean isLeap (int year) {
        return (year%400==0) || (year%100!=0&&year%4==0);
    }
}

Here is Poland's junior Tomasz Roda's Pascal solution for bday:

const dzien:    array[0..6]of String=('monday','tuesday', 'wednesday',
	  'thursday', 'friday', 'saturday', 'sunday');

      miesiac: array[0..11] of Integer=(0, 31, 59, 90, 120, 151,
                                       181, 212, 243, 273, 304, 334);

var zb:         Text;
    d, m, r, x: Longint;
    s:          Longint;
begin
  Assign(zb, 'bday.in'); Reset(zb);
  Readln(zb, r, m, d);
  Close(zb);
  Assign(zb,'bday.out'); Rewrite(zb);
  s := 1;
  inc (s, (r-1800)*365);
  inc (s, (r-1800) div 4 + 1);
  dec (s, (r-1800) div 100 + 1);
  if r >= 2000 then inc(s,(r-2000) div 400 + 1);
  inc (s, miesiac[m-1]);
  inc (s, d);
  if (m<3) and (r mod 4 = 0) and (not(r mod 100 = 0) or (r mod 400 = 0)) then
    dec(s);
  Writeln(zb, dzien[s mod 7]);
  Close(zb);
end.