|
| 1 | +{-# LANGUAGE DeriveGeneric #-} |
| 2 | +{-# LANGUAGE TypeApplications #-} |
| 3 | +{-# LANGUAGE ScopedTypeVariables #-} |
| 4 | +import Lib |
| 5 | +import Data.Char |
| 6 | +import Control.DeepSeq |
| 7 | +import Data.Maybe |
| 8 | +import GHC.Generics |
| 9 | +import Data.Function |
| 10 | +import Control.Monad.Fix |
| 11 | +import Debug.Trace |
1 | 12 |
|
| 13 | +dummyInput = [ "nop +0" |
| 14 | + , "acc +1" |
| 15 | + , "jmp +4" |
| 16 | + , "acc +3" |
| 17 | + , "jmp -3" |
| 18 | + , "acc -99" |
| 19 | + , "acc +1" |
| 20 | + , "jmp -4" |
| 21 | + , "acc +6" ] |
2 | 22 |
|
3 |
| -data Band a = Band (Band a) a (Band a) |
| 23 | +dummyBand = fromJust $ toBand dummyInput |
| 24 | + where toBand = sequence . map ((fmap (flip (,) False)) . parseInstruction) |
4 | 25 |
|
| 26 | +main = do |
| 27 | + let toBand = sequence . map ((fmap (flip (,) False)) . parseInstruction) |
| 28 | + dummyBand = fromJust $ toBand dummyInput |
| 29 | + --print $ toBand dummyInput |
| 30 | + --print $ runState (fixState eval dummyBand) $ EvalState 0 0 |
| 31 | + |
| 32 | + contents <- readFile "8.input" |
| 33 | + let band = fromJust $ toBand $ lines contents |
| 34 | + --print $ runState (fixState eval band) $ EvalState 0 0 |
| 35 | + |
| 36 | + putStrLn "fixing bug:" |
| 37 | + let res = untilLastExecuted band 0 |
| 38 | + print res |
| 39 | + print $ (!!627) . fst $ res |
| 40 | + |
| 41 | +untilLastExecuted :: Band (ArithFunc Int) -> Int -> (Band (ArithFunc Int), EvalState) |
| 42 | +untilLastExecuted band i = |
| 43 | + let result = runState (fixState eval band) $ EvalState 0 0 |
| 44 | + in if (snd . last . fst $ result) |
| 45 | + then result |
| 46 | + else untilLastExecuted (changeIth i band) (i+1) |
| 47 | + |
| 48 | +changeIth :: Int -> Band (ArithFunc Int) -> Band (ArithFunc Int) |
| 49 | +changeIth _ [] = [] |
| 50 | +changeIth 0 ((Jmp x,b):t) = (Nop x,b) : t |
| 51 | +changeIth 0 ((Nop x,b):t) = (Jmp x,b) : t |
| 52 | +changeIth i (instr@(Jmp _,_):t) = instr : changeIth (i-1) t |
| 53 | +changeIth i (instr@(Nop _,_):t) = instr : changeIth (i-1) t |
| 54 | +changeIth i (h:t) = h : changeIth i t |
| 55 | + |
| 56 | +parseArithFunc :: forall a. Read a => String -> Maybe (ArithFunc a) |
| 57 | +parseArithFunc (a:s) |
| 58 | + | a == '+' = Just $ Plus rest |
| 59 | + | a == '-' = Just $ Minus rest |
| 60 | + | a == '*' = Just $ Times rest |
| 61 | + | otherwise = Nothing |
| 62 | + where |
| 63 | + rest = read @a s |
| 64 | + |
| 65 | +parseInstruction :: String -> Maybe (Instruction (ArithFunc Int)) |
| 66 | +parseInstruction s = case inst of |
| 67 | + "jmp" -> Jmp <$> f |
| 68 | + "acc" -> Acc <$> f |
| 69 | + "nop" -> Nop <$> f |
| 70 | + _ -> Nothing |
| 71 | + where inst = take 3 s |
| 72 | + f = parseArithFunc $ drop 4 s |
| 73 | + |
| 74 | +data Instruction a = Nop a | Acc a | Jmp a |
| 75 | + deriving (Show, Generic, Read) |
| 76 | + |
| 77 | +instance NFData a => NFData (Instruction a) |
| 78 | + |
| 79 | +type Band a = [(Instruction a, Bool)] |
| 80 | + |
| 81 | +data EvalState = EvalState { instrPointer :: Int |
| 82 | + , accumulator :: Int } |
| 83 | + deriving (Show, Generic, Eq) |
| 84 | + |
| 85 | +incr :: EvalState -> EvalState |
| 86 | +incr (EvalState i a) = EvalState (i+1) a |
| 87 | + |
| 88 | +modAcc :: (Int -> Int) -> EvalState -> EvalState |
| 89 | +modAcc f (EvalState i a) = EvalState i $ f a |
| 90 | + |
| 91 | +modInstr :: (Int -> Int) -> EvalState -> EvalState |
| 92 | +modInstr f (EvalState i a) = EvalState (f i) a |
| 93 | + |
| 94 | +newtype State s a = State { runState :: s -> (a, s) } |
| 95 | + |
| 96 | +contramap :: (a -> b) -> (a, c) -> (b, c) |
| 97 | +contramap f (a, c) = (f a, c) |
| 98 | + |
| 99 | +instance Functor (State s) where |
| 100 | + f `fmap` (State s) = State $ contramap f . s |
| 101 | + |
| 102 | +instance Applicative (State s) where |
| 103 | + pure a = State $ \s -> (a, s) |
| 104 | + (State s1) <*> s2 = State $ \s -> (fst . ($s) . runState $ (fst . s1) s `fmap` s2, s) |
| 105 | + |
| 106 | +instance Monad (State s) where |
| 107 | + (State act) >>= f = State $ \s -> |
| 108 | + let (a, s') = act s |
| 109 | + in runState (f a) s' |
| 110 | + |
| 111 | + {- |
| 112 | +instance MonadFix (State s) where |
| 113 | + mfix f = mfix $ \st -> f st |
| 114 | + -} |
| 115 | + |
| 116 | +get :: State s s |
| 117 | +get = State $ \s -> (s,s) |
| 118 | + |
| 119 | +put :: s -> State s () |
| 120 | +put x = State $ \sth -> ((), x) |
| 121 | + |
| 122 | +modify :: (s -> s) -> State s () |
| 123 | +modify f = do |
| 124 | + x <- get |
| 125 | + put (f x) |
| 126 | + |
| 127 | +(!!!) :: NFData a => [a] -> Int -> Maybe a |
| 128 | +(!!!) l a = deepTry (l!!) a |
| 129 | + |
| 130 | +data ArithFunc a = Plus a | Minus a | Times a |
| 131 | + deriving (Show, Generic) |
| 132 | + |
| 133 | +instance NFData a => NFData (ArithFunc a) |
| 134 | + |
| 135 | +toFunc :: Num a => ArithFunc a -> (a -> a) |
| 136 | +toFunc (Plus a) = ((+) a) |
| 137 | +toFunc (Minus a) = (flip (-) a) |
| 138 | +toFunc (Times a) = (*a) |
| 139 | + |
| 140 | +firstBy :: Eq a => (a -> a -> Bool) -> [a] -> a |
| 141 | +firstBy f (a:as) = fa as a |
| 142 | + where |
| 143 | + fa (a:as) b |
| 144 | + | f a b = b |
| 145 | + | otherwise = fa as a |
| 146 | + |
| 147 | +modList :: Int -> (a -> a) -> [a] -> [a] |
| 148 | +modList i f l |
| 149 | + | length l > i = take (i) l ++ [f $ l!!i] ++ (drop (i+1) l ) |
| 150 | + | otherwise = l |
| 151 | + |
| 152 | +fixState :: (Eq a, Show a) => (b -> State a b) -> b -> State a b |
| 153 | +fixState action lastOutput = do |
| 154 | + last <- get |
| 155 | + newOutput <- action lastOutput |
| 156 | + new <- get |
| 157 | + if last == new --compare states |
| 158 | + then return lastOutput |
| 159 | + else fixState action newOutput |
| 160 | + {- |
| 161 | + let now = f last |
| 162 | + valNow = fst $ runState (now >> get) $ last |
| 163 | + in if valNow == last |
| 164 | + then now |
| 165 | + else fixState f valNow |
| 166 | +-} |
| 167 | +eval :: Band (ArithFunc Int) -> State EvalState (Band (ArithFunc Int)) |
| 168 | +eval instructions = do |
| 169 | + s@(EvalState p a) <- get |
| 170 | + let newEval = |
| 171 | + (case instructions !!! p of |
| 172 | + Nothing -> s |
| 173 | + (Just (_, True)) -> s |
| 174 | + (Just (Nop f, _)) -> EvalState (p+1) a |
| 175 | + (Just (Acc f, _)) -> EvalState (p+1) (toFunc f $ a) |
| 176 | + (Just (Jmp f, _)) -> EvalState (toFunc f $ p) a ) |
| 177 | + |
| 178 | + put $ newEval |
| 179 | + return $ modList p (\(a, _) -> (a, True)) instructions |
0 commit comments