37 lines
1.4 KiB
Haskell
37 lines
1.4 KiB
Haskell
import Common
|
|
import Data.List.Split (splitOn)
|
|
import GHC.Utils.Misc (fstOf3, thdOf3, sndOf3)
|
|
|
|
parse :: String -> [Pos3]
|
|
parse = map ((\[x, y, z] -> (x, y, z)) . map read . splitOn ",") . lines
|
|
|
|
getAdjacentPos3 :: Pos3 -> [Pos3]
|
|
getAdjacentPos3 pos = map (add3 pos) pos3Permutations
|
|
pos3Permutations :: [Pos3]
|
|
pos3Permutations = [(1, 0, 0), (0, 1, 0), (0, 0, 1), (-1, 0, 0), (0, -1, 0), (0, 0, -1)]
|
|
|
|
surfaceArea :: [Pos3] -> [Pos3] -> Pos3 -> Int
|
|
surfaceArea positions air pos = count (\pos -> (pos `elem` air) && notElem pos positions) $ getAdjacentPos3 pos
|
|
|
|
getAirCells :: [Pos3] -> [Pos3]
|
|
getAirCells positions = getAirCells' [] (minX - 1, minY - 1, minZ - 1)
|
|
where
|
|
minX = minimum $ map fstOf3 positions
|
|
maxX = maximum $ map fstOf3 positions
|
|
minY = minimum $ map sndOf3 positions
|
|
maxY = maximum $ map sndOf3 positions
|
|
minZ = minimum $ map thdOf3 positions
|
|
maxZ = maximum $ map thdOf3 positions
|
|
|
|
inBounds (x, y, z) = x >= (minX - 1) && y >= (minY - 1) && z >= (minZ - 1) && x <= (maxX + 1) && y <= (maxY + 1) && z <= (maxZ + 1)
|
|
|
|
getAirCells' :: [Pos3] -> Pos3 -> [Pos3]
|
|
getAirCells' visited pos = (foldl getAirCells' (pos : (visited ++ adjacent)) adjacent)
|
|
where
|
|
validPos pos = inBounds pos && notElem pos visited && notElem pos positions
|
|
adjacent = filter validPos $ getAdjacentPos3 pos
|
|
|
|
main = interact $
|
|
show
|
|
. (\cubes -> sum $ map (surfaceArea cubes (getAirCells cubes)) cubes)
|
|
. parse |