-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathDay18.hs
113 lines (102 loc) · 3.57 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
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
111
112
113
module Day18 (part1, part2) where
import Text.Regex.TDFA (getAllTextMatches, (=~))
import Data.Array (Array, array, bounds, inRange, (!))
import Data.Map as M (Map, empty, findWithDefault, fromList,
insert, lookup)
import Data.Maybe (isNothing)
import Data.Sequence as S (Seq ((:<|), (:|>)), fromList)
import Linear.V3 (V3 (..))
type Cube = V3 Int
type Grid = Array Cube Bool
type Air = Map Cube Bool
vars = [V3 1 0 0, V3 (-1) 0 0, V3 0 1 0, V3 0 (-1) 0, V3 0 0 1, V3 0 0 (-1)]
parseLine :: String -> Cube
parseLine s = V3 (read x) (read y) (read z)
where
(x:y:z:_) = getAllTextMatches (s =~ "[0-9]+") :: [String]
countSides :: Grid -> Air -> Cube -> Int
countSides grid air cube = sides
where
neighbours = map (cube +) vars
sides = length $ filter isFree neighbours
gridBounds = bounds grid
isFree c =
not (inRange gridBounds c) ||
(not (grid ! c) && findWithDefault False c air)
countAccum :: Grid -> Air -> Int -> Cube -> Int
countAccum grid air acc cube = acc + countSides grid air cube
airFill :: Grid -> Seq Cube -> Air -> Air
airFill grid seq air
| null seq = air
| otherwise = airFill grid toSee (insert s True air)
where
(s :<| xs) = seq
gridBounds = bounds grid
neighbours = map (s +) vars
toSee = foldl (:|>) xs $ filter isEmpty neighbours
isEmpty c =
inRange gridBounds c && not (grid ! c) && isNothing (M.lookup c air)
part1 :: Bool -> String -> String
part1 _ input = show . foldl (countAccum grid nothing) 0 $ cubes
where
cubes = map parseLine $ lines input
minX = minimum . map (\(V3 x y z) -> x) $ cubes
minY = minimum . map (\(V3 x y z) -> y) $ cubes
minZ = minimum . map (\(V3 x y z) -> z) $ cubes
maxX = maximum . map (\(V3 x y z) -> x) $ cubes
maxY = maximum . map (\(V3 x y z) -> y) $ cubes
maxZ = maximum . map (\(V3 x y z) -> z) $ cubes
grid =
array
(V3 minX minY minZ, V3 maxX maxY maxZ)
[ (V3 x y z, V3 x y z `elem` cubes)
| x <- [minX .. maxX]
, y <- [minY .. maxY]
, z <- [minZ .. maxZ]
]
edges =
S.fromList
[ V3 x y z
| x <- [minX .. maxX]
, y <- [minY .. maxY]
, z <- [minZ .. maxZ]
, (x == minX ||
x == maxX || y == minY || y == maxY || z == minZ || z == maxZ) &&
not (grid ! V3 x y z)
]
nothing =
M.fromList
[ (V3 x y z, True)
| x <- [minX .. maxX]
, y <- [minY .. maxY]
, z <- [minZ .. maxZ]
]
part2 :: Bool -> String -> String
part2 _ input = show $ foldl (countAccum grid air) 0 cubes
where
cubes = map parseLine $ lines input
minX = minimum . map (\(V3 x y z) -> x) $ cubes
minY = minimum . map (\(V3 x y z) -> y) $ cubes
minZ = minimum . map (\(V3 x y z) -> z) $ cubes
maxX = maximum . map (\(V3 x y z) -> x) $ cubes
maxY = maximum . map (\(V3 x y z) -> y) $ cubes
maxZ = maximum . map (\(V3 x y z) -> z) $ cubes
grid =
array
(V3 minX minY minZ, V3 maxX maxY maxZ)
[ (V3 x y z, V3 x y z `elem` cubes)
| x <- [minX .. maxX]
, y <- [minY .. maxY]
, z <- [minZ .. maxZ]
]
edges =
S.fromList
[ V3 x y z
| x <- [minX .. maxX]
, y <- [minY .. maxY]
, z <- [minZ .. maxZ]
, (x == minX ||
x == maxX || y == minY || y == maxY || z == minZ || z == maxZ) &&
not (grid ! V3 x y z)
]
air = airFill grid edges empty