This commit is contained in:
Daniel S. 2020-12-04 14:58:01 +01:00
parent 336a03055d
commit 1da99c63be
2 changed files with 170 additions and 0 deletions

169
src/day4.rs Normal file
View file

@ -0,0 +1,169 @@
use aoc_runner_derive::{aoc, aoc_generator};
use std::collections::HashMap;
#[derive(Debug, PartialEq, Eq, Default)]
pub struct Creds {
byr: Option<String>,
iyr: Option<String>,
eyr: Option<String>,
hgt: Option<String>,
hcl: Option<String>,
ecl: Option<String>,
pid: Option<String>,
cid: Option<String>,
}
impl Creds {
fn fields(&self) -> HashMap<&str, Option<String>> {
let mut ret = HashMap::new();
ret.insert("byr", self.byr.clone());
ret.insert("iyr", self.iyr.clone());
ret.insert("eyr", self.eyr.clone());
ret.insert("hgt", self.hgt.clone());
ret.insert("hcl", self.hcl.clone());
ret.insert("ecl", self.ecl.clone());
ret.insert("pid", self.pid.clone());
ret.insert("cid", self.cid.clone());
ret
}
fn is_valid_part1(&self) -> bool {
for (k, v) in self.fields() {
if k == "cid" {
continue;
}
if v.is_none() {
return false;
}
}
return true;
}
fn year_in_range(val: &str, min: i64, max: i64) -> bool {
if val.len() != 4 {
return false;
}
if let Ok(val) = val.parse::<i64>() {
if val >= min && val <= max {
return true;
} else {
return false;
}
};
return false;
}
fn is_number(val: &str, ndigits: usize) -> bool {
val.chars().filter(|c| c.is_ascii_digit()).count() == ndigits
}
fn is_valid_height(val: &str) -> bool {
let it = val.chars();
let (num, unit): (String, String) = it.partition(|c| c.is_ascii_digit());
let num: Result<usize, _> = num.parse();
if let Ok(num) = num {
if unit == "cm" {
return num >= 150 && num <= 193;
};
if unit == "in" {
return num >= 59 && num <= 76;
};
}
return false;
}
fn validate_ecl(val: &str) -> bool {
let choices: Vec<&str> = vec!["amb", "blu", "brn", "gry", "grn", "hzl", "oth"];
return choices.iter().find(|&&v| v == val).is_some();
}
fn validate_hcl(val: &str) -> bool {
let mut ch = val.chars();
if ch.next() != Some('#') {
return false;
}
return ch.take_while(|v| v.is_ascii_hexdigit()).count() == 6;
}
fn validate(key: &str, value: &str) -> bool {
match key {
"byr" => Self::year_in_range(value, 1920, 2002),
"iyr" => Self::year_in_range(value, 2010, 2020),
"eyr" => Self::year_in_range(value, 2020, 2030),
"hgt" => Self::is_valid_height(value),
"pid" => Self::is_number(value, 9),
"ecl" => Self::validate_ecl(value),
"hcl" => Self::validate_hcl(value),
_ => false,
}
}
fn is_valid_part2(&self) -> bool {
for (k, v) in self.fields() {
if k == "cid" {
continue;
}
if let Some(v) = v {
if !Self::validate(k, &v) {
return false;
}
} else {
return false;
}
}
return true;
}
}
#[aoc_generator(day4)]
pub fn input_generator(input: &str) -> Vec<Creds> {
let mut ret = vec![];
for creds in input.split("\n\n") {
let creds = creds.replace("\n", " ");
let creds = creds.split(" ");
let mut cred_data = Creds::default();
for cred in creds {
let cred: Vec<&str> = cred.split(":").collect();
let (key, value) = (cred[0], cred[1]);
match key {
"byr" => {
cred_data.byr = Some(value.to_string());
}
"iyr" => {
cred_data.iyr = Some(value.to_string());
}
"eyr" => {
cred_data.eyr = Some(value.to_string());
}
"hgt" => {
cred_data.hgt = Some(value.to_string());
}
"hcl" => {
cred_data.hcl = Some(value.to_string());
}
"ecl" => {
cred_data.ecl = Some(value.to_string());
}
"pid" => {
cred_data.pid = Some(value.to_string());
}
"cid" => {
cred_data.cid = Some(value.to_string());
}
other => {
panic!("Invalid key: {}", other);
}
}
}
ret.push(cred_data);
}
ret
}
#[aoc(day4, part1)]
pub fn solve_part1(input: &Vec<Creds>) -> usize {
return input.iter().filter(|v| v.is_valid_part1()).count();
}
#[aoc(day4, part2)]
pub fn solve_part2(input: &Vec<Creds>) -> usize {
return input.iter().filter(|v| v.is_valid_part2()).count();
}

View file

@ -2,4 +2,5 @@ use aoc_runner_derive::aoc_lib;
pub mod day1; pub mod day1;
pub mod day2; pub mod day2;
pub mod day3; pub mod day3;
pub mod day4;
aoc_lib! { year = 2020 } aoc_lib! { year = 2020 }