summaryrefslogtreecommitdiff
path: root/2017/10.hs
blob: 0c962ab693d71046d0f1fa20f1d72f7d6f3bd228 (plain)
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
51
52
53
54
55
56
57
58
59
import Control.Monad
import Data.Bits (xor)
import Data.Char
import Data.List
import Numeric


strip :: String -> String
strip = dropWhile isSpace . reverse . dropWhile isSpace . reverse

splitOn :: Eq a => a -> [a] -> [[a]]
splitOn _ [] = []
splitOn ch str = case break (== ch) str of
    (pre, ch' : post) | ch' == ch -> pre : splitOn ch post
    (pre, _) -> [pre]

rotate :: Int -> [a] -> [a]
rotate num l = take (length l) (drop num (cycle l))

blocks :: Int -> [a] -> [[a]]
blocks _ [] = []
blocks n l = let (pre, post) = splitAt n l in pre : blocks n post

pad :: Int -> a -> [a] -> [a]
pad len x list = replicate (len - length list) x ++ list

tie' :: [a] -> [Int] -> Int -> [a]
tie' chain [] _ = chain
tie' chain (len : lens) skip =
    let (sub, rest) = splitAt len chain
    in tie' (rotate skip (rest ++ reverse sub)) lens (skip + 1)

tie :: [a] -> [Int] -> [a]
tie chain lens =
    let chainlen = length chain
        numlens = length lens
        backnum = chainlen - (sum lens + numlens * (numlens - 1) `div` 2) `mod` chainlen
    in rotate backnum (tie' chain lens 0)

part1 :: IO ()
part1 = do
    let chainlen = 256
    lenlist <- liftM (map read . splitOn ',') (readFile "10.in")

    let result = tie [0..chainlen-1] lenlist

    print (let (a:b:_) = result in a * b)

part2 :: IO ()
part2 = do
    let chainlen = 256
    lenlist <- liftM ((++ [17, 31, 73, 47, 23]) . map ord . strip) (readFile "10.in")

    let sparse = tie [0..chainlen-1] (take (64 * length lenlist) (cycle lenlist))
    let dense = map (foldl1 xor) (blocks 16 sparse) :: [Int]
    putStrLn $ concat $ map (pad 2 '0' . flip showHex "") dense

main :: IO ()
main = part1 >> part2