-
Notifications
You must be signed in to change notification settings - Fork 0
/
run.hs
94 lines (78 loc) · 2.06 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
82
83
84
85
86
87
88
89
90
91
92
93
94
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE TypeApplications #-}
import AoC
import AoC.Grid
import Control.Monad (guard)
import Data.List (groupBy, sortBy)
import Data.Ord (comparing)
import Data.HashMap.Strict (HashMap)
import qualified Data.HashMap.Strict as HashMap
import Data.Set (Set)
import qualified Data.Set as Set
type N = Int
type Input = (MapGrid Char, (N, N))
parseAll :: String -> Input
parseAll input =
let g = parseMapGrid id input
in
( g
, maximum $ HashMap.keys g)
-- TODO: Extract to AoC
pairs :: [a] -> [(a, a)]
pairs l = go l l
where go [] [] = []
go (_:xs) [] = go xs xs
go (x:xs) (y:ys) = (x, y):go (x:xs) ys
antinodes :: [((N, N), a)] -> [V2 N]
antinodes l = do
((a, _), (b, _)) <- pairs l
guard $ a /= b
let av = v2 a
bv = v2 b
d = av - bv
[ bv + 2 * d,
av - 2 * d ]
letters :: MapGrid Char -> [[((N, N), Char)]]
letters g = groupBy (\(_, v1) (_, v2) -> v1 == v2)
$ sortBy (comparing snd)
[(k, v) | (k, v) <- HashMap.toList g
, v /= '.'
]
part1 :: Input -> Int
part1 (g, bounds) =
length
. Set.fromList
. filter (inBounds bounds)
. concatMap antinodes
$ letters g
inBounds :: (N, N) -> V2 N -> Bool
inBounds (w, h) (V2 (x, y)) =
0 <= x && x <= w && 0 <= y && y <= h
antinodes' :: (N, N) -> [((N, N), a)] -> [V2 N]
antinodes' bounds l = do
((a, _), (b, _)) <- pairs l
guard $ a /= b
let av = v2 a
bv = v2 b
d = av - bv
concat [ takeWhile (inBounds bounds) $ map (\k -> bv + fromInteger k * d) [0..]
, takeWhile (inBounds bounds) $ map (\k -> av - fromInteger k * d) [0..]
]
part2 :: Input -> Int
part2 (g, bounds) =
length
. Set.fromList
. concatMap (antinodes' bounds)
$ letters g
main :: IO ()
main = main' "input.txt"
exampleMain :: IO ()
exampleMain = main' "example.txt"
main' :: FilePath -> IO ()
main' file = do
input <- parseAll <$> readFile file
print (part1 input)
print (part2 input)