-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathday4.hs
77 lines (59 loc) · 2.52 KB
/
day4.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
65
66
67
68
69
70
71
72
73
74
75
76
77
import Data.List
import Data.List.Split
import Data.Map (Map, fromList, member, (!), toList)
import Data.Maybe
import Text.Regex (matchRegex, mkRegexWithOpts)
type ParsedData = (String, String)
parseInput :: String -> [[ParsedData]]
parseInput = map (extractPairs . words . mergeLines) . groupByDocs . lines
where
groupByDocs = groupBy (\x y -> y /= "")
mergeLines = (>>= (' ':))
list2Pair [x, y] = (x, y)
extractPairs = map (list2Pair . splitOn ":")
allNecessaryFields :: [String]
allNecessaryFields = ["byr", "iyr", "eyr", "hgt", "hcl", "ecl", "pid", "hgt"]
necessaryFieldPassports :: [[ParsedData]] -> [Map String String]
necessaryFieldPassports = filter isValid . map fromList
where
isValid fieldsMap = all (`member` fieldsMap) allNecessaryFields
firstTask :: [[ParsedData]] -> Int
firstTask = length . necessaryFieldPassports
matches :: String -> String -> Bool
matches pattern elem = isJust $ matchRegex (mkRegexWithOpts pattern True False) elem
isGoodNumber :: String -> Int -> (Int, Int) -> Bool
isGoodNumber str n (low, up) = length str == n && number >= low && number < up
where
number = read str
byr :: String -> Bool
byr str = isGoodNumber str 4 (1920, 2003)
iyr :: String -> Bool
iyr str = isGoodNumber str 4 (2010, 2021)
eyr :: String -> Bool
eyr str = isGoodNumber str 4 (2020, 2031)
hcl :: String -> Bool
hcl str = matches "^#[0-9a-f]{6}$" str
hgt :: String -> Bool
hgt str
| matches "^[0-9]{3}cm$" str = isGoodNumber (take 3 str) 3 (150, 194)
| matches "^[0-9]{2}in$" str = isGoodNumber (take 2 str) 2 (59, 77)
| otherwise = False
ecl :: String -> Bool
ecl str = str `elem` ["amb", "blu", "brn" ,"gry", "grn", "hzl", "oth"]
pid :: String -> Bool
pid str = matches "^[0-9]{9}$" str
cid :: String -> Bool
cid _ = True
funcMap :: Map String (String -> Bool)
funcMap = fromList [("byr", byr), ("iyr", iyr), ("eyr", eyr), ("hcl", hcl), ("hgt", hgt), ("ecl", ecl), ("pid", pid), ("cid", cid)]
secondTask :: [[ParsedData]] -> Int
secondTask = length . filter isValid . necessaryFieldPassports
where
applyFunc (x, y) = (funcMap ! x) y
isValid fieldsMap = all (==True) $ (map (applyFunc) . toList) fieldsMap
main :: IO ()
main = do
input <- readFile "input.txt"
let parsedInput = parseInput input
print $ firstTask parsedInput
print $ secondTask parsedInput