Project Euler - Problem 19

I haven't been to Project Euler in a while, but since I'm seeing other F# folks are getting into it, I figured I'd help work to improve the average F# 'genus rating' on the site. (Currently at 11%.)

The easiest one I haven't already solved is problem 19, which is:

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

While you could use System.DateTime and answer this trivially, I figured I would build my own DateTime type in F#.

To do this I simply used a Record type containing the Month, Day, Year, and DayOfWeek and added a method to 'get the next day'. Though it looks somewhat messy, the code is pretty straight forward. I'll leave it as an exercise to the reader how to use this data type to compute the answer.

type Day =

    {Month : int; Day : int; Year : int; DayOfWeek : int}

    member this.NextDay() =

        let daysInMonth =

            match this.Month with

            // Thirty days has September, April, June, and November...

            | 9 | 4 | 6 | 11 -> 30

            // All the rest have thirty one...

            | 1 | 3 | 5 | 7 | 8 | 10 | 12 -> 31

            // Saving February alone, which gets complicated...

            | 2 ->

                    let mod4, mod100, mod400 = (this.Year % 4) = 0,

                                               (this.Year % 100) = 0,

                                           (this.Year % 400) = 0

                    let daysInFeb =

                        match mod4, mod100, mod400 with

                        // Years not mod 4 or centry markers not mod 400 are normal

    | false, _, _ -> 28

                        | true, true, false -> 28

                        // Any other year mod4 year not mod100 is a leap year

                        // Or, any year mod 400

                        | true, false, _ -> 29

                        | true, _, true -> 29

                    daysInFeb

            | _ -> failwith "invalid month"

        if this.Day < daysInMonth then

            {Month = this.Month;

             Day = this.Day + 1;

             Year = this.Year;

             DayOfWeek = (this.DayOfWeek % 7) + 1}

        else

            {Month = (this.Month % 12) + 1;

             Day = 1;

             Year = if this.Month = 12 then (this.Year + 1) else this.Year;

             DayOfWeek = (this.DayOfWeek % 7) + 1}

 

 

Thanks again to the fine folks at Project Euler for maintaining such a great website!