{-# LANGUAGE OverloadedStrings #-} -- for building Text strings module Main where import Control.Applicative (Alternative((<|>))) import Data.Text.Lazy (Text) import Data.Void (Void) import Prelude import qualified Control.Applicative.Permutations as P import qualified Data.List as List import qualified Data.Text.Lazy.Encoding as Text import qualified Text.Megaparsec as P import qualified Text.Megaparsec.Char as P -- import qualified Text.Megaparsec.Debug as P import qualified Data.ByteString.Lazy as BSL import Paths_AoC2020 -- | See https://adventofcode.com/2020/day/6 for the problem statements data Day06Results = Day06Results { example1 :: Int , batch1 :: Int , example2 :: Int , batch2 :: Int } deriving (Show) main :: IO () main = do putStr "Day06Inputs: " >> getDataFileName "" >>= putStrLn print =<< Day06Results <$> (unionGroups <$> parse "example") <*> (unionGroups <$> parse "batch") <*> (intersectGroups <$> parse "example") <*> (intersectGroups <$> parse "batch") type Parser output = P.Parsec {-error-}Void {-input-}Text output type Answer = [Char] parserAnswer :: Parser Answer parserAnswer = -- P.dbg "parserAnswer" $ (P.notFollowedBy (P.char '\n') *>) $ P.runPermutation $ List.foldl' (\acc a -> maybe id (:) <$> a <*> acc) (pure []) [ P.toPermutationWithDefault Nothing (Just <$> P.char c) | c <- ['a'..'z'] ] parserGroup :: Parser [Answer] parserGroup = -- P.dbg "parserGroup" $ P.some $ parserAnswer <* P.char '\n' parserGroups :: Parser [[Answer]] parserGroups = -- P.dbg "parserGroups" $ P.many $ parserGroup <* (() <$ P.char '\n' <|> P.eof) unionGroups :: [[Answer]] -> Int unionGroups = sum . ((length . List.foldr List.union []) <$>) intersectGroups :: [[Answer]] -> Int intersectGroups = sum . ((length . List.foldr1 List.intersect) <$>) parse :: FilePath -> IO [[Answer]] parse input = do content <- Text.decodeUtf8 <$> (BSL.readFile =<< getDataFileName input) case P.parse (parserGroups <* P.eof) input content of Left err -> error (P.errorBundlePretty err) Right groups -> return groups