Created
December 5, 2020 00:44
-
-
Save JCBurnside/e262f08a843956db09e4766b7e8f4b49 to your computer and use it in GitHub Desktop.
day 4 of AoC2020
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use lazy_static::lazy_static; | |
use parse_display::{Display, FromStr}; | |
use std::str::FromStr; | |
#[derive(FromStr, Debug, Copy, Clone)] | |
#[from_str(regex = "(?P<0>\\d+)(in|cm){1}")] | |
pub enum Height { | |
#[from_str(regex = "(?P<0>\\d+)cm")] | |
cm(u8), | |
#[from_str(regex = "(?P<0>\\d+)in")] | |
inch(u8), | |
} | |
#[derive(Debug)] | |
pub struct DataVec(pub Vec<DataP1>); | |
#[derive(Debug, Display)] | |
#[display("")] | |
pub struct VectorParseErr; | |
impl std::error::Error for VectorParseErr {} | |
impl FromStr for DataVec { | |
type Err = VectorParseErr; | |
fn from_str(s: &str) -> Result<Self, Self::Err> { | |
let mut output = DataVec(Vec::new()); | |
let mut current_data = DataP1::default(); | |
for line in s.lines() { | |
if line.is_empty() { | |
output.0.push(current_data); | |
current_data = DataP1::default(); | |
continue; | |
} | |
for word in line.split(' ') { | |
for cap in regex::Regex::new("(?P<name>[a-z]{3}):(?P<value>.+)") | |
.unwrap() | |
.captures_iter(word) | |
{ | |
match &cap["name"] { | |
"byr" => { | |
if cap["value"].is_empty() { | |
return Err(VectorParseErr); | |
} | |
current_data.byr = Some(String::from(&cap["value"])); | |
} | |
"iyr" => { | |
if cap["value"].is_empty() { | |
return Err(VectorParseErr); | |
} | |
current_data.iyr = Some(String::from(&cap["value"])); | |
} | |
"eyr" => { | |
if cap["value"].is_empty() { | |
return Err(VectorParseErr); | |
} | |
current_data.eyr = Some(String::from(&cap["value"])); | |
} | |
"hgt" => { | |
if cap["value"].is_empty() { | |
return Err(VectorParseErr); | |
} | |
current_data.hgt = Some(String::from(&cap["value"])); | |
} | |
"hcl" => { | |
if cap["value"].is_empty() { | |
return Err(VectorParseErr); | |
} | |
current_data.hcl = Some(String::from(&cap["value"])); | |
} | |
"ecl" => { | |
if cap["value"].is_empty() { | |
return Err(VectorParseErr); | |
} | |
current_data.ecl = Some(String::from(&cap["value"])); | |
} | |
"pid" => { | |
if cap["value"].is_empty() { | |
return Err(VectorParseErr); | |
} | |
current_data.pid = Some(String::from(&cap["value"])); | |
} | |
"cid" => { | |
if cap["value"].is_empty() { | |
return Err(VectorParseErr); | |
} | |
current_data.cid = Some(String::from(&cap["value"])); | |
} | |
_ => return Err(VectorParseErr), | |
} | |
} | |
} | |
} | |
output.0.push(current_data); | |
Ok(output) | |
} | |
} | |
#[derive(Default, Debug)] | |
pub struct DataP1 { | |
pub byr: Option<String>, | |
pub iyr: Option<String>, | |
pub eyr: Option<String>, | |
pub hgt: Option<String>, | |
pub hcl: Option<String>, | |
pub ecl: Option<String>, | |
pub pid: Option<String>, | |
pub cid: Option<String>, | |
} | |
impl DataP1 { | |
pub fn is_valid(&self) -> bool { | |
self.byr.is_some() | |
&& self.iyr.is_some() | |
&& self.eyr.is_some() | |
&& self.hgt.is_some() | |
&& self.hcl.is_some() | |
&& self.ecl.is_some() | |
&& self.pid.is_some() | |
// && self.cid.is_some() | |
} | |
} | |
#[derive(Display, FromStr, Debug, Clone, Copy)] | |
#[display(style = "snake_case")] | |
pub enum EyeColor { | |
amb, | |
blu, | |
brn, | |
gry, | |
grn, | |
hzl, | |
oth, | |
} | |
#[derive(Default, Debug)] | |
pub struct DataP2 { | |
pub byr: Option<u16>, | |
pub iyr: Option<u16>, | |
pub eyr: Option<u16>, | |
pub hgt: Option<Height>, | |
pub hcl: Option<String>, | |
pub ecl: Option<EyeColor>, | |
pub pid: Option<String>, | |
pub cid: Option<String>, | |
} | |
impl From<&DataP1> for DataP2 { | |
fn from(data: &DataP1) -> Self { | |
lazy_static! { | |
static ref HCL_RE: regex::Regex = regex::Regex::new("#[0-9a-f]{6}").unwrap(); | |
} | |
let mut output = DataP2::default(); | |
output.byr = match &data.byr { | |
Some(s) => { | |
if let Ok(u) = s.parse() { | |
if u >= 1920 && u <= 2002 { | |
Some(u) | |
} else { | |
None | |
} | |
} else { | |
None | |
} | |
} | |
_ => None, | |
}; | |
output.iyr = match &data.iyr { | |
Some(s) => { | |
if let Ok(u) = s.parse() { | |
if u >= 2010 && u <= 2020 { | |
Some(u) | |
} else { | |
None | |
} | |
} else { | |
None | |
} | |
} | |
_ => None, | |
}; | |
output.eyr = match &data.eyr { | |
Some(s) => { | |
if let Ok(u) = s.parse() { | |
if u >= 2020 && u <= 2030 { | |
Some(u) | |
} else { | |
None | |
} | |
} else { | |
None | |
} | |
} | |
_ => None, | |
}; | |
output.hgt = match &data.hgt { | |
Some(s) => match s.parse() { | |
Ok(Height::inch(u)) => { | |
if u >= 59 && u <= 76 { | |
Some(Height::inch(u)) | |
} else { | |
None | |
} | |
} | |
Ok(Height::cm(u)) => { | |
if u >= 150 && u <= 193 { | |
Some(Height::cm(u)) | |
} else { | |
None | |
} | |
} | |
_ => None, | |
}, | |
_ => None, | |
}; | |
output.hcl = match &data.hcl { | |
Some(s) => { | |
if HCL_RE.is_match(s) { | |
Some(s.clone()) | |
} else { | |
None | |
} | |
} | |
_ => None, | |
}; | |
output.ecl = match &data.ecl { | |
Some(s) => match s.parse() { | |
Ok(c) => Some(c), | |
_ => None, | |
}, | |
_ => None, | |
}; | |
output.pid = match &data.pid { | |
Some(s) => { | |
if s.len() == 9 { | |
Some(s.clone()) | |
} else { | |
None | |
} | |
} | |
_ => None, | |
}; | |
output | |
} | |
} | |
impl DataP2 { | |
pub fn is_valid(&self) -> bool { | |
self.byr.is_some() | |
&& self.iyr.is_some() | |
&& self.eyr.is_some() | |
&& self.hgt.is_some() | |
&& self.hcl.is_some() | |
&& self.ecl.is_some() | |
&& self.pid.is_some() | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
mod data; | |
use data::{DataP1, DataP2, DataVec}; | |
use std::str::FromStr; | |
fn part1(data: &[DataP1]) -> usize { | |
let count = data.iter().filter(|it| it.is_valid()).count(); | |
println!("correct lenght {}", count); | |
count | |
} | |
fn part2(data: &[DataP2]) -> usize { | |
let count = data.iter().filter(|it| it.is_valid()).count(); | |
println!("validated :{}", count); | |
count | |
} | |
fn main() -> anyhow::Result<()> { | |
let data: DataVec = DataVec::from_str(std::fs::read_to_string("data.txt")?.as_str())?; | |
println!("{:?}", data.0.first()); | |
part1(&data.0); | |
let data: Vec<DataP2> = data.0.iter().map(|it| it.into()).collect(); | |
part2(&data); | |
Ok(()) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment