|
| 1 | +import qualified Data.Attoparsec.Text as At |
| 2 | +import qualified Data.Map.Strict as M |
| 3 | +import qualified Data.Set as S |
| 4 | +import qualified Data.Array.Unboxed as A |
| 5 | +import Control.Monad |
| 6 | +import Control.Applicative |
| 7 | +import Control.Monad.Writer.Strict |
| 8 | +import Control.Monad.State.Strict |
| 9 | +import Data.Bits |
| 10 | +import Data.List (tails) |
| 11 | + |
| 12 | +import Commons |
| 13 | + |
| 14 | +parser :: At.Parser ((Integer,Integer,Integer),[Int]) |
| 15 | +parser = do |
| 16 | + let reg = (At.string "Register " >> At.anyChar >> At.string ": ") *> At.decimal <* At.endOfLine |
| 17 | + prog = At.string "Program: " >> At.sepBy1 At.decimal (At.char ',') |
| 18 | + regs <- (,,) <$> reg <*> reg <*> reg |
| 19 | + (regs,) <$> (At.endOfLine *> prog) |
| 20 | + |
| 21 | +data Inst = Adv | Bxl | Bst | Jnz | Bxc | Out | Bdv | Cdv deriving (Eq, Ord, Enum, Show) |
| 22 | + |
| 23 | +newtype Prog = Prog (A.UArray Int Int) deriving Show |
| 24 | + |
| 25 | +data Store = Store { regA :: Integer, regB :: Integer, regC :: Integer, pc :: Int } deriving (Show) |
| 26 | + |
| 27 | +eval :: Prog -> WriterT [Int] (State Store) () |
| 28 | +eval (Prog p) = do |
| 29 | + st <- get |
| 30 | + |
| 31 | + when (pc st <= snd (A.bounds p)) $ do |
| 32 | + let inst = toEnum $ p A.! pc st |
| 33 | + opnd = fromIntegral $ p A.! (1 + pc st) |
| 34 | + combo = if | 0 <= opnd && opnd <= 3 -> fromIntegral opnd |
| 35 | + | opnd == 4 -> regA st |
| 36 | + | opnd == 5 -> regB st |
| 37 | + | opnd == 6 -> regC st |
| 38 | + | opnd == 7 -> error "invalid combo" |
| 39 | + |
| 40 | + modify (\s -> s{pc = pc st + 2}) |
| 41 | + |
| 42 | + case inst of |
| 43 | + Adv -> modify (\s -> s{regA = div (regA st) (2 ^ combo)}) |
| 44 | + Bdv -> modify (\s -> s{regB = div (regA st) (2 ^ combo)}) |
| 45 | + Cdv -> modify (\s -> s{regC = div (regA st) (2 ^ combo)}) |
| 46 | + Bxl -> modify (\s -> s{regB = regB st .^. opnd}) |
| 47 | + Bst -> modify (\s -> s{regB = mod combo 8}) |
| 48 | + Bxc -> modify (\s -> s{regB = regB st .^. regC st}) |
| 49 | + Out -> tell [fromInteger $ mod combo 8] |
| 50 | + Jnz -> unless (regA st == 0) $ modify (\s -> s{pc = fromInteger opnd}) |
| 51 | + |
| 52 | + eval (Prog p) |
| 53 | + |
| 54 | +-- https://old.reddit.com/r/haskell/comments/1hg39hy/advent_of_code_2024_day_17/m2hyhxk/ |
| 55 | +solve2 :: (Integer -> [Int]) -> [[Int]] -> Integer -> [Integer] |
| 56 | +solve2 f [] n = [n] |
| 57 | +solve2 f (x:xs) n = [nx | i <- [0..7], f (n * 8 + i) == x, nx <- solve2 f xs (n * 8 + i)] |
| 58 | + |
| 59 | +main :: IO () |
| 60 | +main = do |
| 61 | + ((ra, rb, rc), prog) <- inp parser |
| 62 | + let startStore = Store ra rb rc 0 |
| 63 | + simulate = snd . evalState (runWriterT $ eval $ Prog (A.listArray (0, length prog - 1) prog)) |
| 64 | + s1 = simulate startStore |
| 65 | + print s1 |
| 66 | + let bbFn i = simulate startStore{regA = i} |
| 67 | + print $ minimum $ solve2 bbFn (tail $ reverse $ tails prog) 0 |
0 commit comments