This repository has been archived by the owner on Nov 17, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 8
/
Day08.hs
128 lines (111 loc) · 3.59 KB
/
Day08.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
-- |
-- Module : AOC.Challenge.Day08
-- License : BSD3
--
-- Stability : experimental
-- Portability : non-portable
--
-- Day 8. See "AOC.Solver" for the types used in this module!
module AOC.Challenge.Day08 (
day08a
, day08b
) where
import AOC.Common (perturbationsBy, CharParser, parseLines, pDecimal)
import AOC.Solver ((:~>)(..))
import Control.DeepSeq (NFData)
import Control.Lens (_1, Ixed(..), Index, IxValue, (^?))
import Data.IntSet (IntSet)
import Data.Maybe (listToMaybe)
import Data.Vector (Vector)
import GHC.Generics (Generic)
import qualified Data.Functor.Foldable as R
import qualified Data.Functor.Foldable.TH as R
import qualified Data.IntSet as IS
import qualified Data.Vector as V
import qualified Text.Megaparsec as P
import qualified Text.Megaparsec.Char as P
data Instr = NOP | ACC | JMP
deriving (Generic, Eq, Ord, Show)
instance NFData Instr
type Command = (Instr, Int)
instrParser :: CharParser Instr
instrParser = P.choice
[ NOP <$ P.string "nop"
, ACC <$ P.string "acc"
, JMP <$ P.string "jmp"
]
commandParser :: CharParser Command
commandParser = (,) <$> (instrParser <* P.space) <*> pDecimal
-- RIP explicit state
-- data CState = CS { csPtr :: !Int, csAcc :: !Int }
-- deriving (Generic, Show)
-- instance NFData CState
-- initialCS :: CState
-- initialCS = CS 0 0
-- runCommand
-- :: (Ixed t, Index t ~ Int, IxValue t ~ (Instr, Int))
-- => t
-- -> CState
-- -> Maybe CState
-- runCommand cmds cs = (cmds ^? ix (csPtr cs)) <&> \case
-- (NOP, _) -> cs & #csPtr +~ 1
-- (ACC, i) -> cs & #csPtr +~ 1
-- & #csAcc +~ i
-- (JMP, i) -> cs & #csPtr +~ i
data EndType = Halt | Loop
deriving (Generic, Eq, Ord, Show)
instance NFData EndType
data AccStream = EndAcc EndType | Step AccStream | Acc Int AccStream
R.makeBaseFunctor ''AccStream
-- | Unfold an 'AccStream' over a program bank (@t@), given a seen-items
-- list and the current instruction pointer.
vmStreamCoalg
:: (Ixed t, Index t ~ Int, IxValue t ~ (Instr, Int))
=> t
-> (IntSet, Int)
-> AccStreamF (IntSet, Int)
vmStreamCoalg cmds (!seen, !i)
| i `IS.member` seen = EndAccF Loop
| otherwise = case cmds ^? ix i of
Nothing -> EndAccF Halt
Just cmd -> case cmd of
(NOP, _) -> StepF (seen', i+1)
(ACC, n) -> AccF n (seen', i+1)
(JMP, n) -> StepF (seen', i+n)
where
seen' = i `IS.insert` seen
-- | Collapse an 'AccStream' to get the sum and the end state.
sumStreamAlg
:: AccStreamF (EndType, Int)
-> (EndType, Int)
sumStreamAlg = \case
EndAccF es -> (es, 0)
StepF a -> a
AccF n (es, !x) -> (es, x + n)
exhaustVM
:: (Ixed t, Index t ~ Int, IxValue t ~ (Instr, Int))
=> t
-> (EndType, Int)
exhaustVM cmds = R.hylo sumStreamAlg (vmStreamCoalg cmds) (IS.empty, 0)
day08a :: Vector Command :~> Int
day08a = MkSol
{ sParse = fmap V.fromList . parseLines commandParser
, sShow = show
, sSolve = Just . snd . exhaustVM
}
day08b :: Vector Command :~> Int
day08b = MkSol
{ sParse = fmap V.fromList . parseLines commandParser
, sShow = show
, sSolve = \cmds0 -> listToMaybe [
i
| cmds <- perturbationsBy (traverse . _1) perturbs cmds0
, let (es, i) = exhaustVM cmds
, es == Halt
]
}
where
perturbs = \case
NOP -> [JMP]
ACC -> []
JMP -> [NOP]