-
Notifications
You must be signed in to change notification settings - Fork 4
/
Day18.hs
40 lines (36 loc) · 1.69 KB
/
Day18.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
{-|
Module: Day18
Description: <https://adventofcode.com/2022/day/18 Day 18: Boiling Boulders>
-}
module Day18 (day18a, day18b) where
import Common (count)
import Control.Arrow ((&&&))
import Data.Ix (inRange)
import Data.List (foldl')
import Data.Semigroup (Max(Max), Min(Min))
import qualified Data.Set as Set (fromList, insert, member, notMember, singleton)
import Data.Text (Text)
import qualified Data.Text as T (cons, lines, unpack, snoc)
neighbors :: (Num a) => (a, a, a) -> [(a, a, a)]
neighbors (x, y, z) =
[(x - 1, y, z), (x + 1, y, z), (x, y - 1, z), (x, y + 1, z), (x, y, z - 1), (x, y, z + 1)]
day18a :: Text -> Int
day18a input = count (`Set.notMember` points') $ points >>= neighbors where
points = read @(Int, Int, Int) . T.unpack . T.cons '(' . flip T.snoc ')' <$> T.lines input
points' = Set.fromList points
day18b :: Text -> Int
day18b input = count (`Set.member` outside) $ points >>= neighbors where
points = read @(Int, Int, Int) . T.unpack . T.cons '(' . flip T.snoc ')' <$> T.lines input
points' = Set.fromList points
((Min minX, Max maxX), (Min minY, Max maxY), (Min minZ, Max maxZ)) = mconcat
[(Min &&& Max $ x, Min &&& Max $ y, Min &&& Max $ z) | (x, y, z) <- points]
outside = let start = (minX - 1, minY - 1, minZ - 1) in dfs (Set.singleton start) [start]
dfs seen [] = seen
dfs seen (point:q) = dfs (foldl' (flip Set.insert) seen next) $ next ++ q where
next = filter ok $ neighbors point
ok point@(x, y, z) =
inRange (minX - 1, maxX + 1) x &&
inRange (minY - 1, maxY + 1) y &&
inRange (minZ - 1, maxZ + 1) z &&
Set.notMember point points' &&
Set.notMember point seen