Broke days into individual pacakges
[advent-of-code-16.git] / adventofcode1614 / app / advent14c.hs
1 module Main(main) where
2
3 import Data.List (nub, tails)
4 import Data.ByteString.Char8 (pack)
5 import Crypto.Hash (hash, Digest, MD5)
6
7 salt = "yjdafjpo"
8 -- salt = "abc"
9
10 main :: IO ()
11 main = do
12 part1
13 part2
14
15 part1 :: IO ()
16 part1 = print $ head $ drop 63 $ filter (\i -> possibleKey sq i && confirmKey sq i) [0..]
17 where sq = md5sequence
18
19 part2 :: IO ()
20 part2 = print $ head $ drop 63 $ filter (\i -> possibleKey sq i && confirmKey sq i) [0..]
21 where sq = md5sequenceS
22
23 getHash :: String -> String
24 getHash bs = show (hash $ pack bs :: Digest MD5)
25
26 md5sequence :: [String]
27 md5sequence = [makeMd5 i | i <- [0..]]
28 where makeMd5 i = getHash (salt ++ show i)
29
30 md5sequenceS :: [String]
31 md5sequenceS = [makeMd5 i | i <- [0..]]
32 where makeMd5 i = stretch $ getHash (salt ++ show i)
33 stretch h0 = foldr (\_ h -> getHash h) h0 [1..2016]
34
35 possibleKey :: [String] -> Int-> Bool
36 possibleKey s = not . null . repeats 3 . ((!!) s)
37
38 confirmKey :: [String] -> Int -> Bool
39 confirmKey s i = any (confirmation) $ take 1000 $ drop (i+1) s
40 where c = head $ repeats 3 $ s!!i
41 confirmation m = c `elem` (repeats 5 m)
42
43 repeats :: Int -> String -> [String]
44 repeats n = filter (null . tail) . map (nub) . substrings n
45
46 substrings :: Int -> [a] -> [[a]]
47 substrings l = filter (\s -> (length s) == l) . map (take l) . tails