Advertisement
bss03

Advent of Code 2020 Day 14

Dec 14th, 2020
1,418
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. {-# language RecordWildCards #-}
  2.  
  3. import Control.Arrow ((&&&))
  4. import Control.Foldl (Fold(Fold), fold)
  5. import Data.Bits (complement, zeroBits, shift, setBit, clearBit, (.|.), (.&.))
  6. import Data.Char (isDigit)
  7. import Data.IntMap (IntMap)
  8. import qualified Data.IntMap as IM
  9. import Data.Maybe (listToMaybe)
  10.  
  11. data Mask = MkMask { clearBits :: Int, setBits :: Int } deriving (Eq, Show)
  12. data Write = MkWrite { location :: Int, value :: Int } deriving (Eq, Show)
  13. data Instruction = WriteInstr Write | MaskInstr Mask deriving (Eq, Show)
  14.  
  15. readMay :: Read a => String -> Maybe a
  16. readMay = fmap fst . listToMaybe . reads
  17.  
  18. parseMask :: String -> Mask
  19. parseMask s = MkMask{..}
  20.  where
  21.   (clearBits, setBits) = fold ((,) <$> clearFold <*> setFold) s
  22.   clearFold = Fold updClear (complement zeroBits) id
  23.   setFold = Fold updSet zeroBits id
  24.   updClear m c = shiftIn ('0' /= c) m
  25.   updSet m c = shiftIn ('1' == c) m
  26.   shiftIn True = flip setBit 0 . flip shift 1
  27.   shiftIn False = flip shift 1
  28.  
  29. parseLine :: String -> Maybe Instruction
  30. parseLine ('m':'a':_:_:_:_:_:maskStr) = pure . MaskInstr $ parseMask maskStr
  31. parseLine ('m':'e':_:_:memStr) = WriteInstr <$> do
  32.   location <- readMay locStr
  33.   value <- readMay valStr
  34.   return MkWrite{..}
  35.  where
  36.   (locStr, rest) = span isDigit memStr
  37.   valStr = drop 4 rest
  38. parseLine _ = Nothing
  39.  
  40. common :: String -> [String]
  41. common = lines
  42.  
  43. data ProgramState = MkProgState { mask :: Mask, mem :: IntMap Int } deriving (Eq, Show)
  44.  
  45. initProgState :: ProgramState
  46. initProgState =
  47.   MkProgState
  48.   { mask = MkMask { clearBits = complement zeroBits, setBits = zeroBits }
  49.   , mem = IM.empty
  50.   }
  51.  
  52. setMask :: Mask -> ProgramState -> ProgramState
  53. setMask m s = s{ mask = m }
  54.  
  55. writeMem :: Int -> Int -> IntMap Int -> IntMap Int
  56. writeMem loc 0 = IM.update (const Nothing) loc
  57. writeMem loc val = IM.insert loc val
  58.  
  59. write :: Write -> ProgramState -> ProgramState
  60. write MkWrite{..} s =
  61.   s{ mem = writeMem location (setBits curMask .|. (clearBits curMask .&. value)) (mem s) }
  62.  where curMask = mask s
  63.  
  64. applyInstruction :: Instruction -> ProgramState -> ProgramState
  65. applyInstruction (WriteInstr w) = write w
  66. applyInstruction (MaskInstr m) = setMask m
  67.  
  68. runProgram :: [Instruction] -> ProgramState
  69. runProgram = fold (Fold (flip applyInstruction) initProgState id)
  70.  
  71. part1 :: [String] -> Maybe Int
  72. part1 = fmap (sum . mem . runProgram) . traverse parseLine
  73.  
  74. data MaskBit = Unchanged | Overwritten | Floating deriving (Eq, Show)
  75. type Mask2 = [MaskBit]
  76. data Instruction2 = WriteInstr2 Write | MaskInstr2 Mask2 deriving (Eq, Show)
  77.  
  78. parseMaskBit :: Char -> Maybe MaskBit
  79. parseMaskBit '0' = pure Unchanged
  80. parseMaskBit '1' = pure Overwritten
  81. parseMaskBit 'X' = pure Floating
  82. parseMaskBit _ = Nothing
  83.  
  84. parseMask2 :: String -> Maybe Mask2
  85. parseMask2 = traverse parseMaskBit
  86.  
  87. parseLine2 :: String -> Maybe Instruction2
  88. parseLine2 ('m':'a':_:_:_:_:_:maskStr) = MaskInstr2 <$> parseMask2 maskStr
  89. parseLine2 ('m':'e':_:_:memStr) = WriteInstr2 <$> do
  90.   location <- readMay locStr
  91.   value <- readMay valStr
  92.   return MkWrite{..}
  93.  where
  94.   (locStr, rest) = span isDigit memStr
  95.   valStr = drop 4 rest
  96. parseLine2 _ = Nothing
  97.  
  98. data ProgramState2 = MkProgState2 { mask2 :: Mask2, mem2 :: IntMap Int } deriving (Eq, Show)
  99.  
  100. initProgState2 :: ProgramState2
  101. initProgState2 =
  102.   MkProgState2
  103.   { mask2 = []
  104.   , mem2 = IM.empty
  105.   }
  106.  
  107. decodeMem :: Mask2 -> Int -> [Int]
  108. decodeMem mbs i = snd $ foldr upd (0,[i]) mbs
  109.  where
  110.   upd Unchanged (n, is) = (succ n, is)
  111.   upd Overwritten (n, is) = (succ n, map (flip setBit n) is)
  112.   upd Floating (n, is) = (succ n, map (flip setBit n) is ++ map (flip clearBit n) is)
  113.  
  114. setMask2 :: Mask2 -> ProgramState2 -> ProgramState2
  115. setMask2 m s = s{ mask2 = m }
  116.  
  117. write2 :: Write -> ProgramState2 -> ProgramState2
  118. write2 MkWrite{..} s =
  119.   s{ mem2 = foldr (\l -> writeMem l value) (mem2 s) $ decodeMem (mask2 s) location }
  120.  
  121. applyInstruction2 :: Instruction2 -> ProgramState2 -> ProgramState2
  122. applyInstruction2 (WriteInstr2 w) = write2 w
  123. applyInstruction2 (MaskInstr2 m) = setMask2 m
  124.  
  125. runProgram2 :: [Instruction2] -> ProgramState2
  126. runProgram2 = fold (Fold (flip applyInstruction2) initProgState2 id)
  127.  
  128. part2 :: [String] -> Maybe Int
  129. part2 = fmap (sum . mem2 . runProgram2) . traverse parseLine2
  130.  
  131. interactive :: Show a => (String -> a) -> IO ()
  132. interactive f = getContents >>= print . f
  133.  
  134. main :: IO ()
  135. main = interactive ((part1 &&& part2) . common)
  136.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement