Skip to content

Instantly share code, notes, and snippets.

@whiter4bbit
Last active December 4, 2020 14:05
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 whiter4bbit/220d30f3278b0077a08c4f28b8047eee to your computer and use it in GitHub Desktop.
Save whiter4bbit/220d30f3278b0077a08c4f28b8047eee to your computer and use it in GitHub Desktop.
AOC-2020: Day 4
use regex::Regex;
use std::io;
use std::ops::RangeInclusive;
use std::fs;
use std::collections::HashMap;
use std::str::FromStr;
fn match_re(re: &str, text: &str, captured_range: Option<RangeInclusive<i32>>) -> bool {
Regex::new(re).ok().and_then(|re|
re.captures(text).and_then(|capt| {
captured_range.and_then(|target_rage| {
capt.get(1).and_then(|group| {
i32::from_str(group.as_str()).ok().map(|num| target_rage.contains(&num))
})
}).or(Some(true))
}).or(Some(false))
).unwrap_or(false)
}
#[derive(Debug)]
struct Passport {
fields: HashMap<String, String>,
}
impl Passport {
fn required_fields_present(&self) -> bool {
vec!["byr", "iyr", "eyr", "hgt", "hcl", "ecl", "pid"]
.into_iter()
.all(|field| self.fields.contains_key(field))
}
fn fields_valid(&self) -> bool {
(&self.fields).into_iter()
.all(|(field, value)| {
match field.as_str() {
"byr" => match_re(r"^([1-9]\d{3})$", value, Some(1920..=2002)),
"iyr" => match_re(r"^([1-9]\d{3})$", value, Some(2010..=2020)),
"eyr" => match_re(r"^([1-9]\d{3})$", value, Some(2020..=2030)),
"hgt" => match_re(r"^([1-9]\d*)cm$", value, Some(150..=193)) ||
match_re(r"^([1-9]\d*)in$", value, Some(59..=76)),
"hcl" => match_re(r"^#[a-z0-9]{6}$", value, None),
"ecl" => match_re(r"^(amb|blu|brn|gry|grn|hzl|oth)$", value, None),
"pid" => match_re(r"^\d{9}$", value, None),
_ => true
}
})
}
}
fn read_passports(input: &str) -> io::Result<Vec<Passport>> {
let mut current: HashMap<String, String> = HashMap::new();
let mut passports: Vec<Passport> = Vec::new();
for line in fs::read_to_string(input)?.lines() {
if line.is_empty() {
passports.push(Passport {
fields: current.clone(),
});
current.clear();
} else {
line.split_ascii_whitespace()
.filter_map(|entry| {
let mut tokens = entry.splitn(3, ':');
match (tokens.next(), tokens.next()) {
(Some(key), Some(value)) => Some((key.to_string(), value.to_string())),
_ => None
}
})
.for_each(|(key, value)| {
current.insert(key.to_string(), value.to_string());
});
}
}
passports.push(Passport {
fields: current.clone()
});
Ok(passports)
}
#[allow(dead_code)]
pub fn solve_p1(input: &str) -> io::Result<usize> {
Ok(
read_passports(input)?
.into_iter()
.filter(|passport| passport.required_fields_present())
.count()
)
}
#[allow(dead_code)]
pub fn solve_p2(input: &str) -> io::Result<usize> {
Ok(
read_passports(input)?
.into_iter()
.filter(|passport| passport.required_fields_present())
.filter(|passport| passport.fields_valid())
.count()
)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment