Advertisement
Guest User

Untitled

a guest
Dec 4th, 2020
134
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. {-# LANGUAGE OverloadedStrings #-}
  2.  
  3. import Data.Text.IO (readFile)
  4. import qualified Data.Text.IO as TIO
  5. import Data.Text (Text)
  6. import qualified Data.Text as T
  7. import Data.Attoparsec.Text
  8. import Control.Applicative
  9.  
  10. import Data.Map (Map, (!))
  11. import qualified Data.Map as M
  12.  
  13. import Data.Char (isSpace, isDigit)
  14.  
  15. type Passport = Map Text Text
  16.  
  17. parseKVP :: Parser (Text, Text)
  18. parseKVP = do
  19.     k <- T.pack <$> many1 letter
  20.     char ':'
  21.     v <- takeWhile1 (not . isSpace)
  22.     return (k, v)
  23.  
  24. parsePassport :: Parser Passport
  25. parsePassport = M.fromList <$> parseKVP `sepBy1` space
  26.  
  27. validatePassport :: Passport -> Bool
  28. validatePassport p = all (`M.member` p) requiredFields
  29.     where
  30.         requiredFields = ["byr", "iyr", "eyr", "hgt", "hcl", "ecl", "pid"] -- no "cid"
  31.  
  32. validatePassport2 :: Passport -> Bool
  33. validatePassport2 = M.foldrWithKey (\k v b -> (fieldValidators!k) v && b) True
  34.     where
  35.         tRead = read . T.unpack
  36.         fieldValidators = M.fromList
  37.             [ ("byr", byr)
  38.             , ("iyr", iyr)
  39.             , ("eyr", eyr)
  40.             , ("hgt", hgt)
  41.             , ("hcl", hcl)
  42.             , ("ecl", ecl)
  43.             , ("pid", pid)
  44.             , ("cid", const True)
  45.             ]
  46.         byr v = T.length v == 4 && T.all isDigit v && 1920 <= tRead v && tRead v <= 2002
  47.         iyr v = T.length v == 4 && T.all isDigit v && 2010 <= tRead v && tRead v <= 2020
  48.         eyr v = T.length v == 4 && T.all isDigit v && 2020 <= tRead v && tRead v <= 2030
  49.         hgt v = case unit of
  50.             "cm" -> 150 <= n && n <= 193
  51.             "in" -> 59 <= n && n <= 76
  52.             _ -> False
  53.             where
  54.                 n =  tRead $ T.dropEnd 2 v
  55.                 unit = T.takeEnd 2 v
  56.         hcl v = T.head v == '#' && T.length color == 6 && T.all (\c -> ('0'<=c && c<='9') || ('a'<=c && c<='f')) color
  57.             where color = T.drop 1 v
  58.         ecl v = (v == "amb") || (v == "blu") || (v == "blu") || (v == "gry") || (v == "grn") || (v == "hzl") || (v == "oth")
  59.         pid v = T.length v == 9 && T.all isDigit v
  60.  
  61.  
  62. main :: IO ()
  63. main = do
  64.     input <- TIO.readFile "input.txt"
  65.     let passports = case parseOnly (parsePassport `sepBy1` many1 space) input of
  66.             Left err -> error $ "Parsing error: " ++ err
  67.             Right out -> out
  68.  
  69.     putStrLn "Part 1:"
  70.     print . length . filter validatePassport $ passports
  71.     putStrLn "Part 2:"
  72.     print . length . filter validatePassport2 $ passports -- this is right...
  73.     print . length . filter ((&&) <$> validatePassport <*> validatePassport2) $ passports -- but this is wrong??
  74.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement