From efd70672fb0bc5cc29672b480401cc7be2466c57 Mon Sep 17 00:00:00 2001 From: Jesse Luehrs Date: Fri, 4 Dec 2020 15:59:15 -0500 Subject: day 4 --- src/2020/4/mod.rs | 132 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 132 insertions(+) create mode 100644 src/2020/4/mod.rs (limited to 'src/2020/4/mod.rs') diff --git a/src/2020/4/mod.rs b/src/2020/4/mod.rs new file mode 100644 index 0000000..4b51b29 --- /dev/null +++ b/src/2020/4/mod.rs @@ -0,0 +1,132 @@ +use anyhow::Context as _; + +const REQUIRED_KEYS: &[&str] = + &["byr", "iyr", "eyr", "hgt", "hcl", "ecl", "pid"]; + +pub fn part1() -> anyhow::Result<()> { + let batch = crate::util::read_file_str("data/4.txt")?; + let mut valid = 0; + for passport in parse(&batch)? { + let mut cur_valid = true; + for key in REQUIRED_KEYS { + if !passport.contains_key(&key.to_string()) { + cur_valid = false; + break; + } + } + if cur_valid { + valid += 1; + } + } + println!("{}", valid); + Ok(()) +} + +pub fn part2() -> anyhow::Result<()> { + let batch = crate::util::read_file_str("data/4.txt")?; + let mut valid = 0; + for passport in parse(&batch)? { + let mut cur_valid = true; + for key in REQUIRED_KEYS { + match passport.get(&key.to_string()) { + Some(val) => { + if !validate(key, val)? { + cur_valid = false; + break; + } + } + None => { + cur_valid = false; + break; + } + } + } + if cur_valid { + valid += 1; + } + } + println!("{}", valid); + Ok(()) +} + +fn parse( + batch: &str, +) -> anyhow::Result>> { + let mut res = vec![]; + let mut cur = std::collections::HashMap::new(); + for line in batch.lines() { + if line.is_empty() { + res.push(cur); + cur = std::collections::HashMap::new(); + continue; + } + + for field in line.split(' ') { + let mut parts = field.split(':'); + let key = parts.next().with_context(|| { + format!("failed to parse field '{}'", field) + })?; + let value = parts.next().with_context(|| { + format!("failed to parse field '{}'", field) + })?; + cur.insert(key.to_string(), value.to_string()); + } + } + if !cur.is_empty() { + res.push(cur); + } + Ok(res) +} + +fn validate(key: &str, val: &str) -> anyhow::Result { + match key { + "byr" => match val.parse::() { + Ok(year) => Ok(year >= 1920 && year <= 2002), + Err(_) => Ok(false), + }, + "iyr" => match val.parse::() { + Ok(year) => Ok(year >= 2010 && year <= 2020), + Err(_) => Ok(false), + }, + "eyr" => match val.parse::() { + Ok(year) => Ok(year >= 2020 && year <= 2030), + Err(_) => Ok(false), + }, + "hgt" => { + if val.len() < 3 { + Ok(false) + } else if val.ends_with("in") { + match val[0..val.len() - 2].parse::() { + Ok(inches) => Ok(inches >= 59 && inches <= 76), + Err(_) => Ok(false), + } + } else if val.ends_with("cm") { + match val[0..val.len() - 2].parse::() { + Ok(inches) => Ok(inches >= 150 && inches <= 193), + Err(_) => Ok(false), + } + } else { + Ok(false) + } + } + "hcl" => Ok(val.len() == 7 + && val.starts_with('#') + && val[1..] + == val[1..] + .matches(|c: char| c.is_ascii_hexdigit()) + .collect::()), + "ecl" => Ok(val == "amb" + || val == "blu" + || val == "brn" + || val == "gry" + || val == "grn" + || val == "hzl" + || val == "oth"), + "pid" => Ok(val.len() == 9 + && val + == val + .matches(|c: char| c.is_ascii_digit()) + .collect::()), + _ => Err(anyhow::anyhow!("invalid key found: {}", key)), + } +} -- cgit v1.2.3-54-g00ecf