-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrun.hs
81 lines (64 loc) · 1.94 KB
/
run.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
{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE TupleSections #-}
import AoC
import Text.Parsec
import Data.Functor (($>))
import Data.Foldable
import qualified Data.Vector.Unboxed.Mutable as M
import qualified Data.Vector.Unboxed as V
type Position = V2 Int
data Command = Turn LightState | Toggle
deriving Show
data Instruction = I Position Position Command
deriving Show
data LightState = On | Off
deriving (Eq, Show)
number = read <$> many1 digit
position = v2 <$> ((,) <$> number <*> (char ',' *> number))
command = try (string "turn on" $> Turn On)
<|> try (string "turn off" $> Turn Off)
<|> string "toggle" $> Toggle
instruction = do
cmd <- command
_ <- char ' '
start <- position
_ <- string " through "
end <- position
pure $ I start end cmd
toUpdate :: Position -> Position -> [Position]
toUpdate (V2 (sx, sy)) (V2 (ex, ey)) = sequence $ v2 ([sx..ex], [sy..ey])
cmdValue :: Command -> Int
cmdValue = \case Turn On -> 1
Turn Off -> -1
Toggle -> 2
execCmd :: Command -> Int -> Int
execCmd = \case Turn On -> const 1
Turn Off -> const 0
Toggle -> \case 0 -> 1
1 -> 0
parseAll :: String -> [Instruction]
parseAll =
map (\(Right v) -> v)
. map (parse instruction "")
. lines
vecIndex :: Position -> Int
vecIndex (V2 (x, y)) = x + y * 1000
process :: (Command -> Int -> Int) -> [Instruction] -> V.Vector Int
process f input = V.create do
vec <- M.new (1000 * 1000)
M.set vec 0
forM_ input \(I start end cmd) ->
forM_ (toUpdate start end) \p ->
M.unsafeModify vec (f cmd) (vecIndex p)
pure vec
part1 :: [Instruction] -> Int
part1 = V.sum . process execCmd
part2 :: [Instruction] -> Int
part2 = V.sum . process (\cmd v -> max (v + cmdValue cmd) 0)
main :: IO ()
main = do
input <- parseAll <$> readFile "input.txt"
print (part1 input)
print (part2 input)