Day 4
This commit is contained in:
parent
336a03055d
commit
1da99c63be
2 changed files with 170 additions and 0 deletions
169
src/day4.rs
Normal file
169
src/day4.rs
Normal 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();
|
||||
}
|
|
@ -2,4 +2,5 @@ use aoc_runner_derive::aoc_lib;
|
|||
pub mod day1;
|
||||
pub mod day2;
|
||||
pub mod day3;
|
||||
pub mod day4;
|
||||
aoc_lib! { year = 2020 }
|
||||
|
|
Loading…
Reference in a new issue