You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

105 lines
2.5KB

  1. -- a haiku:
  2. -- this is some bad code
  3. -- but what more can you expect
  4. -- from a bad problem?
  5. import Data.Char (isDigit, isHexDigit)
  6. import Data.List (sort, nub)
  7. main :: IO ()
  8. main = do
  9. raw <- readFile "day4.txt"
  10. let ls = map (concat . (map words)) $ split "" $ lines raw
  11. ansA = length $ filter (== True) $ map solveA ls
  12. ansB = length $ filter (== True) $ map solveB ls
  13. in do
  14. putStrLn $ "day4a: " ++ (show ansA)
  15. putStrLn $ "day4b: " ++ (show ansB)
  16. rtags :: [String]
  17. rtags = ["byr", "iyr", "eyr", "hgt", "hcl", "ecl", "pid"]
  18. extractTag :: String -> String
  19. extractTag [] = error "empty tag"
  20. extractTag s = takeWhile (/= ':') s
  21. extractValue :: String -> String
  22. extractValue [] = error "empty value"
  23. extractValue s = drop 1 $ dropWhile (/= ':') s
  24. applyAll :: [a] -> [(a -> b)] -> [b]
  25. applyAll [] [] = []
  26. applyAll (a:as) (f:fs) =
  27. if length as /= length fs
  28. then error "applyAll: lists must be same length"
  29. else (f a) : (applyAll as fs)
  30. solveA :: [String] -> Bool
  31. solveA [] = False
  32. solveA s = foldr (&&) True $ map (`elem` tags) rtags
  33. where
  34. tags = map extractTag s
  35. solveB :: [String] -> Bool
  36. solveB [] = False
  37. solveB s = solveA s &&
  38. (foldr (&&) True $ applyAll ls
  39. [ byrValid
  40. , eclValid
  41. , eyrValid
  42. , hclValid
  43. , hgtValid
  44. , iyrValid
  45. , pidValid
  46. ])
  47. where
  48. ls = (sort . nub) $ filter (\x -> elem (extractTag x) rtags) s
  49. yearValid :: Int -> Int -> String -> Bool
  50. yearValid l u s' = (length s) == 4
  51. && (read s) >= l
  52. && (read s) <= u
  53. where
  54. s = drop 1 $ dropWhile (/= ':') s'
  55. byrValid :: String -> Bool
  56. byrValid = yearValid 1920 2002
  57. iyrValid :: String -> Bool
  58. iyrValid = yearValid 2010 2020
  59. eyrValid :: String -> Bool
  60. eyrValid = yearValid 2020 2030
  61. eclValid :: String -> Bool
  62. eclValid s' = s `elem` ["amb","blu","brn","gry","grn","hzl","oth"]
  63. where
  64. s = drop 1 $ dropWhile (/= ':') s'
  65. pidValid :: String -> Bool
  66. pidValid s' = (length s) == 9 && all isDigit s
  67. where
  68. s = drop 1 $ dropWhile (/= ':') s'
  69. hclValid :: String -> Bool
  70. hclValid s' = h == '#' && all isHexDigit s
  71. where
  72. (h:s) = drop 1 $ dropWhile (/= ':') s'
  73. hgtValid :: String -> Bool
  74. hgtValid s' =
  75. case unit of
  76. "cm" -> val >= 150 && val <= 193
  77. "in" -> val >= 59 && val <= 76
  78. _ -> False
  79. where
  80. s = drop 1 $ dropWhile (/= ':') s'
  81. (val,unit) = head $ (reads s :: [(Int,String)])
  82. split :: Eq a => a -> [a] -> [[a]]
  83. split _ [] = []
  84. split d as = chunk : (split d rest)
  85. where
  86. chunk = takeWhile (/= d) as
  87. rest = drop 1 $ dropWhile (/= d) as