December 30, 2008

You are given the following information, but you may prefer to do some research for yourself.

* 1 Jan 1900 was a Monday.
* Thirty days has September,
April, June and November.
All the rest have thirty-one,
Saving February alone,
Which has twenty-eight, rain or shine.
And on leap years, twenty-nine.
* A leap year occurs on any year evenly divisible by 4, but not on a century unless it is divisible by 400.

How many Sundays fell on the first of the month during the twentieth century (1 Jan 1901 to 31 Dec 2000)?

(defconstant +months+ '("Jan" "Feb" "Mar" "April" "May" "June"
"July" "Aug" "Sept" "Oct" "Nov" "Dec"))

(defconstant +days+ '("Sun" "Mon" "Tue" "Wed" "Thurs" "Fri" "Sat"))

(defun days-in-month (month year)
"Returns the number of days in the month given the month and year"
(cond ((member month '("Sept" "April" "June" "Nov") :test #'string=)
((and (string= "Feb" month) (zerop (mod year 4))) 29)
((string= "Feb" month) 28)
(t 31)))

(defun move-ahead (today days)
"Moves ahead a number of days and returns the day.
Example: (move-ahead 'Mon' 3) => 'Thurs'
(move-ahead 'Sun' 8) => 'Mon'"
(let ((cur-day-num (position today +days+ :test #'string=)))
(elt +days+ (mod (+ cur-day-num days) 7))))

(defun euler-19 ()
(let ((today "Mon")
(result 0))
(loop for year from 1900 to 2000 do
(dolist (month +months+)
(when (and (string= today "Sun") (> year 1900))
(incf result))
(setf today (move-ahead today (days-in-month month year)))))