X-Git-Url: https://git.njae.me.uk/?p=advent-of-code-18.git;a=blobdiff_plain;f=src%2Fadvent19%2Fadvent19.hs;fp=src%2Fadvent19%2Fadvent19.hs;h=2ffc3d775cbbef308f6bf1a3115fef4574cab693;hp=0000000000000000000000000000000000000000;hb=c94e9a48c6130661b2891ca56381d11bab681afd;hpb=4a14b7d078a4559e6b9aff551e892aaaab7e4411 diff --git a/src/advent19/advent19.hs b/src/advent19/advent19.hs new file mode 100644 index 0000000..2ffc3d7 --- /dev/null +++ b/src/advent19/advent19.hs @@ -0,0 +1,197 @@ +{-# LANGUAGE NegativeLiterals #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE TypeFamilies #-} + + +import Debug.Trace + +-- import Prelude hiding ((++)) +import Data.Text (Text) +import qualified Data.Text as T +import qualified Data.Text.IO as TIO + +import Data.Void (Void) +import Text.Megaparsec hiding (State) +import Text.Megaparsec.Char +import qualified Text.Megaparsec.Char.Lexer as L +import qualified Control.Applicative as CA + +import qualified Data.Map.Strict as M +import Data.Map.Strict ((!)) +import Data.Bits ((.&.), (.|.)) + +import Control.Monad (when) +import Control.Monad.State.Lazy +import Control.Monad.Reader +import Control.Monad.Writer + +type Memory = M.Map Integer Integer + +data Location = Literal Integer | Register Integer deriving (Show, Eq) +data Instruction = + Addr Integer Integer Integer + | Addi Integer Integer Integer + | Mulr Integer Integer Integer + | Muli Integer Integer Integer + | Banr Integer Integer Integer + | Bani Integer Integer Integer + | Borr Integer Integer Integer + | Bori Integer Integer Integer + | Setr Integer Integer Integer + | Seti Integer Integer Integer + | Gtir Integer Integer Integer + | Gtri Integer Integer Integer + | Gtrr Integer Integer Integer + | Eqir Integer Integer Integer + | Eqri Integer Integer Integer + | Eqrr Integer Integer Integer + deriving (Eq, Show, Ord) + + +data Machine = Machine { _registers :: M.Map Integer Integer + , _pc :: Int + -- , _pcReg :: Integer + } + deriving (Show, Eq) + +type ProgrammedMachine = WriterT [Integer] (ReaderT (Integer, [Instruction]) (State Machine)) () + +emptyMachine = Machine {_registers = M.fromList (zip [0..5] (repeat 0)), + _pc = 0} + +main :: IO () +main = do + text <- TIO.readFile "data/advent19.txt" + let (ip, instrs) = successfulParse text + print (ip, instrs) + -- print $ part1 ip instrs + print $ sum [i | i <- [1..1032], 1032 `mod` i == 0] + -- print $ part2 ip instrs + print $ sum [i | i <- [1..10551432], 10551432 `mod` i == 0] + +part1 ip instructions = + runState ( + runReaderT ( + runWriterT executeInstructions + ) + (ip, instructions) + ) + emptyMachine + +part2 ip instructions = + runState ( + runReaderT ( + runWriterT executeInstructions + ) + (ip, instructions) + ) + m2 + where emptyRegisters = _registers emptyMachine + m2 = emptyMachine {_registers = M.insert 0 1 emptyRegisters} + +executeInstructions = + do (_, instrs) <- ask + m <- get + when (_pc m >= 0 && _pc m < length instrs) + $ + do executeInstruction + executeInstructions + +executeInstruction :: ProgrammedMachine +executeInstruction = + do (pcIs, instrs) <- ask + m <- get + let instr = instrs!!(_pc m) + let memory0 = _registers m + let memory1 = M.insert pcIs (fromIntegral (_pc m)) memory0 + let memory2 = if canPeep1 instrs (_pc m) memory1 -- sample1 == sample1Target + then memoryPeep1 memory1 + else perform instr memory1 + -- let memory2 = perform instr memory1 + let pc' = fromIntegral ((memory2!pcIs) + 1) + -- let aaa = trace ("pc: " ++ show (_pc m) ++ " m0: " ++ show memory0 ++ " m1: " ++ show memory1 ++ "m2: " ++ show memory2 ++ "pc': " ++ show pc') $! True + let m' = m {_registers = memory2, _pc = pc'} + put m' + where sample1 pcVal instructions = take (length sample1Target) $ drop pcVal instructions + sample1Target = [ Mulr 3 1 4 + , Eqrr 4 2 4 + , Addr 4 5 5 + , Addi 5 1 5 + , Addr 3 0 0 + , Addi 1 1 1 + , Gtrr 1 2 4 + , Addr 5 4 5 + , Seti 2 7 5 + ] + canPeep1 instructions pcVal mem = False -- ((sample1 pcVal instructions) == sample1Target) && ((mem!4) == 0) + memoryPeep1 mem = M.union (M.fromList [(0, mem!0 + (if (((mem!2) `mod` (mem!3)) == 0) then mem!3 else 0)), (1, mem!2), (4, mem!2)]) mem + -- M.insert 0 (mem!0 + mem!3) $ M.insert 1 (mem!2) $ M.insert 4 (mem!2) mem + + +perform :: Instruction -> Memory -> Memory +-- perform instr memory | ((memory!5 == 7) || ((memory!5 == 3) && (memory!1 == 1))) && (trace ("Perform " ++ show instr ++ " " ++ show memory) False) = undefined +perform instr memory | trace ("Perform " ++ show instr ++ " " ++ show memory) False = undefined +perform (Addr a b c) memory = M.insert c (memory!a + memory!b) memory +perform (Addi a b c) memory = M.insert c (memory!a + b) memory +perform (Mulr a b c) memory = M.insert c (memory!a * memory!b) memory +perform (Muli a b c) memory = M.insert c (memory!a * b) memory +perform (Banr a b c) memory = M.insert c (memory!a .&. memory!b) memory +perform (Bani a b c) memory = M.insert c (memory!a .&. b) memory +perform (Borr a b c) memory = M.insert c (memory!a .|. memory!b) memory +perform (Bori a b c) memory = M.insert c (memory!a .|. b) memory +perform (Setr a b c) memory = M.insert c (memory!a) memory +perform (Seti a b c) memory = M.insert c a memory +perform (Gtir a b c) memory = M.insert c (if a > (memory!b) then 1 else 0) memory +perform (Gtri a b c) memory = M.insert c (if (memory!a) > b then 1 else 0) memory +perform (Gtrr a b c) memory = M.insert c (if (memory!a) > (memory!b) then 1 else 0) memory +perform (Eqir a b c) memory = M.insert c (if a == memory!b then 1 else 0) memory +perform (Eqri a b c) memory = M.insert c (if (memory!a) == b then 1 else 0) memory +perform (Eqrr a b c) memory = M.insert c (if (memory!a) == (memory!b) then 1 else 0) memory + + +-- evaluate :: Machine -> Location -> Integer +-- evaluate _ (Literal i) = i +-- evaluate m (Register r) = M.findWithDefault 0 r (registers m) + + + +type Parser = Parsec Void Text + +sc :: Parser () +sc = L.space (skipSome spaceChar) CA.empty CA.empty + +lexeme = L.lexeme sc +integer = lexeme L.decimal +symb = L.symbol sc + + +instructionsP = (,) <$> headerP <*> many instructionP +instructionP = choice [ addrP, addiP, mulrP, muliP, banrP, baniP, + borrP, boriP, setrP, setiP, gtirP, gtriP, gtrrP, + eqirP, eqriP, eqrrP ] + +headerP = symb "#ip" *> integer + +addrP = Addr <$> (try (symb "addr") *> integer) <*> integer <*> integer +addiP = Addi <$> (try (symb "addi") *> integer) <*> integer <*> integer +mulrP = Mulr <$> (try (symb "mulr") *> integer) <*> integer <*> integer +muliP = Muli <$> (try (symb "muli") *> integer) <*> integer <*> integer +banrP = Banr <$> (try (symb "banr") *> integer) <*> integer <*> integer +baniP = Bani <$> (try (symb "bani") *> integer) <*> integer <*> integer +borrP = Borr <$> (try (symb "borr") *> integer) <*> integer <*> integer +boriP = Bori <$> (try (symb "bori") *> integer) <*> integer <*> integer +setrP = Setr <$> (try (symb "setr") *> integer) <*> integer <*> integer +setiP = Seti <$> (try (symb "seti") *> integer) <*> integer <*> integer +gtirP = Gtir <$> (try (symb "gtir") *> integer) <*> integer <*> integer +gtriP = Gtri <$> (try (symb "gtri") *> integer) <*> integer <*> integer +gtrrP = Gtrr <$> (try (symb "gtrr") *> integer) <*> integer <*> integer +eqirP = Eqir <$> (try (symb "eqir") *> integer) <*> integer <*> integer +eqriP = Eqri <$> (try (symb "eqri") *> integer) <*> integer <*> integer +eqrrP = Eqrr <$> (try (symb "eqrr") *> integer) <*> integer <*> integer + +successfulParse :: Text -> (Integer, [Instruction]) +successfulParse input = + case parse instructionsP "input" input of + Left _error -> (0, []) -- TIO.putStr $ T.pack $ parseErrorPretty err + Right instructions -> instructions \ No newline at end of file