Advertisement
bss03

Advent of Code 2020 Day 8

Dec 8th, 2020
2,204
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. {-# language TupleSections #-}
  2. {-# language RecordWildCards #-}
  3.  
  4. import Control.Applicative ((<|>))
  5. import Control.Monad ((<=<))
  6. import Data.Bool (bool)
  7. import Data.List.NonEmpty (NonEmpty((:|)), nonEmpty)
  8. import qualified Data.List.NonEmpty as NE
  9. import Data.Maybe (listToMaybe)
  10.  
  11. data Instruction
  12.   = Nop !Int
  13.   | Acc !Int
  14.   | Jmp !Int
  15.   deriving (Eq, Show)
  16.  
  17. parseInstruction :: String -> Maybe Instruction
  18. parseInstruction s =
  19.   case splitAt 3 s of
  20.    (op, _:s:n) -> parseOp op <*> parseNum s n
  21.    _ -> Nothing
  22.  where
  23.   parseOp "nop" = Just Nop
  24.   parseOp "acc" = Just Acc
  25.   parseOp "jmp" = Just Jmp
  26.   parseOp _ = Nothing
  27.   parseNum '+' n = fmap fst . listToMaybe $ reads n
  28.   parseNum '-' n = fmap (negate . fst) . listToMaybe $ reads n
  29.   parseNum _ _ = Nothing
  30.  
  31. data Console a = MkConsole
  32.   { accumulator :: !Int
  33.   , rPast :: [(Instruction, a)]
  34.   , ip :: !(Instruction, a)
  35.   , future :: [(Instruction, a)]
  36.   } deriving (Eq, Show)
  37.  
  38. initConsole :: a -> NonEmpty Instruction -> Console a
  39. initConsole x (h:|t) =
  40.   MkConsole
  41.   { accumulator = 0
  42.   , rPast = []
  43.   , ip = (h, x)
  44.   , future = map (,x) t
  45.   }
  46.  
  47. stepConsole :: (a -> Maybe a) -> Console a -> Either a (Either Int (Console a))
  48. stepConsole f c@MkConsole{..} =
  49.   case f $ snd ip of
  50.    Nothing -> Left $ snd ip
  51.    Just x ->
  52.     Right $ case fst ip of
  53.      Nop _ ->
  54.       case future of
  55.        [] -> Left accumulator
  56.        (ip':future') -> Right c{ rPast = (fst ip, x) : rPast, ip = ip', future = future' }
  57.      Acc d -> let accumulator' = accumulator + d in
  58.      case future of
  59.       [] -> Left accumulator'
  60.        (ip':future') ->
  61.         Right c
  62.         { accumulator = accumulator'
  63.        , rPast = (fst ip, x) : rPast
  64.        , ip = ip'
  65.         , future = future'
  66.        }
  67.     Jmp o ->
  68.      case compare o 0 of
  69.       LT ->
  70.        let
  71.          o' = abs o
  72.           (iPast, tPast) = splitAt o' rPast
  73.          (ip':future') = reverse iPast ++ (fst ip, x) : future
  74.         in
  75.        case reverse iPast ++ (fst ip, x) : future of
  76.         [] -> Left accumulator
  77.         (ip':future') -> Right c{ rPast = tPast, ip = ip', future = future' }
  78.       EQ -> Right c{ ip = (fst ip, x) }
  79.       GT -> let (iFuture, tFuture) = splitAt o ((fst ip, x) : future) in
  80.        case tFuture of
  81.         [] -> Left accumulator
  82.         (ip':future') -> Right c{ rPast = reverse iFuture ++ rPast, ip = ip', future = future' }
  83.  
  84. runConsole :: Console Bool -> Int
  85. runConsole c =
  86.  case stepConsole (bool (Just True) Nothing) c of
  87.   Left _ -> accumulator c
  88.   Right (Left x) -> x
  89.   Right (Right c') -> runConsole c'
  90.  
  91. testConsole :: Console Bool -> Maybe Int
  92. testConsole = testConsole' False
  93.  where
  94.   testConsole' False c =
  95.    case ip c of
  96.     (Nop x, y) -> go False c <|> go True c{ ip = (Jmp x, y) }
  97.     (Acc _, _) -> go False c
  98.     (Jmp x, y) -> go False c <|> go True c{ ip = (Nop x, y) }
  99.  testConsole' True c = go True c
  100.   go v c = case stepConsole (bool (Just True) Nothing) c of
  101.    Left _ -> Nothing
  102.    Right (Left x) -> Just x
  103.    Right (Right c') -> testConsole' v c'
  104.  
  105. part1 = interact (show . fmap (runConsole . initConsole False) . (nonEmpty <=< traverse parseInstruction) . lines)
  106.  
  107. main = interact (show . (testConsole . initConsole False <=< nonEmpty <=< traverse parseInstruction) . lines)
  108.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement