Skip to content

Instantly share code, notes, and snippets.

@mattmess1221
Created December 4, 2020 18:08
Show Gist options
  • Save mattmess1221/1971b038b0e2f1767f220becb6bc268e to your computer and use it in GitHub Desktop.
Save mattmess1221/1971b038b0e2f1767f220becb6bc268e to your computer and use it in GitHub Desktop.
import { Puzzle } from './index';
type Predicate<T> = (value: T) => boolean;
interface Passport {
byr: string
iyr: string
eyr: string
hgt: string
hcl: string
ecl: string
pid: string
cid?: string
}
const fields = [
'byr',
'iyr',
'eyr',
'hgt',
'hcl',
'ecl',
'pid'
];
const eyeColors = ['amb', 'blu', 'brn', 'gry', 'grn', 'hzl', 'oth'];
const checks: Readonly<Record<keyof Passport, Predicate<string>>> = {
byr: checkYear(1920, 2002),
iyr: checkYear(2010, 2020),
eyr: checkYear(2020, 2030),
hgt: checkHeight,
hcl: (value) => /^#[0-9a-f]{6}$/.test(value),
ecl: (value) => eyeColors.includes(value),
pid: (value) => /^\d{9}$/.test(value),
cid: () => true
};
function passportContainsAllRequiredFields (pass: Partial<Passport>) {
const keys = new Set(Object.keys(pass));
return !fields.map((key) => keys.has(key)).includes(false);
}
function passportRequiredFieldsAreValid (pass: Passport): boolean {
try {
for (const [key, val] of Object.entries(checks)) {
check(pass[key as keyof Passport]!, val);
}
return true;
} catch (e) {
return false;
}
}
function check (value: string, func: (value: string) => boolean) {
if (func(value)) {
return;
}
throw new Error();
}
function checkHeight (value: string) {
const match = /^(?<height>\d+)(?<unit>cm|in)$/.exec(value);
if (match) {
const { height, unit } = match.groups!;
const hgt = parseInt(height);
switch (unit) {
case 'in':
return hgt >= 59 && hgt <= 76;
case 'cm':
return hgt >= 150 && hgt <= 193;
}
}
return false;
}
function checkYear (minYear: number, maxYear: number) {
return (value: string) => {
if (/^\d{4}$/.test(value)) {
const year = parseInt(value);
if (year >= minYear && year <= maxYear) {
return true;
}
}
return false;
};
}
export class Day4 implements Puzzle {
private readonly data: Partial<Readonly<Passport>>[]
constructor (buffer: Buffer) {
this.data = buffer.toString('utf-8')
.split(/(\r?\n){2}/)
.map((section) => section.replace(/\s+/g, ' ').trim())
.filter((a) => a)
.map((section) => {
const pass = {} as Passport;
section.split(/\s/).forEach((part) => {
const [key, val] = part.split(':');
pass[key as keyof Passport] = val;
});
return pass;
});
}
solvePart1 (): void {
console.log(this.data
.filter(passportContainsAllRequiredFields)
.length);
}
solvePart2 (): void {
console.log(this.data
.filter(passportContainsAllRequiredFields)
.filter((pass) => passportRequiredFieldsAreValid(pass as Passport))
.length);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment