-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathDay18.hs
73 lines (60 loc) · 2.2 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
{-# LANGUAGE TupleSections #-}
module Day18 (solve) where
import Data.Function ( (&) )
import Data.List
import qualified Data.List.Split as Split
import qualified Data.Set as Set
solve input lines = do
let cubes = readCubes lines
let uncovered cubes = cubes & map ((6 -) . countCovered cubes) & sum
print $ uncovered cubes
let maxs = maximums cubes
let water = findWater cubes maxs
let notWater = complement water maxs & Set.toList
print $ uncovered notWater
findWater cubeList (maxX, maxY, maxZ)= do
let expansions = unfoldr expand (Set.singleton (0, 0, 0))
let pairs = pairwise expansions
let (Just (water, _)) = find ( \ (a, b) -> a == b) pairs
water
where
cubes = Set.fromList cubeList
expand water = do
let newWater = water & concatMap (expandPos water) & nub
let water' = foldl (flip Set.insert) water newWater
Just (water', water')
expandPos water pos = do
neighbours pos
& filter (\ candidate@(x, y, z) ->
0 <= x && x <= maxX
&& 0 <= y && y <= maxY
&& 0 <= z && z <= maxZ
&& not (Set.member candidate water)
&& not (Set.member candidate cubes))
complement water (maxX, maxY, maxZ) =
[0 .. maxZ] & concatMap (\ z ->
[0 .. maxY] & concatMap (\ y ->
[0 .. maxX] & map (, y, z) ))
& Set.fromList
& (`Set.difference` water)
neighbours (x, y, z) =
map (\ (dx, dy, dz) -> (x + dx, y + dy, z + dz))
[ (1, 0, 0), (0, 1, 0), (0, 0, 1) , (-1, 0, 0), (0, -1, 0), (0, 0, -1)]
countCovered cubes cube = cubes & filter ((== 1). dist cube) & length
dist (x, y, z) (x', y', z') = abs (x' - x) + abs (y' - y) + abs (z' - z)
maximums coords = do
let maxX = coords & map x & maximum
let maxY = coords & map y & maximum
let maxZ = coords & map z & maximum
(maxX, maxY, maxZ)
where
x (n, _, _) = n :: Int
y (_, n, _) = n :: Int
z (_, _, n) = n :: Int
pairwise lst = zip lst (tail lst)
readCubes =
map readLine
where
readLine line = do
let [x, y, z] = line & Split.splitOn "," & map read :: [Int]
(x, y, z)