December 14, 2020
Advent of Code is an Advent calendar of small programming puzzles for a variety of skill sets and skill levels that can be solved in any programming language you like. People use them as a speed contest, interview prep, company training, university coursework, practice problems, or to challenge each other. — AdventOfCode.com
For this puzzle, we're given a list of passport data and our job is to count the valid passports.
Passports are separated by a blank line and each passport is repersented as a sequence of key:value paris separated by space or newlines. Here's an example input:
Copied!1ecl:gry pid:860033327 eyr:2020 hcl:#fffffd2byr:1937 iyr:2017 cid:147 hgt:183cm34iyr:2013 ecl:amb cid:350 eyr:2023 pid:0280488845hcl:#cfa07d byr:192967hcl:#ae17e1 iyr:20138eyr:20249ecl:brn pid:760753108 byr:193110hgt:179cm1112hcl:#cfa07d eyr:2025 pid:16655964813iyr:2011 ecl:brn hgt:59in
Every field listed below is required except for cid which is optional:
Problem: Count the number of valid passports (Ones that have all the requried fields.)
Solution: We're going to parse our input and turn it into an array of objects. After that, it should be easier to determine which passports are valid.
Copied!1const input = `2ecl:gry pid:860033327 eyr:2020 hcl:#fffffd3byr:1937 iyr:2017 cid:147 hgt:183cm45iyr:2013 ecl:amb cid:350 eyr:2023 pid:0280488846hcl:#cfa07d byr:192978hcl:#ae17e1 iyr:20139eyr:202410ecl:brn pid:760753108 byr:193111hgt:179cm1213hcl:#cfa07d eyr:2025 pid:16655964814iyr:2011 ecl:brn hgt:59in15`;1617function parseInput(input: string) {18 return input19 .trim()20 .split("\n\n")21 .map((str) => {22 const obj: Record<string, string> = {};23 const pairs = str.split(/\s/).map((p) => p.split(":"));24 pairs.forEach((p) => (obj[p[0]] = p[1]));25 return obj;26 });27}2829// true means "required" and false means "optional"30const validKeys = {31 byr: true,32 iyr: true,33 eyr: true,34 hgt: true,35 hcl: true,36 ecl: true,37 pid: true,38 cid: false,39};4041function part1() {42 const passports = parseInput(input);43 let validCount = 0;4445 for (const passport of passports) {46 let validKeyCount = 0;4748 for (const key in passport) {49 const seenKeys = new Set<string>(); // using this set to handle duplicate keys5051 // if an invalid key is found, skip this passport52 // because it can't be invalid. The actual input53 // doesn't have any invalid keys, but we do this54 // to be safe.55 if (!(key in validKeys)) {56 continue;57 }5859 if (validKeys[key] && !seenKeys.has(key)) {60 validKeyCount++;61 seenKeys.add(key);62 }63 }6465 // if the password is valid, "validKeyCount" must66 // be exactly "7".67 if (validKeyCount === 7) validCount++;68 }6970 return validCount;71}
Complexity: The time complexity is linear (O(n) where n is the number of passports.) The second loop is negligible. The space complexity is constant. We are storing a few things but that's negligible compared to the size of the input.
Each field has strict rules about what is considered a valid value:
Copied!1function isValid(key: string, value: string) {2 switch (key) {3 case "byr":4 return /^\d{4}$/.test(value) && +value <= 2002 && +value >= 1920;5 case "iyr":6 return /^\d{4}$/.test(value) && +value <= 2020 && +value >= 2010;7 case "eyr":8 return /^\d{4}$/.test(value) && +value <= 2030 && +value >= 2020;9 case "hgt":10 const match = value.match(/^(\d+)(in|cm)$/);11 if (!match) return false;12 return match[2] === "in"13 ? +match[1] >= 59 && +match[1] <= 7614 : +match[1] >= 150 && +match[1] <= 193;15 case "hcl":16 return /^#[0-9a-f]{6}$/.test(value);17 case "ecl":18 return /^amb|blu|brn|gry|grn|hzl|oth$/.test(value);19 case "pid":20 return /^[0-9]{9}$/.test(value);21 case "cid":22 return true;23 default:24 return false;25 }26}2728function part2() {29 const passports = parseInput(input);30 let validCount = 0;3132 for (const passport of passports) {33 let validKeyCount = 0;34 const seenKeys = new Set<string>();3536 for (const [key, value] of passport.entries()) {37 if (key === "cid" || seenKeys.has(key)) continue;3839 if (isValid(key, value)) {40 validKeyCount++;41 seenKeys.add(key);42 } else {43 break;44 }45 }4647 // if the password is valid, "validKeyCount" must48 // be exactly "7".49 if (validKeyCount === 7) validCount++;50 }5152 return validCount;53}
Complexity: Same as part I; Linear time and constant space.