From 320c134b0e7dd42100c71316223f56c4682b954f Mon Sep 17 00:00:00 2001 From: Neil Smith Date: Fri, 22 Dec 2023 13:09:51 +0000 Subject: [PATCH] Done day 18 --- advent-of-code23.cabal | 8 +++- advent18/Main.hs | 93 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 100 insertions(+), 1 deletion(-) create mode 100644 advent18/Main.hs diff --git a/advent-of-code23.cabal b/advent-of-code23.cabal index 39f88e1..374f201 100644 --- a/advent-of-code23.cabal +++ b/advent-of-code23.cabal @@ -190,7 +190,7 @@ executable advent14 executable advent15 import: common-extensions, build-directives main-is: advent15/Main.hs - build-depends: containers, text, attoparsec, + build-depends: containers, text, attoparsec executable advent16 import: common-extensions, build-directives @@ -201,3 +201,9 @@ executable advent17 import: common-extensions, build-directives main-is: advent17/Main.hs build-depends: containers, linear, array, pqueue, mtl, lens + +executable advent18 + import: common-extensions, build-directives + main-is: advent18/Main.hs + build-depends: linear, text, attoparsec + \ No newline at end of file diff --git a/advent18/Main.hs b/advent18/Main.hs new file mode 100644 index 0000000..7cccd05 --- /dev/null +++ b/advent18/Main.hs @@ -0,0 +1,93 @@ +-- Writeup at https://work.njae.me.uk/2023/12/18/advent-of-code-2023-day-15/ + +import AoC + +import Data.Text (Text) +import qualified Data.Text.Read as TR +import qualified Data.Text.IO as TIO +import Data.Attoparsec.Text hiding (D) +import qualified Data.Attoparsec.Text as AT +-- import Control.Applicative +import Linear (V2(..), (^+^), (^*)) +import Data.List +import Data.Char +import Data.Either + + +data Direction = U | D | L | R deriving (Show, Eq, Ord) +data Instruction = Instr Direction Int deriving (Show, Eq, Ord) + +type Position = V2 Int -- x, y + +main :: IO () +main = + do dataFileName <- getDataFileName + text <- TIO.readFile dataFileName + print $ part1 text + print $ part2 text + +part1 :: Text -> Int +part1 = area . successfulParse instructions1P + +part2 :: Text -> Int +part2 = area . successfulParse instructions2P + +area :: [Instruction] -> Int +area instrs = (shoelace $ mkTrench instrs) + ((perimeter instrs) `div` 2) + 1 + +shoelace :: [Position] -> Int +shoelace ps = (abs $ sum $ zipWith mulPair ps $ tail ps) `div` 2 + where mulPair (V2 x1 y1) (V2 x2 y2) = x1 * y2 - x2 * y1 + +perimeter :: [Instruction] -> Int +perimeter = sum . fmap (\(Instr _ len) -> len) + +mkTrench :: [Instruction] -> [Position] +mkTrench = scanl' move (V2 0 0) + where move here (Instr dir len) = here ^+^ (delta dir ^* len) + +delta :: Direction -> V2 Int +delta U = V2 0 1 +delta D = V2 0 (-1) +delta L = V2 (-1) 0 +delta R = V2 1 0 + +-- Parse the input file + +instructions1P, instructions2P :: Parser [Instruction] +instruction1P, instruction2P :: Parser Instruction +direction1P, direction2P :: Parser Direction +preambleP :: Parser Int + +instructions1P = instruction1P `sepBy` endOfLine +instruction1P = Instr <$> (direction1P <* " ") + <*> (decimal <* " ") + <* (skipWhile (not . isSpace)) + +direction1P = choice [ U <$ "U" + , D <$ "D" + , L <$ "L" + , R <$ "R" + ] + +direction2P = choice [ U <$ "3" + , D <$ "1" + , L <$ "2" + , R <$ "0" + ] + +instructions2P = instruction2P `sepBy` endOfLine + +instruction2P = + instrify <$> (preambleP *> (AT.take 5)) <*> (direction2P <* ")") + +preambleP = (direction1P *> " " *> decimal <* " (#") + +instrify :: Text -> Direction -> Instruction +instrify h d = Instr d (fst $ fromRight (0, "") $ TR.hexadecimal h) + +successfulParse :: Parser [Instruction] -> Text -> [Instruction] +successfulParse parser input = + case parseOnly parser input of + Left _err -> [] -- TIO.putStr $ T.pack $ parseErrorPretty err + Right matches -> matches \ No newline at end of file -- 2.34.1