advent_of_code/year2020/
day04.rs1use crate::input::Input;
2
3fn is_valid(field_idx: usize, value: &str) -> bool {
4 fn in_range(string: &str, start: u32, end: u32) -> bool {
5 (start..=end).contains(&string.parse::<u32>().unwrap_or_default())
6 }
7
8 match field_idx {
9 0 => value.len() == 4 && in_range(value, 1920, 2002),
10 1 => value.len() == 4 && in_range(value, 2010, 2020),
11 2 => value.len() == 4 && in_range(value, 2020, 2030),
12 3 => {
13 (value.ends_with("cm") && in_range(&value[0..(value.len() - 2)], 150, 193))
14 || (value.ends_with("in") && in_range(&value[0..(value.len() - 2)], 59, 76))
15 }
16 4 => {
17 value.starts_with('#')
18 && value.len() == 7
19 && value[1..]
20 .bytes()
21 .all(|c| matches!(c, b'0'..=b'9' | b'a'..=b'f'))
22 }
23 5 => matches!(value, "amb" | "blu" | "brn" | "gry" | "grn" | "hzl" | "oth"),
24 6 => value.len() == 9 && value.parse::<u32>().is_ok(),
25 _ => false,
26 }
27}
28
29pub fn solve(input: &Input) -> Result<u32, String> {
30 const FIELD_NAMES: [&str; 7] = ["byr", "iyr", "eyr", "hgt", "hcl", "ecl", "pid"];
31
32 let mut fields_validity = [false; 7];
33 let mut valid_passports_count = 0;
34
35 for line in input.text.lines().chain(std::iter::once("")) {
36 if line.is_empty() {
37 if fields_validity.iter().all(|&ok| ok) {
38 valid_passports_count += 1;
39 }
40 fields_validity.iter_mut().for_each(|ok| *ok = false);
41 } else {
42 for (line_idx, entry) in line.split(' ').enumerate() {
43 let mut parts = entry.split(':');
44 if let (Some(key), Some(value), None) = (parts.next(), parts.next(), parts.next()) {
45 if let Some(field_idx) = FIELD_NAMES.iter().position(|&field| field == key) {
46 fields_validity[field_idx] =
47 input.is_part_one() || is_valid(field_idx, value);
48 }
49 } else {
50 return Err(format!(
51 "Line {}: Word not having the format $KEY:$VALUE",
52 line_idx + 1
53 ));
54 }
55 }
56 }
57 }
58
59 Ok(valid_passports_count)
60}
61
62#[test]
63pub fn tests() {
64 use crate::input::{test_part_one, test_part_two};
65
66 test_part_one!("ecl:gry pid:860033327 eyr:2020 hcl:#fffffd
67byr:1937 iyr:2017 cid:147 hgt:183cm
68
69iyr:2013 ecl:amb cid:350 eyr:2023 pid:028048884
70hcl:#cfa07d byr:1929
71
72hcl:#ae17e1 iyr:2013
73eyr:2024
74ecl:brn pid:760753108 byr:1931
75hgt:179cm
76
77hcl:#cfa07d eyr:2025 pid:166559648
78iyr:2011 ecl:brn hgt:59in" => 2);
79
80 let real_input = include_str!("day04_input.txt");
81 test_part_one!(real_input => 210);
82 test_part_two!(real_input => 131);
83}