From 1da99c63be8381b08ef8c7ebbc5bcc5899f21efc Mon Sep 17 00:00:00 2001 From: Daniel Seiller Date: Fri, 4 Dec 2020 14:58:01 +0100 Subject: [PATCH] Day 4 --- src/day4.rs | 169 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 1 + 2 files changed, 170 insertions(+) create mode 100644 src/day4.rs diff --git a/src/day4.rs b/src/day4.rs new file mode 100644 index 0000000..fbbb544 --- /dev/null +++ b/src/day4.rs @@ -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, + iyr: Option, + eyr: Option, + hgt: Option, + hcl: Option, + ecl: Option, + pid: Option, + cid: Option, +} + +impl Creds { + fn fields(&self) -> HashMap<&str, Option> { + 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::() { + 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 = 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 { + 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) -> usize { + return input.iter().filter(|v| v.is_valid_part1()).count(); +} + +#[aoc(day4, part2)] +pub fn solve_part2(input: &Vec) -> usize { + return input.iter().filter(|v| v.is_valid_part2()).count(); +} diff --git a/src/lib.rs b/src/lib.rs index 19246c5..6da892d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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 }