X-Git-Url: https://git.njae.me.uk/?a=blobdiff_plain;f=advent18%2FMain.hs;fp=advent18%2FMain.hs;h=f16e6df81b724ad182279f30f98477b7ecf63a1f;hb=2b58adc795652b845b6ceba6eebab9cfd01f401a;hp=0000000000000000000000000000000000000000;hpb=ba1fb8a459ef5514a246e66557fab4507824918e;p=advent-of-code-22.git diff --git a/advent18/Main.hs b/advent18/Main.hs new file mode 100644 index 0000000..f16e6df --- /dev/null +++ b/advent18/Main.hs @@ -0,0 +1,72 @@ +-- Writeup at https://work.njae.me.uk/2022/12/19/advent-of-code-2022-day-18/ + +import AoC +import Data.Text (Text) +import qualified Data.Text.IO as TIO +import Data.Attoparsec.Text hiding (take, D) +-- import Control.Applicative +import qualified Data.Set as S +import Linear +import Control.Lens +import Data.Ix +import Data.Maybe + +type Droplet = V3 Int +type Lava = S.Set Droplet + +main :: IO () +main = + do dataFileName <- getDataFileName + text <- TIO.readFile dataFileName + let lava = successfulParse text + print $ part1 lava + print $ part2 lava + +part1, part2 :: Lava -> Int +part1 lava = surfaceArea lava + +part2 lava = surfaceArea enclosed + where box = boundingBox lava + steam = floodFill lava box (S.singleton $ head $ range box) S.empty + enclosed = (S.fromList (range box)) `S.difference` steam + +surfaceArea :: Lava -> Int +surfaceArea lava = sum $ fmap countFree $ S.elems lava + where countFree droplet = 6 - (S.size $ S.intersection lava (neigbours droplet)) + +neigbours :: Droplet -> Lava +neigbours here = S.fromList [ here & d %~ (+) n | d <- [_x, _y, _z], n <- [- 1, 1]] + +boundingBox :: Lava -> (Droplet, Droplet) +boundingBox lava = ((V3 minX minY minZ), (V3 maxX maxY maxZ)) + where minX = (fromJust $ minimumOf (folded . _x) lava) - 1 + minY = (fromJust $ minimumOf (folded . _y) lava) - 1 + minZ = (fromJust $ minimumOf (folded . _z) lava) - 1 + maxX = (fromJust $ maximumOf (folded . _x) lava) + 1 + maxY = (fromJust $ maximumOf (folded . _y) lava) + 1 + maxZ = (fromJust $ maximumOf (folded . _z) lava) + 1 + +floodFill :: Lava -> (Droplet, Droplet) -> Lava -> Lava -> Lava +floodFill lava box boundary found + | S.null boundary = found + | otherwise = floodFill lava box (S.union nbrs $ S.delete here boundary) (S.insert here found) + where here = S.findMin boundary + nbrs = S.filter (`S.notMember` lava) + $ S.filter (`S.notMember` boundary) + $ S.filter (`S.notMember` found) + $ S.filter (inRange box) + $ neigbours here + +-- Parse the input file + +lavaP :: Parser Lava +dropletP :: Parser Droplet + +lavaP = S.fromList <$> dropletP `sepBy` endOfLine +dropletP = V3 <$> (decimal <* ",") <*> (decimal <* ",") <*> decimal + +successfulParse :: Text -> Lava +successfulParse input = + case parseOnly lavaP input of + Left _err -> S.empty -- TIO.putStr $ T.pack $ parseErrorPretty err + Right lava -> lava