-
Notifications
You must be signed in to change notification settings - Fork 0
/
Day9.hs
59 lines (44 loc) · 1.59 KB
/
Day9.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
module Day9
( part1
, part2
) where
import Data.Array.Unboxed as A (UArray, bounds, inRange, range, (!))
import Data.List (sortBy)
import Data.Set (Set, empty, fromList, insert)
import Helpers.Parsers (digitArrayFromString)
import Helpers.Search (floodFill, treeSize)
import Linear.V2 (V2 (..))
type Pos = V2 Int
type HeightMap = UArray Pos Int
up = V2 0 (-1)
down = V2 0 1
right = V2 1 0
left = V2 (-1) 0
fourDirs = [up, down, left, right]
neighbours :: HeightMap -> Pos -> [Pos]
neighbours heightMap pos =
filter (bounds heightMap `inRange`) . map (pos +) $ fourDirs
isLowPoint :: HeightMap -> Pos -> Bool
isLowPoint heightMap pos =
(heightMap ! pos <) . minimum . map (heightMap !) . neighbours heightMap $ pos
lowPoints :: HeightMap -> [Pos]
lowPoints heightMap = filter (isLowPoint heightMap) . range . bounds $ heightMap
scoreLowPoints :: HeightMap -> Int
scoreLowPoints heightMap =
sum . map ((1 +) . (!) heightMap) . lowPoints $ heightMap
basins :: HeightMap -> [Int]
basins heightMap = sortBy (flip compare) . map treeSize . floodFill edges $ pos
where
pos = lowPoints heightMap
edges =
map
(\x ->
( heightMap ! x
, x
, filter ((< 9) . (!) heightMap) . neighbours heightMap $ x)) .
filter ((< 9) . (!) heightMap) . range . bounds $
heightMap
part1 :: Bool -> String -> String
part1 _ = show . scoreLowPoints . digitArrayFromString
part2 :: Bool -> String -> String
part2 _ = show . product . take 3 . basins . digitArrayFromString