X-Git-Url: https://git.njae.me.uk/?a=blobdiff_plain;f=src%2Fadvent18%2Fadvent18a.hs;fp=src%2Fadvent18%2Fadvent18a.hs;h=2c3e1e1f7df1b87e465fdd66bb09d9f2b3fae5cd;hb=eefbb6bc370b6ae9c2ad16f7daaeac78642025d3;hp=0000000000000000000000000000000000000000;hpb=9ce2b21f9734aa6e51186d2cc0075083a5864155;p=advent-of-code-17.git diff --git a/src/advent18/advent18a.hs b/src/advent18/advent18a.hs new file mode 100644 index 0000000..2c3e1e1 --- /dev/null +++ b/src/advent18/advent18a.hs @@ -0,0 +1,123 @@ +{-# LANGUAGE NegativeLiterals #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE TypeFamilies #-} + +import Data.Text (Text) +import qualified Data.Text as T +import qualified Data.Text.IO as TIO + +import qualified Data.Map.Strict as M +import Data.Map.Strict ((!)) + +import Control.Monad (when) +import Control.Monad.State.Lazy +import Control.Monad.Reader +import Control.Monad.Writer + +import Advent18Parser + +data Machine = Machine { registers :: M.Map Char Integer + , lastSound :: Integer + , pc :: Int + } + deriving (Show, Eq) + +type ProgrammedMachine = WriterT [Integer] (ReaderT [Instruction] (State Machine)) () + +emptyMachine = Machine {registers = M.empty, lastSound = 0, pc = 0} + +main :: IO () +main = do + text <- TIO.readFile "data/advent18.txt" + let instrs = successfulParse text + let ((result, l), machinef) = part1 instrs + print $ head l + +part1 :: [Instruction] -> (((), [Integer]), Machine) +part1 instructions = + runState ( + runReaderT ( + runWriterT executeInstructions + ) + instructions + ) + emptyMachine + +executeInstructions :: ProgrammedMachine +executeInstructions = + do instrs <- ask + m <- get + when (pc m >= 0 && pc m < length instrs) + $ + do let rt = recoverTriggers instrs m + if rt + then tell [lastSound m] + else do executeInstruction + executeInstructions + +executeInstruction :: ProgrammedMachine +executeInstruction = + do instrs <- ask + m <- get + let instr = instrs!!(pc m) + put (applyInstruction instr m) + + +isRecover :: Instruction -> Bool +isRecover (Rcv _) = True +isRecover _ = False + + +recoverTriggers :: [Instruction] -> Machine -> Bool +recoverTriggers instrs m = + if isRecover instr + then (x /= 0) + else False + where instr = instrs!!(pc m) + Rcv a = instr + x = evaluate m a + + +applyInstruction :: Instruction -> Machine -> Machine + +applyInstruction (Snd sound) m = m {lastSound = freq, pc = pc'} + where pc' = pc m + 1 + freq = evaluate m sound + +applyInstruction (Set (Register a) b) m = m {registers = reg', pc = pc'} + where pc' = pc m + 1 + y = evaluate m b + reg' = M.insert a y $ registers m + +applyInstruction (Add (Register a) b) m = m {registers = reg', pc = pc'} + where pc' = pc m + 1 + x = evaluate m (Register a) + y = evaluate m b + reg' = M.insert a (x + y) $ registers m + +applyInstruction (Mul (Register a) b) m = m {registers = reg', pc = pc'} + where pc' = pc m + 1 + x = evaluate m (Register a) + y = evaluate m b + reg' = M.insert a (x * y) $ registers m + +applyInstruction (Mod (Register a) b) m = m {registers = reg', pc = pc'} + where pc' = pc m + 1 + x = evaluate m (Register a) + y = evaluate m b + reg' = M.insert a (x `mod` y) $ registers m + +applyInstruction (Rcv _a) m = m {pc = pc'} + where pc' = pc m + 1 + +applyInstruction (Jgz a b) m = m {pc = pc'} + where x = evaluate m a + y = evaluate m b + pc' = if x > 0 then pc m + (fromIntegral y) else pc m + 1 + + +evaluate :: Machine -> Location -> Integer +evaluate _ (Literal i) = i +evaluate m (Register r) = M.findWithDefault 0 r (registers m) +