-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrun.hs
83 lines (66 loc) · 2.03 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
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE TypeApplications #-}
import AoC
import AoC.Grid
import Data.Foldable
import Data.Bits (xor)
import Data.Ord (comparing)
import Data.Bifunctor
import Data.Maybe
import Data.List
import Data.HashMap.Strict (HashMap)
import qualified Data.HashMap.Strict as HashMap
import Data.Sequence (Seq)
import qualified Data.Sequence as Seq
import Data.Set (Set)
import qualified Data.Set as Set
import Data.IntSet (IntSet)
import qualified Data.IntSet as IntSet
parseAll = readMapGrid @Int
type Pos = (Int, Int)
neighbors :: Pos -> [Pos]
neighbors (i, j) = [ (i + dx, j + dy) | dx <- [-1..1]
, dy <- [-1..1]
, not (dx == 0 && dy == 0) ]
hv :: Pos -> [Pos]
hv (i, j) = [ (i + dx, j + dy) | dx <- [-1..1]
, dy <- [-1..1]
, dx == 0 || dy == 0 ]
hvNeighbors :: MapGrid Int -> Pos -> [(Pos, Int)]
hvNeighbors m =
mapMaybe (\pos -> sequence (pos, pos `HashMap.lookup` m))
. hv
neighborVals :: MapGrid Int -> Pos -> [Int]
neighborVals m = mapMaybe (`HashMap.lookup` m) . neighbors
lowPoints :: MapGrid Int -> HashMap Pos Int
lowPoints m = HashMap.filterWithKey f m
where f pos val = all (> val) $ neighborVals m pos
basin :: MapGrid Int -> Pos -> Int -> Set (Pos, Int)
basin m pos val = fixpoint f (Set.singleton (pos, val))
where f :: Set (Pos, Int) -> Set (Pos, Int)
f b = Set.union b . Set.unions . Set.map expand $ b
expand (k, v) =
Set.fromList
. filter (validExpand v . snd)
$ hvNeighbors m k
validExpand v v' = v < v' && v' < 9
part1 =
sum
. map (+1)
. toList
. lowPoints
part2 m =
product
. take 3
. sortBy (comparing negate)
. map length
. toList
$ HashMap.mapWithKey (basin m) (lowPoints m)
main = main' "input.txt"
exampleMain = main' "example.txt"
main' file = do
input <- parseAll <$> readFile file
print (part1 input)
print (part2 input)