-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathDay22.hs
67 lines (56 loc) · 2.63 KB
/
Day22.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
module Day22 where
import qualified Data.Map as M
import qualified Data.Set as S
import Data.List.Split (splitOn)
import Debug.Trace (traceShow)
import Data.List (delete, mapAccumL, sortOn)
import Control.Parallel.Strategies
type Coord = (Int, Int, Int)
type Brick = (Coord, Coord)
type World = M.Map (Int, Int) (S.Set (Int, Int))
fall :: World -> Brick -> (World, Brick)
fall world ((bfx,bfy,bfz), (btx,bty,btz)) = (newWorld, newBrick) where
coords = [(x,y) | x <- [bfx .. btx], y <- [bfy..bty]]
fallxy (x,y) = 1 + maybe 0 snd (S.lookupLT (bfz,btz) (world M.! (x,y)))
fallAmount = bfz - maximum (map fallxy coords)
newBrick = ((bfx,bfy,bfz-fallAmount), (btx,bty,btz-fallAmount))
updatexy = S.insert (bfz-fallAmount, btz-fallAmount) . S.delete (bfz,btz)
newWorld = foldr (M.adjust updatexy) world coords
fallAll :: World -> [Brick] -> (World, [Brick])
fallAll = mapAccumL fall
conv :: Eq c => (c -> c) -> c -> c
conv f x = let x' = f x in if x == x' then x else conv f x'
fallConv :: [Brick] -> (World, [Brick])
fallConv bs = conv (uncurry fallAll) (initWorld bs, bs)
initWorld :: [Brick] -> World
initWorld = foldr insertBrick M.empty where
insertBrick :: Brick -> World -> World
insertBrick ((bfx,bfy,bfz), (btx,bty,btz)) m = foldr (M.alter (Just . ins)) m coords where
ins Nothing = S.singleton (bfz, btz)
ins (Just s) = S.insert (bfz, btz) s
coords = [(x,y) | x <- [bfx .. btx], y <- [bfy..bty]]
canDisintegrate :: [Brick] -> World -> Brick -> Bool
canDisintegrate bs w b@((bfx,bfy,bfz), (btx,bty,btz)) = fallb == b'
where
coords = [(x,y) | x <- [bfx .. btx], y <- [bfy..bty]]
b' = delete b bs
w' = foldr (M.adjust (S.delete (bfz, btz))) w coords
(fallw, fallb) = fallAll w' b'
canDisintegrateX :: [Brick] -> World -> Brick -> Int
canDisintegrateX bs w b@((bfx,bfy,bfz), (btx,bty,btz)) = diffs fallb b'
where
coords = [(x,y) | x <- [bfx .. btx], y <- [bfy..bty]]
b' = delete b bs
w' = foldr (M.adjust (S.delete (bfz, btz))) w coords
(fallw, fallb) = conv (uncurry fallAll) (w', b')
diffs xs ys = sum $ zipWith (\x y -> if x /= y then 1 else 0) xs ys
readCoord :: String -> (Int, Int, Int)
readCoord xs = read ("(" ++ xs ++ ")")
readBrick :: [Char] -> ((Int, Int, Int), (Int, Int, Int))
readBrick xs = let [f,t] = splitOn "~" xs in (readCoord f, readCoord t)
main :: IO ()
main = do
input <- sortOn (\(_, (x,y,z)) -> z) . map readBrick . lines <$> getContents
let (w, bs) = fallConv input
putStr "part 1: "; print $ length $ filter (canDisintegrate bs w) bs
putStrLn "part 2: "; print $ sum $ parMap rseq (canDisintegrateX bs w) bs