challenge LL Golf Hole 3 - 13日の金曜日を数え上げる

今日から2013年12月31日までの、13日の金曜日とその総数を表示してください。

余力のあるものはこのプログラムを短くしてみたり、短くしてみたり、短くしてください。

※LL Future実行委員の高野光弘です。この出題は LL Future公式の出題であり、優れたものについてはLL Golfのセッションでご紹介させていただくかもしれません。ご理解の上、ご投稿ください。また、LL Futureのチケットは現在も発売中です。よろしければ、メインイベントの方にもぜひご参加ください。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
#!/usr/bin/env ruby
require 'date'

from = DateTime.now
to = DateTime.parse("2013-12-31")

friday = (from..to).inject(0) do |friday, date|
    if date.mday == 13 and date.wday == 5 then
        puts date.strftime('%Y-%m-%d')
        friday + 1
    else
        friday
    end
end

puts friday

Posted feedbacks - Haskell

愚直なつくりをしています。
*Main> :main
(10,[2009-02-13,2009-03-13,2009-11-13,2010-08-13,2011-05-13,2012-01-13,2012-04-13,2012-07-13,2013-09-13,2013-12-13])
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
module Main where

import Data.Time
import Data.Time.Calendar.WeekDate
import Control.Arrow

getCurrentZonedTime :: a -> IO ZonedTime
getCurrentZonedTime = (const getCurrentTimeZone &&& const getCurrentTime)
         >>> joinTuple 
         >>> (=<<) (return . uncurry utcToZonedTime)
  where joinTuple :: Monad m => (m a, m b) -> m (a, b)
        joinTuple (x,y) = do { x' <- x; y' <- y; return (x',y') }

check :: Day -> Bool
check day = thirteen && friday
  where thirteen = "31" == (take 2 $ reverse $ show day)
        friday = case toWeekDate day of (_,_,5) -> True; _ -> False                                                     

friday13s lst = Kleisli getCurrentZonedTime 
              >>> arr (localDay . zonedTimeToLocalTime)
              >>> arr (flip enumFromTo lst)
              >>> arr (filter check)
              >>> arr (length &&& id) >>> Kleisli print

main = runKleisli (friday13s (read "2013-12-31")) ()

方法は、各年の全月の13日が金曜日か調べるだけです。
が、目的の日付の曜日を調べる手軽な手段を見つけられなかったので、
ClockTime と CalendarTime を相互変換して、
 曜日を得るために addToClockTime すると言う、なんか変な事になっています。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
module Main (main) where
import Time
import Control.Monad
import System.IO.Unsafe

crossProduct :: [a] -> [b]-> [(a,b)]
crossProduct = liftM2 p
    where
        p x y = (x,y)

isJason :: (Int,Int) -> Bool
isJason (year,month) = week == Friday
    where
        mon = toEnum (month-1) :: Month
        clock = toClockTime $ CalendarTime year mon 13 0 0 0 0 Sunday 0 "JST" 9 False
        time = addToClockTime (TimeDiff 0 0 0 0 0 0 0) clock
        week = ctWDay $ unsafePerformIO $ toCalendarTime time

isAfter :: CalendarTime -> (Int,Int) -> Bool
isAfter cal (year,month) =
    year > ctYear cal || month > (fromEnum $ ctMonth cal) || 13 <= ctDay cal

main :: IO ()
main = do
    time <- getClockTime
    cal <- toCalendarTime time
    putStrLn $ show $
        filter (isAfter cal) $
        filter (isJason) $ crossProduct [(ctYear cal)..2013] [1..12]

今日の日付の取得の仕方があやしいです。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
import Data.Time
import Data.Time.Calendar.OrdinalDate

isFriday d =
  case sundayStartWeek d of
    (_, 5)    -> True
    otherwise -> False

main = do
  today <- getZonedTime >>= \ zt -> (return.localDay.zonedTimeToLocalTime) zt
  let fridays = filter isFriday $ filter (today <=) [fromGregorian y m 13 | y <- [2008..2013], m <-[1..12]]
  mapM_ (putStrLn.show) fridays
  putStrLn $ (show $ length fridays) ++ " days"

あまり無駄にArrowを使わないで欲しいです…

1
getCurrentZonedTime = liftM2 utcToZonedTime getCurrentTimeZone getCurrentTime

Index

Feed

Other

Link

Pathtraq

loading...