Skip to content

Instantly share code, notes, and snippets.

@samueltardieu
Created December 4, 2020 10:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save samueltardieu/9d61cca5c6366f98e43f5719c3ae86b5 to your computer and use it in GitHub Desktop.
Save samueltardieu/9d61cca5c6366f98e43f5719c3ae86b5 to your computer and use it in GitHub Desktop.
use lazy_static::lazy_static;
use regex::Regex;
use std::collections::{HashMap, HashSet};
#[aoc_generator(day4)]
fn input_generator(input: &str) -> Vec<HashMap<String, String>> {
input
.split(&Regex::new("\n\n").unwrap())
.map(|passport| {
passport
.split_ascii_whitespace()
.map(|w| {
let mut f = w.split(':');
(f.next().unwrap().to_owned(), f.next().unwrap().to_owned())
})
.collect()
})
.collect()
}
#[aoc(day4, part1)]
fn part1(passports: &[HashMap<String, String>]) -> usize {
passports
.iter()
.filter(|&passport| has_required_keys(passport))
.count()
}
#[aoc(day4, part2)]
fn part2(passports: &[HashMap<String, String>]) -> usize {
passports
.iter()
.filter(|&p| {
has_required_keys(p) && p.iter().all(|(k, v)| check_field(k, v).unwrap_or(false))
})
.count()
}
fn has_required_keys(passport: &HashMap<String, String>) -> bool {
lazy_static! {
static ref REQUIRED: HashSet<&'static str> =
["byr", "iyr", "eyr", "hgt", "hcl", "ecl", "pid", "cid"]
.iter()
.cloned()
.collect();
}
REQUIRED
.difference(&passport.keys().map(|k| k.as_str()).collect::<HashSet<_>>())
.filter(|&&s| s != "cid")
.next()
.is_none()
}
fn check_field(k: &str, v: &str) -> Result<bool, Box<dyn std::error::Error>> {
lazy_static! {
static ref EYE_COLOR: HashSet<&'static str> =
["amb", "blu", "brn", "gry", "grn", "hzl", "oth"]
.iter()
.cloned()
.collect();
}
match k {
"byr" => Ok(v.len() == 4 && (1920..=2002).contains(&v.parse::<u32>()?)),
"iyr" => Ok(v.len() == 4 && (2010..=2020).contains(&v.parse::<u32>()?)),
"eyr" => Ok(v.len() == 4 && (2020..=2030).contains(&v.parse::<u32>()?)),
"hgt" => match v.split_at(v.len() - 2) {
(h, "cm") => Ok((150..=193).contains(&h.parse::<u32>()?)),
(h, "in") => Ok((59..=76).contains(&h.parse::<u32>()?)),
_ => Ok(false),
},
"hcl" => Ok(v.chars().next() == Some('#')
&& v.chars()
.skip(1)
.all(|c| c.is_ascii_hexdigit() && !c.is_uppercase())),
"ecl" => Ok(EYE_COLOR.contains(v)),
"pid" => Ok(v.len() == 9 && v.chars().all(|c| c.is_numeric())),
_ => Ok(true),
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment