diff --git a/hs/src/Aoc/Day.hs b/hs/src/Aoc/Day.hs index 90d9641..83fe1b6 100644 --- a/hs/src/Aoc/Day.hs +++ b/hs/src/Aoc/Day.hs @@ -34,6 +34,6 @@ dayText name f = dayFile name $ f <=< T.readFile dayParse :: String -> Parser a -> (a -> IO ()) -> Day dayParse name p f = dayFile name $ \path -> do text <- T.readFile path - case parse p path text of + case parse (p <* eof) path text of Right a -> f a Left e -> putStrLn $ errorBundlePretty e diff --git a/hs/src/Aoc/Parse.hs b/hs/src/Aoc/Parse.hs index d6d62d7..ab3e01d 100644 --- a/hs/src/Aoc/Parse.hs +++ b/hs/src/Aoc/Parse.hs @@ -4,9 +4,12 @@ module Aoc.Parse , module Text.Megaparsec.Char.Lexer , Parser , manyLines + , word + , untilEol ) where import Data.Void +import Data.Char import qualified Data.Text as T import Text.Megaparsec @@ -18,4 +21,10 @@ import Text.Megaparsec.Char.Lexer (binary, decimal, float, type Parser = Parsec Void T.Text manyLines :: Parser a -> Parser [a] -manyLines p = sepBy p newline <* optional newline <* eof +manyLines p = sepEndBy (try p) newline + +word :: Parser T.Text +word = takeWhileP Nothing (not . isSeparator) + +untilEol :: Parser T.Text +untilEol = takeWhileP Nothing (/= '\n') diff --git a/hs/src/Aoc/Y2020.hs b/hs/src/Aoc/Y2020.hs index c1513e4..b4eb5b6 100644 --- a/hs/src/Aoc/Y2020.hs +++ b/hs/src/Aoc/Y2020.hs @@ -4,8 +4,10 @@ module Aoc.Y2020 import Aoc.Day import qualified Aoc.Y2020.D01 as D01 +import qualified Aoc.Y2020.D02 as D02 days :: [Day] days = [ D01.day + , D02.day ] diff --git a/hs/src/Aoc/Y2020/D02.hs b/hs/src/Aoc/Y2020/D02.hs new file mode 100644 index 0000000..1d92ad4 --- /dev/null +++ b/hs/src/Aoc/Y2020/D02.hs @@ -0,0 +1,44 @@ +module Aoc.Y2020.D02 + ( day + ) where + +import qualified Data.Text as T + +import Aoc.Day +import Aoc.Parse + +data Line = Line + { lMin :: Int + , lMax :: Int + , lChar :: Char + , lPw :: T.Text + } + +parser :: Parser [Line] +parser = manyLines $ Line + <$> (decimal <* char '-') + <*> (decimal <* space) + <*> (anySingle <* char ':' <* space) + <*> untilEol + +validCount :: Line -> Bool +validCount l = n >= lMin l && n <= lMax l + where + n = T.count (T.singleton $ lChar l) $ lPw l + +validPositions :: Line -> Bool +validPositions l = (left == lChar l) /= (right == lChar l) + where + left = T.index (lPw l) (lMin l - 1) + right = T.index (lPw l) (lMax l - 1) + +solver :: [Line] -> IO () +solver ls = do + putStrLn ">> Part 1" + print $ length $ filter validCount ls + + putStrLn ">> Part 2" + print $ length $ filter validPositions ls + +day :: Day +day = dayParse "2020_02" parser solver