22
[aoc20.git] / 14 / one.icl
1 module one
2
3 import StdEnv
4 import Text
5 import Data.Func
6 import Data.List
7 from Data.Map import :: Map(..)
8 import qualified Data.Map as DM
9
10 read :: *File -> [Char]
11 read f
12 # (ok, c, f) = freadc f
13 | not ok = []
14 = [c:read f]
15
16 Start w
17 # (io, w) = stdio w
18 # ls = split ['\n'] $ read io
19 = ( sum $ 'DM'.elems $ one [] ls 'DM'.newMap
20 , sum $ 'DM'.elems $ two [] ls 'DM'.newMap
21 )
22
23 toBin :: (Int -> [Char])
24 toBin = tob [35,34..0]
25 where
26 tob [b:bs] n
27 | n >= 2^b = ['1':tob bs (n-2^b)]
28 = ['0':tob bs n]
29 tob [] _ = []
30 fromBin :: [Char] -> Int
31 fromBin rs= sum [n*2^i\\i<-[35,34..] & n <- map digitToInt rs]
32
33 one :: [Char] [[Char]] -> ((Map Int Int) -> Map Int Int)
34 one _ [['mask = ':mask]:xs] = one mask xs
35 one mask [['mem[':rest]:xs]
36 = case span isDigit rest of
37 (num, ['] = ':rest])
38 = one mask xs o 'DM'.put (toInt $ toString num)
39 (fromBin $ zipWith msk mask $ toBin $ toInt $ toString rest)
40 where
41 msk :: Char Char -> Char
42 msk '1' _ = '1'
43 msk '0' _ = '0'
44 msk 'X' c = c
45 one mask [[]:xs] = one mask xs
46 one mask [] = id
47
48 two :: [Char] [[Char]] -> ((Map Int Int) -> Map Int Int)
49 two _ [['mask = ':mask]:xs] = two mask xs
50 two mask [['mem[':rest]:xs]
51 = case span isDigit rest of
52 (addr, ['] = ':val])
53 = foldl (o) (two mask xs)
54 [ 'DM'.put (fromBin addr) $ toInt $ toString val
55 \\addr<-mkAddrs $ zipWith aMask mask $ toBin $ toInt $ toString addr]
56 where
57 aMask :: Char Char -> Char
58 aMask 'X' _ = 'X'
59 aMask '1' _ = '1'
60 aMask '0' c = c
61
62 mkAddrs :: [Char] -> [[Char]]
63 mkAddrs ['X':msk] = mkAddrs ['1':msk] ++ mkAddrs ['0':msk]
64 mkAddrs [c:msk] = map (\x->[c:x]) $ mkAddrs msk
65 mkAddrs [] = [[]]
66 two mask [[]:xs] = two mask xs
67 two mask [] = id