Life Goes On

まあまあだけど楽しんでる方です

109問目

http://projecteuler.net/index.php?section=problems&id=109
ダーツで、100 未満の得点でチェックアウトできる場合の数を求める。3 投以下で、最後は Double で終わらないといけない。1 投目と 2 投目は入れ替わっても同じとみなす。
1 投目と 2 投目が同じだったときの扱いがちょっと面倒だけど、あとは素直に。

main = print $ euler109 100

euler109 :: Integer -> Integer
euler109 n = sum [ combination |
    total <- [2..n-1],
    s3 <- [2,4..40] ++ [50],
    s2 <- [0..div (total-s3) 2],
    let s1 = total-s3-s2,
    let c1 = count s1, let c2 = count s2,
    let combination = if s1 /= s2 then c1*c2 else div (c1*(c1+1)) 2 ]

count :: Integer -> Integer
count 0 = 1
count s = single + double + treble
     where single = if (s > 0 && s <= 20) || s == 25 then 1 else 0
           double = if r2 == 0 && (q2 > 0 && q2 <= 20 || q2 == 25) then 1 else 0
           treble = if r3 == 0 && (q3 > 0 && q3 <= 20) then 1 else 0
           (q2, r2) = divMod s 2
           (q3, r3) = divMod s 3