-
Notifications
You must be signed in to change notification settings - Fork 0
/
run.hs
93 lines (77 loc) · 2.53 KB
/
run.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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
{-# LANGUAGE TypeApplications #-}
import Data.Char (isDigit)
import Data.Bits (xor)
import Data.Ord (comparing)
import Data.Maybe
import Data.List
import Data.Sequence (Seq)
import qualified Data.Sequence as Seq
import Data.Set (Set)
import qualified Data.Set as Set
-- byr (Birth Year)
-- iyr (Issue Year)
-- eyr (Expiration Year)
-- hgt (Height)
-- hcl (Hair Color)
-- ecl (Eye Color)
-- pid (Passport ID)
-- cid (Country ID)
fields =
[ "byr"
, "iyr"
, "eyr"
, "hgt"
, "hcl"
, "ecl"
, "pid"
, "cid" ]
required = init fields
parseLineFields :: String -> [(String, String)]
parseLineFields =
map parseLineField
. words
parseLineField f =
case span (/= ':') f of
(fname, ':':value) -> (fname, value)
parse :: [String] -> [[(String, String)]]
parse = go [] Nothing
where go acc (Just c) [] = reverse $ c:acc
go acc curr (f:rest) =
case (curr, parseLineFields f) of
(Just c, []) -> go (c:acc) Nothing rest
(Nothing, []) -> go acc Nothing rest
(Just c, fs) -> go acc (Just (c ++ fs)) rest
(Nothing, fs) -> go acc (Just fs) rest
parseAll =
parse . lines
hasAllRequired pp = all (`elem` (map fst pp)) required
between v l h = l <= v && v <= h
validate "byr" v = between (read @Int v) 1920 2002
validate "iyr" v = between (read @Int v) 2010 2020
validate "eyr" v = between (read @Int v) 2020 2030
validate "hgt" v =
case reads @Int v of
[(v', "cm")] -> between v' 150 193
[(v', "in")] -> between v' 59 76
_ -> False
validate "hcl" ('#':v) = all (`elem` "0123456789abcdef") v
validate "ecl" v = v `elem` ["amb", "blu", "brn", "gry", "grn", "hzl", "oth"]
validate "pid" v = length v == 9 && all isDigit v
validate "cid" _ = True
validate _ _ = 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.
valid pp = hasAllRequired pp && all (uncurry validate) pp
part1 = length . filter hasAllRequired
part2 = length . filter valid
main = do
input <- parseAll <$> readFile "input.txt"
print (part1 input)
print (part2 input)