diff --git a/hs/aoc2024.cabal b/hs/aoc2024.cabal index 1bc53a88..c28694ea 100644 --- a/hs/aoc2024.cabal +++ b/hs/aoc2024.cabal @@ -31,10 +31,7 @@ library build-depends: base ^>=4.20.0.0, containers ^>=0.7, - megaparsec ^>=9.7.0, - mtl ^>=2.3.1, - parser-combinators ^>=1.3.0, - text ^>=2.1.1, + text ^>=2.1.2, ghc-options: -Wall default-language: GHC2024 diff --git a/hs/app/Main.hs b/hs/app/Main.hs index ed87b8a8..a53999cf 100644 --- a/hs/app/Main.hs +++ b/hs/app/Main.hs @@ -12,7 +12,6 @@ import Day2 qualified (part1, part2) import Day3 qualified (part1, part2) import System.Environment (getArgs, lookupEnv) import System.FilePath (combine) -import Text.Megaparsec (errorBundlePretty) getDayInput :: Int -> IO Text getDayInput i = do @@ -35,4 +34,4 @@ main :: IO () main = do run 1 (either fail print) [Day1.part1, Day1.part2] run 2 (either fail print) [Day2.part1, Day2.part2] - run 3 (either (fail . errorBundlePretty) print) [Day3.part1, Day3.part2] + run 3 print [Day3.part1, Day3.part2] diff --git a/hs/src/Day3.hs b/hs/src/Day3.hs index ef3efff6..429de560 100644 --- a/hs/src/Day3.hs +++ b/hs/src/Day3.hs @@ -1,32 +1,24 @@ {-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE PatternSynonyms #-} -- | -- Module: Day3 -- Description: module Day3 (part1, part2) where -import Control.Monad (filterM) -import Control.Monad.State (MonadState (get, put), evalState) import Data.Either (rights) -import Data.Functor (($>)) -import Data.String (IsString) import Data.Text (Text) -import Data.Void (Void) -import Text.Megaparsec (MonadParsec (try), ParseErrorBundle, Stream (Token, Tokens), anySingle, between, many, parse, skipManyTill, (<|>)) -import Text.Megaparsec.Char (char, string) -import Text.Megaparsec.Char.Lexer qualified as L (decimal) +import Data.Text qualified as T (splitOn, pattern (:<)) +import Data.Text.Read qualified as T (decimal) -mul :: (MonadParsec e s m, IsString (Tokens s), Token s ~ Char, Num a) => m a -mul = between (string "mul(") (string ")") $ (*) <$> L.decimal <* char ',' <*> L.decimal +part1 :: Text -> Int +part1 input = + sum + [ a * b + | part <- drop 1 $ T.splitOn "mul(" input, + (a, ',' T.:< part') <- rights [T.decimal part], + (b, ')' T.:< _) <- rights [T.decimal part'] + ] -parser1 :: (MonadParsec e s m, IsString (Tokens s), Token s ~ Char, Num a) => m [a] -parser1 = many $ try $ skipManyTill anySingle $ try mul - -parser2 :: (MonadParsec e s m, IsString (Tokens s), Token s ~ Char, Num a) => m [Either Bool a] -parser2 = many $ try $ skipManyTill anySingle $ Right <$> try mul <|> string "do()" $> Left True <|> string "don't()" $> Left False - -part1 :: Text -> Either (ParseErrorBundle Text Void) Int -part1 = fmap sum . parse parser1 "" - -part2 :: Text -> Either (ParseErrorBundle Text Void) Int -part2 = fmap (sum . rights . flip evalState True . filterM (either (($> False) . put) $ const get)) . parse parser2 "" +part2 :: Text -> Int +part2 input = sum $ part1 <$> (T.splitOn "do()" input >>= take 1 . T.splitOn "don't()") diff --git a/hs/test/Day3Spec.hs b/hs/test/Day3Spec.hs index c9d0ef38..d2c8bd8e 100644 --- a/hs/test/Day3Spec.hs +++ b/hs/test/Day3Spec.hs @@ -21,7 +21,7 @@ spec :: Spec spec = do describe "part 1" $ do it "examples" $ do - part1 example1 `shouldBe` Right 161 + part1 example1 `shouldBe` 161 describe "part 2" $ do it "examples" $ do - part2 example2 `shouldBe` Right 48 + part2 example2 `shouldBe` 48