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
94
95
96
97
98
99
100
101
102
103
104
|
import { Observable, of } from "rxjs";
import { concatAll, count, filter, groupBy, map, mergeMap, reduce, tap } from 'rxjs/operators';
import { ExerciseModuleFunc } from "../types";
interface Passport {
byr: string;
iyr: string;
eyr: string;
hgt: string;
hcl: string;
ecl: string;
pid: string;
cid?: string;
}
const parsePassports = (input: string): Passport[] => {
const sections = input.split("\n\n")
const splitted = sections.map(s => s.split(/[\n\r\s]+/g));
const result = splitted.map(s => s.reduce((acc, val) => {
const [lhs, rhs] = val.split(":");
acc[lhs] = rhs;
return acc;
}, {})) as Passport[];
return result;
}
const requiredFieldsPresent = (passport: Passport): boolean => {
const requiredKeys = ["byr", "iyr", "eyr", "hgt", "hcl", "ecl", "pid"];
let valid = true;
requiredKeys.forEach(key => {
if (passport[key] === undefined) {
valid = false;
}
});
return valid;
}
const byrValid = (byr: string): boolean => {
const match = byr.match(/\d{4}/);
if (!match) return false;
const val = Number(match[0]);
return val >= 1920 && val <= 2002;
}
const iyrValid = (iyr: string): boolean => {
const match = iyr.match(/\d{4}/);
if (!match) return false;
const val = Number(match[0]);
return val >= 2010 && val <= 2020;
}
const eyrValid = (eyr: string): boolean => {
const match = eyr.match(/\d{4}/);
if (!match) return false;
const val = Number(match[0]);
return val >= 2020 && val <= 2030;
}
const hgtValid = (hgt: string): boolean => {
const match = hgt.match(/(\d{2,3})(cm|in)/);
if (!match) return false;
const val = Number(match[1]);
const unit = match[2];
return (unit === "cm" && val >= 150 && val <= 193) || (unit === "in" && val >= 59 && val <= 76);
}
const hclValid = (hcl: string): boolean => !!hcl.match(/\#[0-9a-f]{6}/);
const eclValid = (ecl: string): boolean => ["amb", "blu", "brn", "gry", "grn", "hzl", "oth"].includes(ecl);
const pidValid = (pid: string): boolean => !!pid.match(/\d{9}/);
const isPassportValid = (passport: Passport): boolean =>
requiredFieldsPresent(passport)
&& byrValid(passport.byr)
&& iyrValid(passport.iyr)
&& eyrValid(passport.eyr)
&& hgtValid(passport.hgt)
&& hclValid(passport.hcl)
&& eclValid(passport.ecl)
&& pidValid(passport.pid)
const day4: ExerciseModuleFunc = async (input: string) => {
const prom1 = of(input).pipe(
map(parsePassports),
concatAll(),
filter(requiredFieldsPresent),
count()
).toPromise();
const prom2 = of(input).pipe(
map(parsePassports),
concatAll(),
filter(isPassportValid),
count()
).toPromise();
return Promise.all([prom1, prom2]);
}
export default day4;
|