-
Notifications
You must be signed in to change notification settings - Fork 0
/
04.hs
64 lines (53 loc) · 2.19 KB
/
04.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
import Data.Char (isNumber)
import Data.List (find, isInfixOf)
import Data.List.Split (splitOn)
import Data.Maybe (isJust)
keywords :: [[Char]]
keywords = ["ecl", "pid", "eyr", "hcl", "byr", "iyr", "hgt"]
eclList :: [[Char]]
eclList = ["amb", "blu", "brn", "gry", "grn", "hzl", "oth"]
testPassport :: [Char] -> Bool
testPassport pass = all (`isInfixOf` pass) keywords
testHeight :: ([Char], [Char]) -> Bool
testHeight (val, unit) = case unit of
"cm" -> let x = read val in x >= 150 && x <= 193
"in" -> let x = read val in x >= 59 && x <= 76
_ -> False
testHairColor :: [Char] -> Bool
testHairColor val = case val of
(x : xs) -> x == '#' && length xs == 6 && all (`elem` ['0' .. '9'] ++ ['a' .. 'f']) xs
_ -> False
--byr (Birth Year) - four digits; at least 1920 and at most 2002.
--iyr (Issue Year) - four digits; at least 2010 and at most 2020.
--eyr (Expiration Year) - four digits; at least 2020 and at most 2030.
--hgt (Height) - a number followed by either cm or in:
--If cm, the number must be at least 150 and at most 193.
--If in, the number must be at least 59 and at most 76.
--hcl (Hair Color) - a # followed by exactly six characters 0-9 or a-f.
--ecl (Eye Color) - exactly one of: amb blu brn gry grn hzl oth.
--pid (Passport ID) - a nine-digit number, including leading zeroes.
--cid (Country ID) - ignored, missing or not.
testEntry :: [[Char]] -> Bool
testEntry [key, val] = case key of
"byr" -> let x = read val in x >= 1920 && x <= 2002
"iyr" -> let x = read val in x >= 2010 && x <= 2020
"eyr" -> let x = read val in x >= 2020 && x <= 2030
"hgt" -> testHeight $ span isNumber val
"hcl" -> testHairColor val
"ecl" -> isJust . find (== val) $ eclList
"pid" -> length val == 9 && all isNumber val
"cid" -> True
_ -> False
checkPassport :: [Char] -> Bool
checkPassport p =
let vals = map (splitOn ":") $ words p
in all testEntry vals
part2 :: [String] -> Int
part2 passports = length . filter (== True) $ map checkPassport passports
main = do
input <- getContents
let passports = map (unwords . lines) $ splitOn "\n\n" input
let isvalid = map testPassport passports
let part1 = [x | (x, valid) <- zip passports isvalid, valid]
print $ length part1
print $ part2 part1