-
Notifications
You must be signed in to change notification settings - Fork 0
/
Day12.hs
151 lines (128 loc) · 4.1 KB
/
Day12.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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
module Day12
( part1
, part2
) where
import qualified Control.Applicative as A (empty)
import Control.Monad (void)
import Data.Either (fromRight)
import Data.List as L (length)
import Data.Map as M (Map, empty, findWithDefault,
fromList, insert)
import Data.Text (Text)
import Data.Vector as V (Vector, generate, length, (!))
import Helpers.Parsers.Text (Parser, string)
import Text.Megaparsec (eof, many, manyTill, optional,
parse, try, (<|>))
import Text.Megaparsec.Char (char, eol, lowerChar)
import qualified Text.Megaparsec.Char.Lexer as L (decimal, lexeme, signed,
space)
data Program = Program
{ getPointer :: Pointer
, getRegister :: Register
, getInstructions :: Vector Inst
}
type Register = Map Char Int
type Pointer = Int
type Inst = (Program -> Program)
instance Show Program where
show (Program p r _) = "Program " ++ show p ++ " " ++ show r
instance Eq Program where
(Program p1 r1 _) == (Program p2 r2 _) = p1 == p2 && r1 == r2
spaceConsumer :: Parser ()
spaceConsumer = L.space (void . char $ ' ') A.empty A.empty
decimal :: Parser Int
decimal = L.lexeme spaceConsumer L.decimal
signed :: Parser Int
signed = L.signed spaceConsumer decimal
parseProgram :: Parser Program
parseProgram =
Program 0 M.empty . (\l -> generate (L.length l) (l !!))
<$> manyTill
(try parseCPYReg
<|> parseCPYVal
<|> parseInc
<|> parseDec
<|> try parseJNZReg
<|> parseJNZVal)
eof
parseCPYReg :: Parser Inst
parseCPYReg = do
string "cpy "
reg1 <- lowerChar
char ' '
reg2 <- lowerChar
optional eol
return $ \program ->
let val = findWithDefault 0 reg1 . getRegister $ program
in movePointer . setRegister program reg2 $ val
parseCPYVal :: Parser Inst
parseCPYVal = do
string "cpy "
val <- signed
reg <- lowerChar
optional eol
return $ \program -> movePointer . setRegister program reg $ val
parseInc :: Parser Inst
parseInc = do
string "inc "
reg <- lowerChar
optional eol
return $ \program ->
let val = findWithDefault 0 reg . getRegister $ program
in movePointer . setRegister program reg $ val + 1
parseDec :: Parser Inst
parseDec = do
string "dec "
reg <- lowerChar
optional eol
return $ \program ->
let val = findWithDefault 0 reg . getRegister $ program
in movePointer . setRegister program reg $ val - 1
parseJNZReg :: Parser Inst
parseJNZReg = do
string "jnz "
reg <- lowerChar
char ' '
offset <- signed
optional eol
return $ \program ->
let val = findWithDefault 0 reg . getRegister $ program
in jumpPointer program val offset
parseJNZVal :: Parser Inst
parseJNZVal = do
string "jnz "
val <- signed
offset <- signed
optional eol
return $ \program -> jumpPointer program val offset
setRegister :: Program -> Char -> Int -> Program
setRegister (Program p r i) ad v = Program p r' i
where
r' = insert ad v r
jumpPointer :: Program -> Int -> Int -> Program
jumpPointer program val offset
| val /= 0 = program {getPointer = getPointer program + offset}
| otherwise = movePointer program
movePointer :: Program -> Program
movePointer program = program {getPointer = 1 + getPointer program}
execute :: Program -> Int
execute program
| getPointer program' >= V.length (getInstructions program) =
findWithDefault 0 'a' . getRegister $ program
| otherwise = execute program'
where
instruction = getInstructions program ! getPointer program
program' = instruction program
part1 :: Bool -> Text -> String
part1 _ =
show
. execute
. fromRight (error "couldn't parse input")
. parse parseProgram ""
part2 :: Bool -> Text -> String
part2 _ =
show
. execute
. (\p -> setRegister p 'c' 1)
. fromRight (error "couldn't parse input")
. parse parseProgram ""