aboutsummaryrefslogtreecommitdiff
path: root/2020/04-Passport_Processing/second.hs
diff options
context:
space:
mode:
authorJulien Dessaux2023-03-11 21:01:24 +0100
committerJulien Dessaux2023-03-11 21:01:24 +0100
commit8e97f2dfdc35d5249b8be681580b6243aebb80c3 (patch)
tree990d67096674f438071c394895c71fde33be484e /2020/04-Passport_Processing/second.hs
parent2020-03 in haskell (diff)
downloadadvent-of-code-8e97f2dfdc35d5249b8be681580b6243aebb80c3.tar.gz
advent-of-code-8e97f2dfdc35d5249b8be681580b6243aebb80c3.tar.bz2
advent-of-code-8e97f2dfdc35d5249b8be681580b6243aebb80c3.zip
2020-04 in haskell
Diffstat (limited to '')
-rw-r--r--2020/04-Passport_Processing/second.hs153
1 files changed, 153 insertions, 0 deletions
diff --git a/2020/04-Passport_Processing/second.hs b/2020/04-Passport_Processing/second.hs
new file mode 100644
index 0000000..e258302
--- /dev/null
+++ b/2020/04-Passport_Processing/second.hs
@@ -0,0 +1,153 @@
+-- requires cabal install --lib megaparsec parser-combinators
+module Main (main) where
+
+import Control.Applicative.Permutations
+import Control.Monad (void, when)
+import Data.Maybe (catMaybes)
+import Data.Void (Void)
+import Text.Megaparsec
+import Text.Megaparsec.Char
+-- import Text.Megaparsec.Debug
+import System.Exit (die)
+
+exampleExpectedOutput = 2
+
+data Passport = Passport { byr :: Int
+ , iyr :: Int
+ , eyr :: Int
+ , hgt :: Int
+ , hcl :: String
+ , ecl :: String
+ , pid :: Int
+ } deriving (Show)
+
+type Parser = Parsec Void String
+
+parseKey :: String -> Parser ()
+parseKey key = do
+ void (string key)
+ void (char ':')
+
+parseColor :: String -> Parser (Maybe String)
+parseColor key = do
+ value <- try (do
+ parseKey key
+ void $ char '#'
+ v <- some hexDigitChar
+ spaceBetween
+ return $ Just v
+ ) <|> skipString key
+ case value of
+ Just v -> if length v == 6 then return value else return Nothing
+ _ -> return Nothing
+
+parseEyeColor :: String -> Parser (Maybe String)
+parseEyeColor key = do
+ parseKey key
+ value <- (Just <$> ( string "amb"
+ <|> string "blu"
+ <|> string "brn"
+ <|> string "gry"
+ <|> string "grn"
+ <|> string "hzl"
+ <|> string "oth"
+ )) <|> ((some $ alphaNumChar <|> char '#') *> return Nothing)
+ spaceBetween
+ return value
+
+parseHeight :: String -> Parser (Maybe Int)
+parseHeight key = do
+ vu <- try (do
+ parseKey key
+ v <- some digitChar
+ u <- string "cm" <|> string "in"
+ spaceBetween
+ return $ Just (v, u)
+ ) <|> skipString key *> return Nothing
+ case vu of
+ Just (value, unit) -> let v = read value
+ in case unit of
+ "cm" -> if v >= 150 && v <= 193 then return (Just v) else return Nothing
+ "in" -> if v >= 59 && v <= 76 then return (Just v) else return Nothing
+ _ -> return Nothing
+ _ -> return Nothing
+
+parseInt :: String -> Int -> Int -> Parser (Maybe Int)
+parseInt key low high = do
+ parseKey key
+ value <- some digitChar
+ spaceBetween
+ let vv = read value
+ if vv >= low && vv <= high then return $ Just vv else return Nothing
+
+parsePid :: String -> Parser (Maybe Int)
+parsePid key = do
+ value <- try (do
+ parseKey key
+ v <- some digitChar
+ spaceBetween
+ return $ Just v
+ ) <|> skipString key *> return Nothing
+ case value of
+ Just v -> if length v == 9 then return (Just $ read v) else return Nothing
+ _ -> return Nothing
+
+skipInt :: String -> Parser (Maybe Int)
+skipInt key = do
+ parseKey key
+ void (some $ alphaNumChar <|> char '#')
+ spaceBetween
+ return Nothing
+
+skipString :: String -> Parser (Maybe String)
+skipString key = do
+ parseKey key
+ void (some $ alphaNumChar <|> char '#')
+ spaceBetween
+ return Nothing
+
+spaceBetween :: Parser ()
+spaceBetween = void $ char ' ' <|> char '\n'
+
+parsePassport :: Parser (Maybe Passport)
+parsePassport = do
+ -- (byr, iyr, eyr, hgt, hcl, ecl, pid, _) <- dbg "passport" . runPermutation $
+ (byr, iyr, eyr, hgt, hcl, ecl, pid, _) <- runPermutation $
+ (,,,,,,,) <$> toPermutationWithDefault Nothing (parseInt "byr" 1920 2002)
+ <*> toPermutationWithDefault Nothing (parseInt "iyr" 2010 2020)
+ <*> toPermutationWithDefault Nothing (parseInt "eyr" 2020 2030)
+ <*> toPermutationWithDefault Nothing (parseHeight "hgt")
+ <*> toPermutationWithDefault Nothing (parseColor "hcl")
+ <*> toPermutationWithDefault Nothing (parseEyeColor "ecl")
+ <*> toPermutationWithDefault Nothing (parsePid "pid")
+ <*> toPermutationWithDefault Nothing (skipString "cid")
+ void (char '\n')
+ return $ makePassport byr iyr eyr hgt hcl ecl pid
+
+makePassport :: Maybe Int -> Maybe Int -> Maybe Int -> Maybe Int -> Maybe String -> Maybe String -> Maybe Int -> Maybe Passport
+makePassport (Just byr) ( Just iyr) (Just eyr) (Just hgt) (Just hcl) (Just ecl) (Just pid) = Just $ Passport { byr=byr, iyr=iyr, eyr=eyr, hgt=hgt, hcl=hcl, ecl=ecl, pid=pid }
+makePassport _ _ _ _ _ _ _ = Nothing
+
+parsePassports :: Parser [Passport]
+parsePassports = do
+ passports <- some parsePassport
+ eof
+ return $ catMaybes passports
+
+parseInput :: String -> IO [Passport]
+parseInput filename = do
+ input <- readFile filename
+ case runParser parsePassports filename input of
+ Left bundle -> die $ errorBundlePretty bundle
+ Right passports -> return passports
+
+compute :: [Passport]-> Int
+compute passports = length passports
+
+main :: IO ()
+main = do
+ example <- parseInput "example"
+ let exampleOutput = compute example
+ when (exampleOutput /= exampleExpectedOutput) (die $ "example failed: got " ++ show exampleOutput ++ " instead of " ++ show exampleExpectedOutput)
+ input <- parseInput "input"
+ print $ compute input