Merge branch 'master' of git.martlubbers.net:aoc20
[aoc20.git] / 14 / one.icl
diff --git a/14/one.icl b/14/one.icl
new file mode 100644 (file)
index 0000000..ceb0b18
--- /dev/null
@@ -0,0 +1,67 @@
+module one
+
+import StdEnv
+import Text
+import Data.Func
+import Data.List
+from Data.Map import :: Map(..)
+import qualified Data.Map as DM
+
+read :: *File -> [Char]
+read f
+       # (ok, c, f) = freadc f
+       | not ok = []
+       = [c:read f]
+
+Start w
+       # (io, w) = stdio w
+       # ls = split ['\n'] $ read io
+       = ( sum $ 'DM'.elems $ one [] ls 'DM'.newMap
+         , sum $ 'DM'.elems $ two [] ls 'DM'.newMap
+         )
+
+toBin :: (Int -> [Char])
+toBin = tob [35,34..0]
+where
+       tob [b:bs] n
+               | n >= 2^b = ['1':tob bs (n-2^b)]
+                          = ['0':tob bs n]
+       tob [] _ = []
+fromBin :: [Char] -> Int
+fromBin rs= sum [n*2^i\\i<-[35,34..] & n <- map digitToInt rs]
+
+one :: [Char] [[Char]] -> ((Map Int Int) -> Map Int Int)
+one _ [['mask = ':mask]:xs] = one mask xs
+one mask [['mem[':rest]:xs]
+       = case span isDigit rest of
+               (num, ['] = ':rest])
+                       = one mask xs o 'DM'.put (toInt $ toString num)
+                               (fromBin $ zipWith msk mask $ toBin $ toInt $ toString rest)
+where
+       msk :: Char Char -> Char
+       msk '1' _ = '1'
+       msk '0' _ = '0'
+       msk 'X' c = c
+one mask [[]:xs] = one mask xs
+one mask [] = id
+
+two :: [Char] [[Char]] -> ((Map Int Int) -> Map Int Int)
+two _ [['mask = ':mask]:xs] = two mask xs
+two mask [['mem[':rest]:xs]
+       = case span isDigit rest of
+               (addr, ['] = ':val])
+                       = foldl (o) (two mask xs)
+                               [ 'DM'.put (fromBin addr) $ toInt $ toString val
+                               \\addr<-mkAddrs $ zipWith aMask mask $ toBin $ toInt $ toString addr]
+where
+       aMask :: Char Char -> Char
+       aMask 'X' _ = 'X'
+       aMask '1' _ = '1'
+       aMask '0' c = c
+
+       mkAddrs :: [Char] -> [[Char]]
+       mkAddrs ['X':msk] = mkAddrs ['1':msk] ++ mkAddrs ['0':msk]
+       mkAddrs [c:msk] = map (\x->[c:x]) $ mkAddrs msk
+       mkAddrs [] = [[]]
+two mask [[]:xs] = two mask xs
+two mask [] = id