bss03

Advent of Code 2020 Day 4

Dec 4th, 2020
563
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. import Data.Char (isDigit)
  2. import Data.List (intercalate)
  3.  
  4. import Data.Set (Set)
  5. import qualified Data.Set as S
  6. import Data.Map (Map)
  7. import qualified Data.Map as M
  8.  
  9. key :: String -> String
  10. key = fst . kv
  11.  
  12. kv :: String -> (String, String)
  13. kv s = (key, drop 1 value)
  14.  where (key, value) = break (':' ==) s
  15.  
  16. paras :: [String] -> [String]
  17. paras ls = if null pls then [] else intercalate " " pls : paras (drop 1 remain)
  18.  where
  19.   (pls, remain) = break (null . words) ls
  20.  
  21. reqKeys :: Set String
  22. reqKeys = S.fromList [ "byr", "iyr", "eyr", "hgt", "hcl", "ecl", "pid" ]
  23.  
  24. validations :: Map String (String -> Bool)
  25. validations = M.fromList
  26.   [ ("byr", validByr)
  27.   , ("iyr", validIyr)
  28.   , ("eyr", validEyr)
  29.   , ("hgt", validHgt)
  30.   , ("hcl", validHcl)
  31.   , ("ecl", validEcl)
  32.   , ("pid", validPid)
  33.   ]
  34.  
  35. keys :: String -> Set String
  36. keys = S.fromList . map key . words
  37.  
  38. kvs :: String -> Map String String
  39. kvs = M.fromList . map kv . words
  40.  
  41. hasReqKeys :: Set String -> Bool
  42. hasReqKeys x = S.size reqKeys == S.size (S.intersection reqKeys x)
  43.  
  44. validates :: Map String String -> Bool
  45. validates x = M.size results == M.size validations && and results
  46.  where results = M.intersectionWith ($) validations x
  47.  
  48. count :: (a -> Bool) -> [a] -> Int
  49. count pred = length . filter pred
  50.  
  51. validByr :: String -> Bool
  52. validByr byr = 1920 <= v && v <= 2002
  53.  where v = read byr
  54.  
  55. validIyr :: String -> Bool
  56. validIyr iyr = 2010 <= v && v <= 2020
  57.  where v = read iyr
  58.  
  59. validEyr :: String -> Bool
  60. validEyr eyr = 2020 <= v && v <= 2030
  61.  where v = read eyr
  62.  
  63. validHgt :: String -> Bool
  64. validHgt hgt =
  65.   case units of
  66.    "cm" -> 150 <= v && v <= 193
  67.    "in" -> 59 <= v && v <= 76
  68.    _ -> False
  69.  where
  70.   (n, units) = span isDigit hgt
  71.   v = read n
  72.  
  73. lcHexDigits :: Set Char
  74. lcHexDigits = S.fromList "0123456789abcdef"
  75.  
  76. validHcl :: String -> Bool
  77. validHcl ('#':hex@(_:_:_:_:_:_:[])) = all (flip S.member lcHexDigits) hex
  78. validHcl _ = False
  79.  
  80. eyeColors :: Set String
  81. eyeColors = S.fromList [ "amb", "blu", "brn", "gry", "grn", "hzl", "oth" ]
  82.  
  83. validEcl :: String -> Bool
  84. validEcl = flip S.member eyeColors
  85.  
  86. validPid :: String -> Bool
  87. validPid pid = length pid == 9 && all isDigit pid
  88.  
  89. main = interact ((++"\n") . show . count (validates . kvs). paras . lines)
  90.  
RAW Paste Data