{-# LANGUAGE FlexibleContexts #-} import qualified Data.Vector as V import Text.Parsec data Op = Acc Int | Jmp Int | Nop Int deriving Show main :: IO () main = do raw <- readFile "day8.txt" let ops = V.fromList $ zip (repeat False) $ validate $ map (parse lineP []) $ lines raw ansA = solveA ops ansB = solveB ops in do putStrLn $ "day8a: " ++ (show ansA) putStrLn $ "day8b: " ++ (show ansB) solveA :: V.Vector (Bool, Op) -> Int solveA ops = runMachineA ops 0 0 solveB :: V.Vector (Bool, Op) -> Int solveB ops = case testSwaps ops 0 of Nothing -> error "unsolvable?" Just x -> x runMachineA :: V.Vector (Bool, Op) -> Int -> Int -> Int runMachineA ops pc ac = do let (check,op) = ops V.! pc in case check of True -> ac _ -> do let nac = case op of (Acc x) -> ac + x _ -> ac npc = case op of (Jmp y) -> pc + y _ -> succ pc nops = ops V.// [(pc, (True, op))] in runMachineA nops npc nac swapOp :: V.Vector (Bool, Op) -> Int -> Maybe (V.Vector (Bool, Op)) swapOp ops ind = case op of (Acc _) -> Nothing (Nop x) -> Just $ ops V.// [(ind, (check, Jmp x))] (Jmp x) -> Just $ ops V.// [(ind, (check, Nop x))] where (check,op) = ops V.! ind testSwaps :: V.Vector (Bool, Op) -> Int -> Maybe Int testSwaps ops ind | ind >= V.length ops = Nothing | otherwise = case res of Nothing -> testSwaps ops $ succ ind (Just nops) -> case (runMachineB nops 0 0) of Nothing -> testSwaps ops $ succ ind x -> x where res = swapOp ops ind runMachineB :: V.Vector (Bool, Op) -> Int -> Int -> Maybe Int runMachineB ops pc ac = if pc == V.length ops then Just ac else do let (check,op) = ops V.! pc in case check of True -> Nothing _ -> do let nac = case op of (Acc x) -> ac + x _ -> ac npc = case op of (Jmp y) -> pc + y _ -> succ pc nops = ops V.// [(pc, (True, op))] in runMachineB nops npc nac validate :: [Either ParseError Op] -> [Op] validate [] = [] validate ((Left _):_) = error "invalid input" validate ((Right b):bs) = b:(validate bs) lineP :: Parsec String () Op lineP = do o <- opP whitespaces i <- intP whitespaces eof return $ o i intP :: Parsec String () Int intP = do s <- oneOf ['+','-'] v <- many1 digit return $ (if s == '-' then -1 else 1) * (read v) opP :: Parsec String () (Int -> Op) opP = do o <- (string "acc") <|> (string "jmp") <|> (string "nop") case o of "acc" -> return Acc "jmp" -> return Jmp _ -> return Nop whitespaces :: Parsec String () String whitespaces = many $ char ' '