-
Notifications
You must be signed in to change notification settings - Fork 1
/
Day4.hs
50 lines (38 loc) · 1.52 KB
/
Day4.hs
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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
module Day4 where
import Data.List
-- General purpose reverse digitizer
digitsR :: Integral a => a -> [a]
digitsR = fmap snd
. takeWhile (/= (0, 0))
. iterate (divMod10 . fst)
. divMod10
where divMod10 = flip divMod 10
-- We'll work with reverse digit arrays
-- so we check for non-increasing order
isNonIncr :: [Int] -> Bool
isNonIncr lst = all (\(a, b) -> a >= b) $ zip lst (tail lst)
hasDouble :: [Int] -> Bool
hasDouble lst = any (\(a, b) -> a == b) $ zip lst (tail lst)
isGood :: Int -> Bool
isGood n = isNonIncr ds && hasDouble ds
where ds = digitsR n
-- fromEnum turns False to 0 and True to 1
countPasswds :: Int -> Int -> Int
countPasswds from to = sum $ fmap (fromEnum . isGood) [from .. to]
-- Chunk digits of a 6-digit number into groups of 4
-- after putting sentinel non-digits on both sides
chunk64 :: Int -> [[Int]]
chunk64 = fmap (take 4) . take 5 . tails . bracket10
where -- put (non-digit) 10 on both sides of the digit array as sentinels
bracket10 n = 10 : digitsR n ++ [10]
-- Two equal digits surrounded by other digits (or sentinels)
isPureDouble (a:b:c:d:[]) = a /= b && b == c && c /= d
isPureDouble x = error $ show x ++ "is not a four-letter word!"
hasPureDoubles :: Int -> Bool
hasPureDoubles n = or $ fmap isPureDouble $ chunk64 n
countPasswds' :: Int -> Int -> Int
countPasswds' from to = sum $ fmap isGood' [from .. to]
where isGood' n = fromEnum (isGood n && hasPureDoubles n)
main = do
print $ countPasswds 264793 803935
print $ countPasswds' 264793 803935