-
Notifications
You must be signed in to change notification settings - Fork 0
/
Day8.hs
70 lines (58 loc) · 2.26 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
{-# LANGUAGE TupleSections #-}
module Day8
( part1
, part2
) where
import Data.Array.Unboxed (UArray, assocs, bounds, range)
import Data.Char (isAlphaNum)
import Data.Function (on)
import Data.HashSet (HashSet, empty, insert, size)
import Data.List (groupBy, sortBy, tails)
import Data.Ord (comparing)
import Data.Ratio ((%))
import Data.Text (Text)
import Data.Tuple (swap)
import Helpers.Graph (Pos)
import Helpers.Parsers.Text (arrayFromText)
import Linear.V2 (V2 (..))
type Frequency = [Pos]
type Grid = UArray Pos Char
type Rule = ([Pos] -> (Pos, Pos) -> [Pos])
findAntinodes :: [Pos] -> (Pos, Pos) -> [Pos]
findAntinodes pos (V2 x0 y0, V2 x1 y1) = filter (\x -> dist x && inLine x) pos
where
inLine (V2 x y)
| y0 == y1 = y == y0
| otherwise = y /= y0 && (x - x0) % (y - y0) == (x1 - x0) % (y1 - y0)
dist (V2 x y) =
(x - x0) ^ 2 + (y - y0) ^ 2 + (x - x1) ^ 2 + (y - y1) ^ 2
== 5 * ((x0 - x1) ^ 2 + (y0 - y1) ^ 2)
findAligned :: [Pos] -> (Pos, Pos) -> [Pos]
findAligned pos (p1@(V2 x0 y0), V2 x1 y1) = p1 : filter inLine pos
where
inLine (V2 x y)
| y0 == y1 = y == y0
| otherwise = y /= y0 && (x - x0) % (y - y0) == (x1 - x0) % (y1 - y0)
frequencyAntinodes :: [Pos] -> Rule -> Frequency -> (HashSet Pos -> HashSet Pos)
frequencyAntinodes pos rule frequency = foldr (.) id antinodes
where
antinodes = zipWith freqFold <*> (tail . tails) $ frequency
freqFold p = foldr ((.) . flip (foldr insert) . rule pos . (p, )) id
buildAntennas :: Grid -> [Frequency]
buildAntennas =
map (foldr ((:) . snd) [])
. groupBy ((==) `on` fst)
. sortBy (comparing fst)
. map swap
. filter (isAlphaNum . snd)
. assocs
findAllAntinodes :: Rule -> Grid -> Int
findAllAntinodes rule grid =
size . foldr (frequencyAntinodes pos rule) empty $ antennas
where
antennas = buildAntennas grid
pos = range . bounds $ grid
part1 :: Bool -> Text -> String
part1 _ = show . findAllAntinodes findAntinodes . arrayFromText
part2 :: Bool -> Text -> String
part2 _ = show . findAllAntinodes findAligned . arrayFromText