@@ -9,19 +9,19 @@ module AOC2017.Day18 (day18a, day18b) where
9
9
10
10
import AOC2017.Types (Challenge )
11
11
import AOC2017.Util.Accum (AccumT (.. ), execAccumT , look , add )
12
- import AOC2017.Util.Prompt ()
13
12
import AOC2017.Util.Tape (Tape (.. ), HasTape (.. ), move , unsafeTape )
14
13
import Control.Applicative (many , empty )
15
14
import Control.Lens (makeClassy , use , at , non , (%=) , use , (.=) , (<>=) , zoom )
16
15
import Control.Monad (guard , when )
17
- import Control.Monad.Prompt (MonadPrompt (.. ), runPromptM )
18
- import Control.Monad.State (MonadState (.. ), execStateT , State , evalState )
16
+ import Control.Monad.Prompt (Prompt , prompt , runPromptM )
17
+ import Control.Monad.State (MonadState (get ,put ), StateT (.. ), State , execStateT , evalState )
18
+ import Control.Monad.Trans.Class (MonadTrans (lift ))
19
19
import Control.Monad.Trans.Maybe (MaybeT (.. ))
20
- import Control.Monad.Writer (First ( .. ), Last ( .. ), MonadWriter (.. ), WriterT (.. ), Writer , execWriter )
20
+ import Control.Monad.Writer (MonadWriter (.. ), WriterT (.. ), Writer , execWriter )
21
21
import Data.Char (isAlpha )
22
- import Data.Coerce (coerce )
23
22
import Data.Kind (Type )
24
23
import Data.Maybe (fromJust )
24
+ import Data.Monoid (First (.. ), Last (.. ))
25
25
import qualified Data.Map as M
26
26
import qualified Data.Vector.Sized as V
27
27
@@ -67,29 +67,36 @@ data Command :: Type -> Type where
67
67
CRcv :: Int -> Command Int -- ^ input is current value of buffer
68
68
CSnd :: Int -> Command () -- ^ input is thing being sent
69
69
70
- rcvMachine :: MonadPrompt Command m => Int -> m Int
70
+ type Machine = Prompt Command
71
+
72
+ rcvMachine :: Int -> Machine Int
71
73
rcvMachine = prompt . CRcv
72
74
73
- sndMachine :: MonadPrompt Command m => Int -> m ()
75
+ sndMachine :: Int -> Machine ()
74
76
sndMachine = prompt . CSnd
75
77
76
78
data ProgState = PS { _psTape :: Tape Op
77
79
, _psRegs :: M. Map Char Int
78
80
}
79
81
makeClassy ''ProgState
80
82
83
+ -- | Context in which a 'Duet' program runs
84
+ type Duet = MaybeT (StateT ProgState Machine )
85
+ execDuet :: Duet a -> ProgState -> Machine ProgState
86
+ execDuet = execStateT . runMaybeT
87
+
81
88
-- | Single step through program tape.
82
- stepTape :: ( MonadState ProgState m , MonadPrompt Command m ) => m ()
89
+ stepTape :: Duet ()
83
90
stepTape = use (psTape . tFocus) >>= \ case
84
91
OSnd x -> do
85
- sndMachine =<< addrVal x
92
+ lift . lift . sndMachine =<< addrVal x
86
93
advance 1
87
94
OBin f x y -> do
88
95
yVal <- addrVal y
89
96
psRegs . at x . non 0 %= (`f` yVal)
90
97
advance 1
91
98
ORcv x -> do
92
- y <- rcvMachine =<< use (psRegs . at x . non 0 )
99
+ y <- lift . lift . rcvMachine =<< use (psRegs . at x . non 0 )
93
100
psRegs . at x . non 0 .= y
94
101
advance 1
95
102
OJgz x y -> do
@@ -124,14 +131,14 @@ interpretA :: Command a -> PartA a
124
131
interpretA = \ case
125
132
CRcv x -> do
126
133
when (x /= 0 ) $
127
- tell . coerce =<< look
134
+ tell . First . getLast =<< look
128
135
return x
129
136
CSnd x -> add (pure x)
130
137
131
138
day18a :: Challenge
132
- day18a = show
133
- . execPartA . runPromptM interpretA
134
- . execStateT (runMaybeT ( many stepTape) ) -- stepTape until program terminates
139
+ day18a = show . execPartA
140
+ . runPromptM interpretA
141
+ . execDuet ( many stepTape) -- stepTape until program terminates
135
142
. (`PS ` M. empty) . parse
136
143
137
144
{-
@@ -140,11 +147,6 @@ day18a = show
140
147
************************
141
148
-}
142
149
143
- data Thread = T { _tState :: ProgState
144
- , _tBuffer :: [Int ]
145
- }
146
- makeClassy ''Thread
147
-
148
150
-- | Context in which to interpret Command for Part B
149
151
type PartB s = MaybeT (State s )
150
152
@@ -158,35 +160,35 @@ interpretB = \case
158
160
[] -> empty
159
161
x: xs -> put xs >> return x
160
162
161
- -- runTapeB :: ProgState -> PartB Thread (ProgState, [Int])
162
- -- runTapeB = zoom tBuffer . runWriterT . runPromptM interpretB . execStateT stepTape
163
+ data Thread = T { _tState :: ProgState
164
+ , _tBuffer :: [Int ]
165
+ }
166
+ makeClassy ''Thread
163
167
164
168
-- | Single step through a thread. Nothing = either the thread terminates,
165
169
-- or requires extra input.
166
170
stepThread :: PartB Thread [Int ]
167
171
stepThread = do
168
- ps0 <- use tState
169
- (ps1, out) <- zoom tBuffer $ runWriterT
170
- . runPromptM interpretB
171
- $ execStateT stepTape ps0
172
- tState .= ps1
172
+ machine <- execDuet stepTape <$> use tState
173
+ (ps, out) <- runWriterT . zoom tBuffer
174
+ $ runPromptM interpretB machine
175
+ tState .= ps
173
176
return out
174
177
175
178
type MultiState = V. Vector 2 Thread
176
179
177
180
-- | Single step through both threads. Nothing = both threads terminate
178
- stepThreads :: PartB MultiState [ Int ]
181
+ stepThreads :: PartB MultiState Int
179
182
stepThreads = do
180
183
outA <- zoom (V. ix 0 ) $ concat <$> many stepThread
181
184
outB <- zoom (V. ix 1 ) $ concat <$> many stepThread
182
185
V. ix 0 . tBuffer <>= outB
183
186
V. ix 1 . tBuffer <>= outA
184
187
guard . not $ null outA && null outB
185
- return outB
188
+ return $ length outB
186
189
187
190
day18b :: Challenge
188
- day18b (parse-> t) = show . length . concat
189
- . fromJust
191
+ day18b (parse-> t) = show . sum . concat
190
192
. evalState (runMaybeT (many stepThreads))
191
193
$ ms
192
194
where
0 commit comments