-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathLiteBrite.hs
160 lines (129 loc) · 4.73 KB
/
LiteBrite.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
152
153
154
155
156
157
158
159
160
module LiteBrite where
import Control.Applicative
import qualified Data.Vector as V
import Text.Trifecta
-- Part 1
data Coord = Coord Int Int
deriving Show
data Mode = On | Off | Toggle | Noop | AddOne | AddTwo | SubOne
deriving Show
data Instruction = Instruction Mode Coord Coord
deriving Show
newtype LightState = LightState (V.Vector (V.Vector Bool))
deriving Show
countLightsOn :: String -> Int
countLightsOn input =
let LightState finalPattern = patternLights (parseInput input)
rowCounts = V.map (V.length . V.filter id) finalPattern
in sum rowCounts
parseInput :: String -> V.Vector Instruction
parseInput s = V.fromList $ cleanupInstructions $ map parseLine (lines s)
cleanupInstruction :: Result Instruction -> Instruction
cleanupInstruction (Failure _) =
Instruction Noop (Coord (-1) (-1)) (Coord (-1) (-1))
cleanupInstruction (Success x) =
x
cleanupInstructions :: [Result Instruction] -> [Instruction]
cleanupInstructions = map cleanupInstruction
parseLine :: String -> Result Instruction
parseLine = parseString parseInstruction mempty
parseInstruction :: Parser Instruction
parseInstruction = parseOn <|> parseOff <|> parseToggle
parseOn :: Parser Instruction
parseOn = do
_ <- string "turn on "
(ca, cb) <- parseCoords
return (Instruction On ca cb)
parseOff :: Parser Instruction
parseOff = do
_ <- string "turn off "
(ca, cb) <- parseCoords
return (Instruction Off ca cb)
parseToggle :: Parser Instruction
parseToggle = do
_ <- string "toggle "
(ca, cb) <- parseCoords
return (Instruction Toggle ca cb)
parseCoords :: Parser (Coord, Coord)
parseCoords = do
startx <- decimal
_ <- char ','
starty <- decimal
_ <- string " through "
endx <- decimal
_ <- char ','
endy <- decimal
return ((Coord (fromInteger startx) (fromInteger starty)),
(Coord (fromInteger endx) (fromInteger endy)))
initState :: LightState
initState = LightState $ V.generate 1000 (const $ V.generate 1000 $ const False)
patternLights :: V.Vector Instruction -> LightState
patternLights = V.foldl' execInst initState
execInst :: LightState -> Instruction -> LightState
execInst (LightState state) (Instruction m start end) =
let f = case m of
On -> const True
Off -> const False
Toggle -> not
_ -> id
in LightState $ applyInst state f start end
applyInst :: V.Vector (V.Vector a)
-> (a -> a)
-> Coord
-> Coord
-> V.Vector (V.Vector a)
applyInst state f (Coord x1 y1) (Coord x2 y2) =
let updateRow i =
let curRow = state V.! i
colUpdate j = (j, f (curRow V.! j))
colUpdateV = V.map colUpdate (V.enumFromN y1 ((y2 - y1) + 1))
in
(i, curRow `V.update` colUpdateV)
rowUpdateV = V.map updateRow (V.enumFromN x1 ((x2 - x1) + 1))
in
state `V.update` rowUpdateV
-- Part 2
newtype LightBrightness = LightBrightness (V.Vector (V.Vector Int))
deriving Show
totalBrightness :: String -> Int
totalBrightness input = let LightBrightness finalPattern =
patternNordicLights (parseNordicInput input)
rowBrightness = V.map sum finalPattern
in
sum rowBrightness
parseNordicInput :: String -> V.Vector Instruction
parseNordicInput s = V.fromList $
cleanupInstructions $ map parseNordicLine (lines s)
parseNordicLine :: String -> Result Instruction
parseNordicLine = parseString parseNordicInstruction mempty
parseNordicInstruction :: Parser Instruction
parseNordicInstruction = parseAddOne <|> parseAddTwo <|> parseSubOne
parseAddOne :: Parser Instruction
parseAddOne = do
_ <- string "turn on "
(ca, cb) <- parseCoords
return (Instruction AddOne ca cb)
parseSubOne :: Parser Instruction
parseSubOne = do
_ <- string "turn off "
(ca, cb) <- parseCoords
return (Instruction SubOne ca cb)
parseAddTwo :: Parser Instruction
parseAddTwo = do
_ <- string "toggle "
(ca, cb) <- parseCoords
return (Instruction AddTwo ca cb)
initNordicState :: LightBrightness
initNordicState = LightBrightness $
V.generate 1000 (const $ V.generate 1000 $ const (0 :: Int))
patternNordicLights :: V.Vector Instruction -> LightBrightness
patternNordicLights = V.foldl' execNordicInst initNordicState
execNordicInst :: LightBrightness -> Instruction -> LightBrightness
execNordicInst (LightBrightness state) (Instruction m start end) =
let f = case m of
AddOne -> (+ 1)
SubOne -> (\x -> if x == 0 then 0 else x - 1)
AddTwo -> (+ 2)
_ -> id
in
LightBrightness $ applyInst state f start end