Advent of Code solutions
1{-# LANGUAGE ViewPatterns #-}
2import Control.Monad
3import Data.Functor
4import Data.List
5import Data.Maybe
6
7data Instruction
8 = Nop Int
9 | Acc Int
10 | Jmp Int
11
12swap :: Instruction -> Maybe Instruction
13swap (Nop i) = Just (Jmp i)
14swap (Jmp i) = Just (Nop i)
15swap _ = Nothing
16
17parse :: String -> Instruction
18parse (fmap read . stripPrefix "acc +" -> Just i) = Acc i
19parse (fmap read . stripPrefix "acc -" -> Just i) = Acc (-i)
20parse (fmap read . stripPrefix "jmp +" -> Just i) = Jmp i
21parse (fmap read . stripPrefix "jmp -" -> Just i) = Jmp (-i)
22parse (fmap read . stripPrefix "nop +" -> Just i) = Nop i
23parse (fmap read . stripPrefix "nop -" -> Just i) = Nop (-i)
24parse _ = error "invalid"
25
26exec :: Int -> [Int] -> [Instruction] -> Maybe Int
27exec i e _ | i `elem` e = Nothing
28exec i _ inst | i >= length inst = Just 0
29exec i e inst = case inst !! i of
30 Nop _ -> exec (i + 1) (i : e) inst
31 Acc n -> (n +) <$> exec (i + 1) (i : e) inst
32 Jmp n -> exec (i + n) (i : e) inst
33
34connect :: [Instruction] -> [Instruction] -> Instruction -> [Instruction]
35connect ls rs i = ls ++ (i : rs)
36
37fix :: [Instruction] -> Int
38fix inst = fromJust $ join $ find isJust $ zipWith3 try (inits (init inst)) (tails (tail inst)) (swap <$> inst)
39 where
40 try :: [Instruction] -> [Instruction] -> Maybe Instruction -> Maybe Int
41 try ls rs x = x <&> connect ls rs >>= exec 0 []
42
43main :: IO ()
44main = do
45 instructions <- fmap parse . lines <$> getContents
46 print $ fix instructions