-
Notifications
You must be signed in to change notification settings - Fork 0
/
run.hs
97 lines (80 loc) · 2.28 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
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE TypeApplications #-}
import AoC
import Data.Foldable (toList)
import Data.List (partition)
import Data.List.Split (splitOn)
import Data.Set (Set)
import qualified Data.Set as Set
type N = Int
v3FromList :: [a] -> V3 a
v3FromList [x,y,z] = v3 (x, y, z)
parse :: String -> V3 N
parse = v3FromList . map (read @N) . splitOn ","
parseAll :: String -> [V3 N]
parseAll = map parse . lines
connected :: [V3 N] -> [(V3 N, V3 N)]
connected nodes =
let nset = Set.fromList nodes
in
[ (c1, c2)
| c1 <- nodes
, c2 <- hvNeighbors3 c1
, c2 `Set.member` nset
]
part1 :: [V3 N] -> Int
part1 nodes =
let conn = length (connected nodes)
in length nodes * 6 - conn
side :: N -> [V2 N]
side b = [ v2 (x, y)
| x <- [0..b]
, y <- [0..b]
]
hvNeighbors3 :: V3 N -> [V3 N]
hvNeighbors3 n =
[ n + v3 (1, 0, 0)
, n + v3 (-1, 0, 0)
, n + v3 (0, 1, 0)
, n + v3 (0, -1, 0)
, n + v3 (0, 0, 1)
, n + v3 (0, 0, -1)
]
fill :: N -> [V3 N] -> Int
fill b nodes = go (Set.fromList initial) 0 initial
where nset = Set.fromList nodes
go !visited !acc =
\case
[] -> acc
n:rest ->
let (hits, nexts) = partition (`Set.member` nset)
. filter (valid visited)
$ hvNeighbors3 n
in
go (Set.fromList nexts `Set.union` visited)
(acc + length hits)
(nexts ++ rest)
valid visited n =
all (\c -> c >= 0 && c <= b) n
&& not (n `Set.member` visited)
initial = map (extendX' (-1)) (side b)
++ map (extendX' (b + 1)) (side b)
++ map (extendY' (-1)) (side b)
++ map (extendY' (b + 1)) (side b)
++ map (extendZ' (-1)) (side b)
++ map (extendZ' (b + 1)) (side b)
part2 :: [V3 N] -> Int
part2 nodes =
let b = maximum $ concatMap toList nodes
in fill b nodes
main :: IO ()
main = main' "input.txt"
exampleMain :: IO ()
exampleMain = main' "example.txt"
main' :: FilePath -> IO ()
main' file = do
input <- parseAll <$> readFile file
print (part1 input)
print (part2 input)