-
Notifications
You must be signed in to change notification settings - Fork 0
/
aoc18.hs
49 lines (45 loc) · 1.62 KB
/
aoc18.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
import qualified Data.Set as S
import System.Environment (getArgs)
neigh3d :: (Int, Int, Int) -> [(Int, Int, Int)]
neigh3d (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)
]
main :: IO ()
main = do
-- parse input
args <- getArgs
let filename =
if null args
then "aoc18.in"
else head args
s <- lines <$> readFile filename
let pts = map (\ln -> read $ "(" ++ ln ++ ")") s
-- part 1
let ptSet = S.fromList pts
print $ length [n | p <- pts, n <- neigh3d p, S.notMember n ptSet]
-- part 2
let untilEq f x = let y = f x in if x == y then y else untilEq f y
let allnums = concatMap (\(a, b, c) -> [a, b, c]) pts
let inbounds =
let a = minimum allnums
b = maximum allnums
in ( \(x, y, z) ->
a - 1 <= x && x <= b + 1
&& a - 1 <= y && y <= b + 1
&& a - 1 <= z && z <= b + 1
)
let nbhd pt = neigh3d pt ++ [pt]
-- Experimentally, using two points as a start is much faster than using one.
-- Adding more starting points though seems to slow things down.
let air =
untilEq (S.fromList . filter inbounds . filter (`S.notMember` ptSet) . concatMap nbhd . S.toList) $
S.fromList
[ (minimum allnums - 1, minimum allnums, minimum allnums)
, (maximum allnums + 1, maximum allnums, maximum allnums)
]
print $ length [n | p <- pts, n <- neigh3d p, n `S.member` air]