/* Five weekends problem (Rosetta code) in Picat. http://rosettacode.org/wiki/Five_weekends """ The month of October in 2010 has five Fridays, five Saturdays, and five Sundays. Task - Write a program to show all months that have this same characteristic of five full weekends from the year 1900 through 2100 (Gregorian calendar). - Show the number of months with this property (there should be 201). - Show at least the first and last five dates, in order. Algorithm suggestions - Count the number of Fridays, Saturdays, and Sundays in every month. - Find all of the 31-day months that begin on Friday. Extra credit Count and/or show all of the years which do not have at least one five-weekend month (there should be 29). """ This Picat model was created by Hakan Kjellerstrand, hakank@gmail.com See also my Picat page: http://www.hakank.org/picat/ */ import util. main => go. % % First approach % go ?=> FiveWeekends = [], NoHitYears = [], foreach(Year in 1900..2100) Hits = 0, foreach(Month in 1..12) Days = max_days_in_month(Year,Month), Dows = [dow(Year,Month,Day) : Day in 1..Days], All = findall([From,To], find(Dows,[5,6,0],From,To)), if All.len >= 5 then FiveWeekends := FiveWeekends ++ [[Year,Month]], Hits := Hits + 1 end end, if Hits == 0 then NoHitYears := NoHitYears ++ [Year] end end, println(fiveWeekends=FiveWeekends), println(len=FiveWeekends.len), nl, % Extra credit println(noHitYears=NoHitYears), println(len=NoHitYears.len), nl. go => true. % % Alternative approach: Count the number of 31 days months that start on Friday. % go2 ?=> FiveWeekends = [], NoHitYears = [], foreach(Year in 1900..2100) Hits = 0, % 31 days months foreach(Month in [1,3,5,7,8,10,12]) if dow(Year,Month,1) == 5 then FiveWeekends := FiveWeekends ++ [[Year,Month]], Hits := Hits + 1 end end, if Hits == 0 then NoHitYears := NoHitYears ++ [Year] end end, println(fiveWeekends=FiveWeekends), println(len=FiveWeekends.len), nl, println(noHitYears=NoHitYears), println(len=NoHitYears.len), nl. go2 => true. % % List comprehension approach of alternative approach % go3 ?=> println("Months with five weekends:"), FiveWeekends = [ [Year,Month] : Year in 1900..2100, Month in [1,3,5,7,8,10,12], dow(Year,Month,1) == 5], WLen = FiveWeekends.len, println(take(FiveWeekends,5)), println("..."), println(drop(FiveWeekends,WLen-5)), println(len=WLen), nl, println("Years w/o five weekends:"), FiveWeekendYears = [Year : [Year,_] in FiveWeekends].remove_dups, NoHitYears = [Year : Year in 1900..2100, not member(Year,FiveWeekendYears)], NHLen = NoHitYears.len, println(take(NoHitYears,5)), println("..."), println(drop(NoHitYears,NHLen-5)), println(len=NHLen), nl. go3 => true. % % Day of week, Sakamoto's method % http://en.wikipedia.org/wiki/Weekday_determination#Sakamoto.27s_Method % dow(Y, M, D) = R => T = [0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4], if M < 3 then Y := Y - 1 end, R = (Y + Y // 4 - Y // 100 + Y // 400 + T[M] + D) mod 7. % Days in a month. max_days_in_month(Year,Month) = Days => if member(Month, [1,3,5,7,8,10,12]) then Days = 31 elseif member(Month,[4,6,9,11]) then Days = 30 else if leap_year(Year) then Days = 29 else Days = 28 end end. leap_year(Year) => (Year mod 4 == 0, Year mod 100 != 0) ; Year mod 400 == 0.