-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathDay6.hs
110 lines (97 loc) · 3.17 KB
/
Day6.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
{-# LANGUAGE TemplateHaskell #-}
module Day6
( part1
, part2
) where
import Control.Applicative (some, (<|>))
import Control.Monad (forM_)
import Control.Monad.ST (ST, runST)
import Data.Bits (shiftL)
import Data.ByteString (ByteString)
import Data.ByteString.UTF8 (fromString)
import Data.Vector.Unboxed (unsafeFreeze)
import qualified Data.Vector.Unboxed as V (filter, length)
import Data.Vector.Unboxed.Mutable (MVector, unsafeModify, unsafeRead,
unsafeWrite)
import qualified Data.Vector.Unboxed.Mutable as MV (foldr', replicate)
import Data.Void (Void)
import FlatParse.Basic (anyAsciiDecimalInt, char,
runParser, string, switch)
import qualified FlatParse.Basic as F (char, string)
import Helpers.Parsers.FlatParse (Parser, extract)
data Modify
= TurnOn [Int]
| TurnOff [Int]
| Toggle [Int]
posify :: Int -> Int -> Int
posify x y = x + shiftL y 10
tokenise :: Parser ([Int] -> Modify)
tokenise =
$(switch
[|case _ of
"turn on " -> pure TurnOn
"turn off " -> pure TurnOff
"toggle " -> pure Toggle|])
parseInput :: Parser [Modify]
parseInput = some parseLine
parseLine :: Parser Modify
parseLine = do
op <- tokenise
lx <- anyAsciiDecimalInt
$(F.char ',')
ly <- anyAsciiDecimalInt
$(F.string " through ")
ux <- anyAsciiDecimalInt
$(F.char ',')
uy <- anyAsciiDecimalInt
$(F.char '\n')
pure . op $ [posify x y | x <- [lx .. ux], y <- [ly .. uy]]
solvePart1 :: [Modify] -> ST s Int
solvePart1 mods = do
lights <- MV.replicate (2 ^ 20) False
forM_ mods $ \mod -> do
operate1 mod lights
V.length . V.filter id <$> unsafeFreeze lights
solvePart2 :: [Modify] -> ST s Int
solvePart2 mods = do
lights <- MV.replicate (2 ^ 20) 0
forM_ mods $ \mod -> do
operate2 mod lights
MV.foldr' (+) 0 lights
operate1 :: Modify -> MVector s Bool -> ST s ()
operate1 (TurnOn poss) lights = do
forM_ poss $ \pos -> do
unsafeWrite lights pos True
operate1 (TurnOff poss) lights = do
forM_ poss $ \pos -> do
unsafeWrite lights pos False
operate1 (Toggle poss) lights = do
forM_ poss $ \pos -> do
onOff <- unsafeRead lights pos
unsafeWrite lights pos $ not onOff
operate2 :: Modify -> MVector s Int -> ST s ()
operate2 (TurnOn poss) lights = do
forM_ poss $ \pos -> do
unsafeModify lights (+ 1) pos
operate2 (TurnOff poss) lights = do
forM_ poss $ \pos -> do
unsafeModify
lights
(\x ->
if x > 1
then x - 1
else 0)
pos
operate2 (Toggle poss) lights = do
forM_ poss $ \pos -> do
unsafeModify lights (+ 2) pos
part1 :: Bool -> ByteString -> String
part1 _ input = show solved
where
solved = runST $ solvePart1 mods
mods = extract . runParser parseInput $ input :: [Modify]
part2 :: Bool -> ByteString -> String
part2 _ input = show solved
where
solved = runST $ solvePart2 mods
mods = extract . runParser parseInput $ input