2020-12-04 01:14:56 -06:00
|
|
|
import streams, strutils, sets, sequtils, sugar, re, tables
|
|
|
|
|
2020-12-04 11:02:05 -06:00
|
|
|
let regexes = toTable({
|
|
|
|
"hcl": re"^#[0-9a-f]{6}$",
|
|
|
|
"ecl": re"^(amb|blu|brn|gry|grn|hzl|oth)$",
|
|
|
|
"pid": re"^\d{9}$",
|
|
|
|
"hgt": re"^\d+(cm|in)$",
|
|
|
|
"nondec": re"[^0-9]",
|
|
|
|
})
|
|
|
|
|
2020-12-04 10:21:14 -06:00
|
|
|
let validators = toTable({
|
2020-12-04 11:02:05 -06:00
|
|
|
"hcl": (v: string) => v.match regexes["hcl"],
|
|
|
|
"ecl": (v: string) => v.match regexes["ecl"],
|
|
|
|
"pid": (v: string) => v.match regexes["pid"],
|
2020-12-04 10:21:14 -06:00
|
|
|
"byr": (v: string) => parseInt(v) in 1920..2002,
|
|
|
|
"iyr": (v: string) => parseInt(v) in 2010..2020,
|
|
|
|
"eyr": (v: string) => parseInt(v) in 2020..2030,
|
|
|
|
"hgt": proc (v: string): bool =
|
|
|
|
let (mn, mx) = if v.endsWith("cm"): (150, 193) else: (59, 76)
|
2020-12-04 11:02:05 -06:00
|
|
|
v.match(regexes["hgt"]) and v.replace(regexes["nondec"]).parseInt in mn..mx,
|
2020-12-04 01:14:56 -06:00
|
|
|
"cid": (v: string) => true,
|
2020-12-04 10:21:14 -06:00
|
|
|
})
|
2020-12-04 01:14:56 -06:00
|
|
|
|
2020-12-04 10:21:14 -06:00
|
|
|
proc parsePassports(s: Stream): seq[Table[string, string]] =
|
|
|
|
s.readAll().split("\n\n").mapIt(it.replace("\n", " ").split(' ')
|
|
|
|
.filterIt(it != "").mapIt(it.split(':', 2)).mapIt((it[0], it[1])).toTable)
|
2020-12-04 01:14:56 -06:00
|
|
|
|
|
|
|
proc hasRequiredFields(p: Table[string, string]): bool =
|
2020-12-04 10:31:44 -06:00
|
|
|
(toSeq(validators.keys).toHashSet - ["cid"].toHashSet) <= toSeq(p.keys).toHashSet
|
2020-12-03 22:49:54 -06:00
|
|
|
|
|
|
|
proc part1*(s: Stream): int =
|
2020-12-04 10:30:31 -06:00
|
|
|
s.parsePassports.countIt(it.hasRequiredFields)
|
2020-12-03 22:49:54 -06:00
|
|
|
|
|
|
|
proc part2*(s: Stream): int =
|
2020-12-04 10:30:31 -06:00
|
|
|
s.parsePassports.countIt(it.hasRequiredFields and toSeq(it.pairs).allIt(validators[it[0]](it[1])))
|