1
Fork 0
advent-of-code/source/year_2020/day_04/mod.rs

165 lines
4.1 KiB
Rust

use crate::prelude::*;
pub fn solution() -> Solution {
Solution::new(Day::new(4, 2020), part_1, part_2).with_expected(237, 172)
}
#[derive(Debug, Clone)]
struct Passport {
byr: Option<String>,
iyr: Option<String>,
eyr: Option<String>,
hgt: Option<String>,
hcl: Option<String>,
ecl: Option<String>,
pid: Option<String>,
cid: Option<String>,
}
fn parse_passports(input: &str) -> Vec<Passport> {
let mut passports = vec![];
let blank = Passport {
byr: None,
iyr: None,
eyr: None,
hgt: None,
hcl: None,
ecl: None,
pid: None,
cid: None,
};
let mut intermediate = blank.clone();
for line in input.lines() {
if line.is_empty() {
passports.push(intermediate.clone());
intermediate = blank.clone();
continue;
}
let components = line.split(' ');
for component in components {
let colon_index = component.find(':').unwrap();
let key = &component[0..colon_index];
let value = &component[colon_index + 1..];
match key {
"byr" => intermediate.byr = Some(value.to_string()),
"iyr" => intermediate.iyr = Some(value.to_string()),
"eyr" => intermediate.eyr = Some(value.to_string()),
"hgt" => intermediate.hgt = Some(value.to_string()),
"hcl" => intermediate.hcl = Some(value.to_string()),
"ecl" => intermediate.ecl = Some(value.to_string()),
"pid" => intermediate.pid = Some(value.to_string()),
"cid" => intermediate.cid = Some(value.to_string()),
_ => unreachable!("{key}"),
};
}
}
passports
}
fn part_1(input: &str) -> Result<String> {
Ok(
parse_passports(input)
.into_iter()
.filter(|passport| {
passport.byr.is_some()
&& passport.iyr.is_some()
&& passport.eyr.is_some()
&& passport.hgt.is_some()
&& passport.hcl.is_some()
&& passport.ecl.is_some()
&& passport.pid.is_some()
})
.count()
.to_string(),
)
}
fn part_2(input: &str) -> Result<String> {
let hcl_regex = Regex::new("^#[a-fA-F0-9]{6}$").unwrap();
let pid_regex = Regex::new("^[0-9]{9}$").unwrap();
let ecl_values = vec![
"amb".to_string(),
"blu".to_string(),
"brn".to_string(),
"gry".to_string(),
"grn".to_string(),
"hzl".to_string(),
"oth".to_string(),
];
Ok(
parse_passports(input)
.into_iter()
.filter(|passport| {
passport.byr.is_some()
&& passport.iyr.is_some()
&& passport.eyr.is_some()
&& passport.hgt.is_some()
&& passport.hcl.is_some()
&& passport.ecl.is_some()
&& passport.pid.is_some()
})
.filter(|passport| {
let byr = passport
.byr
.as_ref()
.unwrap()
.parse::<i32>()
.unwrap_or_default();
(1920..=2002).contains(&byr)
})
.filter(|passport| {
let iyr = passport
.iyr
.as_ref()
.unwrap()
.parse::<i32>()
.unwrap_or_default();
(2010..=2020).contains(&iyr)
})
.filter(|passport| {
let eyr = passport
.eyr
.as_ref()
.unwrap()
.parse::<i32>()
.unwrap_or_default();
(2020..=2030).contains(&eyr)
})
.filter(|passport| {
let hgt = passport.hgt.as_ref().unwrap();
match &hgt[hgt.len() - 2..] {
"cm" => {
let value =
hgt[0..hgt.len() - 2].parse::<i32>().unwrap_or_default();
(150..=193).contains(&value)
}
"in" => {
let value =
hgt[0..hgt.len() - 2].parse::<i32>().unwrap_or_default();
(59..=76).contains(&value)
}
_ => false,
}
})
.filter(|passport| {
let hcl = passport.hcl.as_ref().unwrap();
hcl_regex.is_match(hcl)
})
.filter(|passport| {
let ecl = passport.ecl.as_ref().unwrap();
ecl_values.contains(ecl)
})
.filter(|passport| {
let pid = passport.pid.as_ref().unwrap();
pid_regex.is_match(pid)
})
.count()
.to_string(),
)
}