-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrun.hs
110 lines (92 loc) · 2.6 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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE TypeApplications #-}
-- TODO: Clean up
import AoC
import AoC.Grid
import Data.Char (isDigit)
import Data.Bifunctor
import Data.Foldable
import Data.List
import Data.List.Split
import Data.Maybe
import Control.Monad (guard)
import Data.Ord
import Data.Map.Strict (Map)
import qualified Data.Map.Strict as Map
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
type N = Int
parse = HashMap.filter (/= '.') . parseMapGrid id
neighbors (ci, ri) =
[ (ci + cd, ri + rd) | rd <- [-1, 0, 1]
, cd <- [-1, 0, 1]
, not (rd == 0 && cd == 0)
]
collect numbers (n@(ci, ri), x) =
let l = leftsOf numbers n
r = rightsOf numbers n
res = l <> [x] <> r
in
( (ci - length l, ri)
, length res
, read @N res
)
leftsOf numbers = go
where go (ci, ri) =
let next = (ci - 1, ri)
in case numbers HashMap.!? next of
Just c | isDigit c -> go next <> [c]
_ -> []
rightsOf numbers = go
where go (ci, ri) =
let next = (ci + 1, ri)
in case numbers HashMap.!? next of
Just c | isDigit c -> c:go next
_ -> []
partNumbers g =
let numbers = HashMap.filter isDigit g
symbols = HashMap.keys $ g `HashMap.difference` numbers
startNums = do
s <- symbols
n <- neighbors s
x <- toList $ numbers HashMap.!? n
pure (n, x)
in
Set.fromList $ map (collect numbers) startNums
gearNumbers g =
let parts = toList $ partNumbers g
-- (ci, ri) -> part
partMap = HashMap.fromList do
p@((ci, ri), len, _) <- parts
i <- [0..len - 1]
pure ((ci + i, ri), p)
gearSyms = HashMap.keys $ HashMap.filter (== '*') g
in do
gear <- gearSyms
let adj = toList $ Set.fromList do
n <- neighbors gear
p <- toList $ partMap HashMap.!? n
pure p
guard $ length adj == 2
pure (gear, map thd adj)
thd (_, _, z) = z
part1 = sum . map thd . toList . partNumbers
part2 = sum . map (product . snd) . gearNumbers
main :: IO ()
main = main' "input.txt"
exampleMain :: IO ()
exampleMain = main' "example.txt"
main' :: FilePath -> IO ()
main' file = do
input <- parse <$> readFile file
print (part1 input)
print (part2 input)