{-# Language QuasiQuotes, TemplateHaskell, RankNTypes #-}
module Main where
import Advent (format, stageTH)
import Data.Map (Map)
import Text.Read (readMaybe)
import qualified Data.Map as Map
import qualified Data.Vector as V
data C = Cset | Cjnz | Cmul | Csub
deriving Int -> C -> ShowS
[C] -> ShowS
C -> String
(Int -> C -> ShowS) -> (C -> String) -> ([C] -> ShowS) -> Show C
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> C -> ShowS
showsPrec :: Int -> C -> ShowS
$cshow :: C -> String
show :: C -> String
$cshowList :: [C] -> ShowS
showList :: [C] -> ShowS
Show
stageTH
main :: IO ()
IO ()
main =
do Vector (C, Either Char Integer, Either Char Integer)
input <- [(C, Either Char Integer, Either Char Integer)]
-> Vector (C, Either Char Integer, Either Char Integer)
forall a. [a] -> Vector a
V.fromList ([(C, Either Char Integer, Either Char Integer)]
-> Vector (C, Either Char Integer, Either Char Integer))
-> IO [(C, Either Char Integer, Either Char Integer)]
-> IO (Vector (C, Either Char Integer, Either Char Integer))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [format|2017 23 (@C (%a|%ld) (%a|%ld)%n)*|]
let pgm :: p -> Int
pgm p
n = Vector (C, Either Char Integer, Either Char Integer) -> Int
runProgram Vector (C, Either Char Integer, Either Char Integer)
input
Int -> IO ()
forall a. Show a => a -> IO ()
print (Integer -> Int
forall {p}. p -> Int
pgm Integer
0)
(!) ::
Map Char Integer ->
Either Char Integer ->
Integer
Map Char Integer
m ! :: Map Char Integer -> Either Char Integer -> Integer
! Either Char Integer
k =
case Either Char Integer
k of
Right Integer
n -> Integer
n
Left Char
v -> Integer -> Char -> Map Char Integer -> Integer
forall k a. Ord k => a -> k -> Map k a -> a
Map.findWithDefault Integer
0 Char
v Map Char Integer
m
runProgram ::
V.Vector (C, Either Char Integer, Either Char Integer) ->
Int
runProgram :: Vector (C, Either Char Integer, Either Char Integer) -> Int
runProgram Vector (C, Either Char Integer, Either Char Integer)
cmds = Int -> Int -> Map Char Integer -> Int
forall {t}. Num t => t -> Int -> Map Char Integer -> t
step Int
0 Int
0 Map Char Integer
forall k a. Map k a
Map.empty
where
step :: t -> Int -> Map Char Integer -> t
step t
acc Int
pc Map Char Integer
regs =
case Vector (C, Either Char Integer, Either Char Integer)
cmds Vector (C, Either Char Integer, Either Char Integer)
-> Int -> Maybe (C, Either Char Integer, Either Char Integer)
forall a. Vector a -> Int -> Maybe a
V.!? Int
pc of
Maybe (C, Either Char Integer, Either Char Integer)
Nothing -> t
acc
Just (C
Cset,Left Char
x,Either Char Integer
y) -> t -> Int -> Map Char Integer -> t
step t
acc (Int
pcInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int
1) (Char -> Integer -> Map Char Integer -> Map Char Integer
forall k a. Ord k => k -> a -> Map k a -> Map k a
Map.insert Char
x (Map Char Integer
regsMap Char Integer -> Either Char Integer -> Integer
!Either Char Integer
y) Map Char Integer
regs)
Just (C
Csub,Left Char
x,Either Char Integer
y) -> t -> Int -> Map Char Integer -> t
step t
acc (Int
pcInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int
1) (Char -> Integer -> Map Char Integer -> Map Char Integer
forall k a. Ord k => k -> a -> Map k a -> Map k a
Map.insert Char
x (Map Char Integer
regs Map Char Integer -> Char -> Integer
forall k a. Ord k => Map k a -> k -> a
Map.! Char
x Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
- Map Char Integer
regsMap Char Integer -> Either Char Integer -> Integer
!Either Char Integer
y) Map Char Integer
regs)
Just (C
Cmul,Left Char
x,Either Char Integer
y) -> t -> Int -> Map Char Integer -> t
step (t
1t -> t -> t
forall a. Num a => a -> a -> a
+t
acc) (Int
pcInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int
1) (Char -> Integer -> Map Char Integer -> Map Char Integer
forall k a. Ord k => k -> a -> Map k a -> Map k a
Map.insert Char
x (Map Char Integer
regs Map Char Integer -> Char -> Integer
forall k a. Ord k => Map k a -> k -> a
Map.! Char
x Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* Map Char Integer
regsMap Char Integer -> Either Char Integer -> Integer
!Either Char Integer
y) Map Char Integer
regs)
Just (C
Cjnz,Either Char Integer
x,Either Char Integer
y) -> t -> Int -> Map Char Integer -> t
step t
acc (Int
pcInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int
o) Map Char Integer
regs
where
o :: Int
o | Map Char Integer
regsMap Char Integer -> Either Char Integer -> Integer
!Either Char Integer
x Integer -> Integer -> Bool
forall a. Eq a => a -> a -> Bool
/= Integer
0 = Integer -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Map Char Integer
regsMap Char Integer -> Either Char Integer -> Integer
!Either Char Integer
y)
| Bool
otherwise = Int
1