diff options
author | Julien Dessaux | 2024-12-10 09:27:43 +0100 |
---|---|---|
committer | Julien Dessaux | 2024-12-10 09:27:43 +0100 |
commit | f8251081772e217ad537937cd48bb7e3f0541974 (patch) | |
tree | 4ab6a0c958898b2662f971f5c53a924f6024e2c0 /2024/10-Hoof_It/first.hs | |
parent | 2024-09 in haskell (diff) | |
download | advent-of-code-f8251081772e217ad537937cd48bb7e3f0541974.tar.gz advent-of-code-f8251081772e217ad537937cd48bb7e3f0541974.tar.bz2 advent-of-code-f8251081772e217ad537937cd48bb7e3f0541974.zip |
2024-10 in haskell
Diffstat (limited to '')
-rw-r--r-- | 2024/10-Hoof_It/first.hs | 64 |
1 files changed, 64 insertions, 0 deletions
diff --git a/2024/10-Hoof_It/first.hs b/2024/10-Hoof_It/first.hs new file mode 100644 index 0000000..878a30a --- /dev/null +++ b/2024/10-Hoof_It/first.hs @@ -0,0 +1,64 @@ +-- requires cabal install --lib megaparsec parser-combinators heap vector +module Main (main) where + +import Control.Monad (void, when) +import qualified Data.Set as S +import qualified Data.Vector as V +import qualified Data.Vector.Unboxed as VU +import Data.Void (Void) +import Text.Megaparsec +import Text.Megaparsec.Char + +exampleExpectedOutput = 36 + +type Line = VU.Vector Int +type Input = V.Vector Line + +type Parser = Parsec Void String + +parseNumber :: Parser Int +parseNumber = read . pure <$> digitChar + +parseLine :: Parser Line +parseLine = do + line <- some parseNumber <* eol + return $ VU.generate (length line) (line !!) + +parseInput' :: Parser Input +parseInput' = do + line <- some parseLine <* eof + return $ V.generate (length line) (line !!) + +parseInput :: String -> IO Input +parseInput filename = do + input <- readFile filename + case runParser parseInput' filename input of + Left bundle -> error $ errorBundlePretty bundle + Right input' -> return input' + +compute :: Input -> Int +compute input = sum $ V.imap scoreLine input + where + scoreLine :: Int -> VU.Vector Int -> Int + scoreLine y line = VU.sum $ VU.imap (\x c -> score x y c) line + score :: Int -> Int -> Int -> Int + score x y c | c == 0 = S.size $ reachableSummits 0 (x, y) + | otherwise = 0 + reachableSummits :: Int -> (Int, Int) -> S.Set (Int, Int) + reachableSummits h (x, y) | h == 9 = S.singleton (x, y) + | otherwise = S.unions $ map (reachableSummits (h+1)) succ + where + succ = filter valid [(x-1, y), (x+1, y), (x, y-1), (x, y+1)] + valid (x, y) = case input V.!? y of + Just line -> case line VU.!? x of + Just h' -> h+1 == h' + _ -> False + _ -> False + +main :: IO () +main = do + example <- parseInput "example" + let exampleOutput = compute example + when (exampleOutput /= exampleExpectedOutput) (error $ "example failed: got " ++ show exampleOutput ++ " instead of " ++ show exampleExpectedOutput) + input <- parseInput "input" + print $ compute input |