-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathDay8.hs
114 lines (95 loc) · 3.25 KB
/
Day8.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
module Day8
( part1
, part2
) where
import qualified Control.Applicative as A (empty)
import Control.Monad (void)
import Control.Monad.State (State, execState, get, modify)
import Data.Bifunctor (second)
import Data.Char (isDigit)
import Data.Either (fromRight)
import Data.Set as S (Set, delete, empty, filter,
insert, map, member, size)
import Data.Text (Text, pack)
import Data.Void
import Helpers.Graph (Pos)
import Linear.V2 (V2 (..))
import Text.Megaparsec (ParsecT, eof, optional, runParserT,
takeWhileP, try, (<|>))
import Text.Megaparsec.Char (char, eol, string)
import qualified Text.Megaparsec.Char.Lexer as L (decimal, lexeme, space)
type Screen = Set Pos
type Parser = ParsecT Void Text (State (Bool, Screen))
space :: Parser ()
space = void (char ' ') :: Parser ()
spaceConsumer :: Parser ()
spaceConsumer = L.space space A.empty A.empty
decimal :: Parser Int
decimal = L.lexeme spaceConsumer L.decimal
rows test
| test = 3
| otherwise = 6
columns test
| test = 7
| otherwise = 50
parseInput :: Parser ()
parseInput = try parseRect <|> parseRotateR <|> parseRotateC <|> end
end :: Parser ()
end = do
eof
return ()
parseRect :: Parser ()
parseRect = do
string . pack $ "rect "
a <- decimal
char 'x'
b <- decimal
optional eol
modify . second . rect a $ b
parseInput
parseRotateR :: Parser ()
parseRotateR = do
string . pack $ "rotate row y="
index <- decimal
string . pack $ "by "
shift <- decimal
optional eol
modify . rotateR index $ shift
parseInput
parseRotateC :: Parser ()
parseRotateC = do
string . pack $ "rotate column x="
index <- decimal
string . pack $ "by "
shift <- decimal
optional eol
modify . rotateC index $ shift
parseInput
rect :: Int -> Int -> Screen -> Screen
rect a b screen =
foldr insert screen [V2 x y | x <- [0 .. (a - 1)], y <- [0 .. b - 1]]
rotateR :: Int -> Int -> (Bool, Screen) -> (Bool, Screen)
rotateR index shift (test, screen) = (test, foldr insert screen' row')
where
row = S.filter (\(V2 _ y) -> y == index) screen
row' = S.map (\(V2 x y) -> V2 (mod (x + shift) (columns test)) y) row
screen' = foldr delete screen row
rotateC :: Int -> Int -> (Bool, Screen) -> (Bool, Screen)
rotateC index shift (test, screen) = (test, foldr insert screen' column')
where
column = S.filter (\(V2 x _) -> x == index) screen
column' = S.map (\(V2 x y) -> V2 x (mod (y + shift) (rows test))) column
screen' = foldr delete screen column
render :: Bool -> Screen -> String
render test screen = unlines . fmap line $ [0 .. rows test - 1]
where
line y = [point (V2 x y) | x <- [0 .. columns test - 1]]
point p
| p `member` screen = '#'
| otherwise = ' '
part1 :: Bool -> Text -> String
part1 test =
show . size . snd . flip execState (test, empty) . runParserT parseInput ""
part2 :: Bool -> Text -> String
part2 test =
render test . snd . flip execState (test, empty) . runParserT parseInput ""