diff --git a/aoc2024.cabal b/aoc2024.cabal index c18c790..9a01756 100644 --- a/aoc2024.cabal +++ b/aoc2024.cabal @@ -8,7 +8,10 @@ build-type: Simple common common ghc-options: -Wall -O3 - default-extensions: LambdaCase + default-extensions: + LambdaCase + ViewPatterns + build-depends: , base >=4.14 && <5 , parsec >=3 @@ -17,7 +20,6 @@ library libaoc import: common exposed: False hs-source-dirs: lib - build-depends: containers exposed-modules: AoC executable day1 @@ -49,3 +51,11 @@ executable day4alt hs-source-dirs: src main-is: Day4Alt.hs build-depends: libaoc + +executable day5 + import: common + hs-source-dirs: src + main-is: Day5.hs + build-depends: + , containers + , libaoc diff --git a/src/Day5.hs b/src/Day5.hs new file mode 100644 index 0000000..3d9a788 --- /dev/null +++ b/src/Day5.hs @@ -0,0 +1,50 @@ +module Main where + +import qualified AoC as A (extract) +import Data.Bool (bool) +import Data.List (sortBy, tails) +import qualified Data.Set as S +import Text.Parsec (char, digit, many1, newline, parse, sepBy1, sepEndBy1) +import Text.Parsec.String (Parser) + +type Rule = (Int, Int) + +type Rules = S.Set Rule + +type Update = [Int] + +parseRules :: Parser (Rules, [Update]) +parseRules = do + rules <- S.fromList <$> parseRule `sepEndBy1` newline + newline + updates <- parseUpdate `sepEndBy1` newline + return (rules, updates) + where + parseRule :: Parser Rule + parseRule = (,) <$> (read <$> many1 digit <* char '|') <*> (read <$> many1 digit) + parseUpdate :: Parser Update + parseUpdate = (read <$> many1 digit) `sepBy1` char ',' + +middle :: [a] -> a +middle xs = xs !! (length xs `div` 2) + +isOrdered :: Rules -> Update -> Bool +isOrdered rules (first : rest) = all (flip S.member rules . (,) first) rest +isOrdered _ _ = False + +part1 :: Rules -> [Update] -> Int +part1 rules = sum . map middle . filter (all (isOrdered rules) . init . tails) + +part2 :: Rules -> [Update] -> Int +part2 rules = + sum + . map (middle . sortBy (\x -> bool GT LT . flip S.member rules . (,) x)) + . filter (not . all (isOrdered rules) . init . tails) + +main :: IO () +main = + do + raw <- readFile "./inputs/day5.in" + let (rules, updates) = A.extract $ parse parseRules "" raw + putStr "Part 1: " >> print (part1 rules updates) + putStr "Part 2: " >> print (part2 rules updates)