Done day 18
authorNeil Smith <NeilNjae@users.noreply.github.com>
Fri, 22 Dec 2023 13:09:51 +0000 (13:09 +0000)
committerNeil Smith <NeilNjae@users.noreply.github.com>
Fri, 22 Dec 2023 13:09:51 +0000 (13:09 +0000)
advent-of-code23.cabal
advent18/Main.hs [new file with mode: 0644]

index 39f88e1390675edaf8f346eccb4ef97586bcaef8..374f2015f10d1eeafd3135f4f80a787652616c4e 100644 (file)
@@ -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 (file)
index 0000000..7cccd05
--- /dev/null
@@ -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