You're not alone in the ugly feeling. I had a particularly nasty bug that gave me one result too many in part two (realized I had a missing ^ and $ on the regex for pid).
I see a fair amount of similarities in approach, so I'm glad to see I'm in good company. :D
useaoc_runner_derive::{aoc,aoc_generator};useregex::Regex;#[derive(Debug,PartialEq)]structHeight{measure:usize,unit:String,}implHeight{fnparse(hgt_str:&str)->Option<Height>{letre=Regex::new("(\\d+)(in|cm)").expect("Unable to create Regex");matchre.captures(hgt_str){None=>None,Some(captures)=>{leth=Height{measure:str::parse(captures.get(1).unwrap().as_str()).expect("Unable to parse number"),unit:String::from(captures.get(2).unwrap().as_str()),};Some(h)}}}fnis_valid(&self)->bool{matchself.unit.as_str(){"cm"=>self.measure>=150&&self.measure<=193,"in"=>self.measure>=59&&self.measure<=76,_=>panic!("Not a valid unit"),}}}#[derive(Debug,PartialEq)]structPassport{byr:Option<usize>,iyr:Option<usize>,eyr:Option<usize>,hgt:Option<Height>,hgt_str:Option<String>,hcl:Option<String>,ecl:Option<String>,pid:Option<String>,cid:Option<String>,}implPassport{fnnew()->Passport{Passport{byr:None,iyr:None,eyr:None,hgt:None,hgt_str:None,hcl:None,ecl:None,pid:None,cid:None,}}fnhas_fields(&self)->bool{self.byr.is_some()&&self.iyr.is_some()&&self.eyr.is_some()&&self.hgt_str.is_some()&&self.hcl.is_some()&&self.ecl.is_some()&&self.pid.is_some()}fnis_valid(&self)->bool{self.valid_byr()&&self.valid_iyr()&&self.valid_eyr()&&self.valid_hgt()&&self.valid_hcl()&&self.valid_ecl()&&self.valid_pid()}fnvalid_byr(&self)->bool{matchself.byr{None=>false,Some(n)=>n>=1920&&n<=2002,}}fnvalid_iyr(&self)->bool{matchself.iyr{None=>false,Some(n)=>n>=2010&&n<=2020,}}fnvalid_eyr(&self)->bool{matchself.eyr{None=>false,Some(n)=>n>=2020&&n<=2030,}}fnvalid_hgt(&self)->bool{match&self.hgt{None=>false,Some(h)=>h.is_valid(),}}fnvalid_hcl(&self)->bool{letre=Regex::new("^#[0-9a-f]{6}$").expect("Failed to make regex");match&self.hcl{None=>false,Some(hair)=>re.is_match(hair.as_str()),}}fnvalid_ecl(&self)->bool{letvalid_colors=vec!["amb","blu","brn","gry","grn","hzl","oth"];match&self.ecl{None=>false,Some(c)=>valid_colors.contains(&c.as_str()),}}fnvalid_pid(&self)->bool{letre=Regex::new("^[0-9]{9}$").expect("Failed to build Regex");match&self.pid{None=>false,Some(pid)=>re.is_match(pid.as_str()),}}}#[aoc_generator(day4)]fnparse_input_day4(input:&str)->Vec<Passport>{input.split("\n\n").map(|passport_str|parse_passport(passport_str)).collect()}fnparse_passport(passport_str:&str)->Passport{letkv:Vec<&str>=passport_str.lines().flat_map(|line|line.split(" ")).collect();letmutpass=Passport::new();forkey_valinkv{letpair:Vec<&str>=key_val.split(":").collect();match*(pair.get(0).unwrap()){"cid"=>pass.cid=Some(String::from(*pair.get(1).unwrap())),"byr"=>pass.byr=Some(str::parse(*pair.get(1).unwrap()).unwrap()),"iyr"=>pass.iyr=Some(str::parse(*pair.get(1).unwrap()).unwrap()),"eyr"=>pass.eyr=Some(str::parse(*pair.get(1).unwrap()).unwrap()),"hgt"=>{pass.hgt_str=Some(str::parse(*pair.get(1).unwrap()).unwrap());pass.hgt=Height::parse(*pair.get(1).unwrap());}"hcl"=>pass.hcl=Some(String::from(*pair.get(1).unwrap())),"ecl"=>pass.ecl=Some(String::from(*pair.get(1).unwrap())),"pid"=>pass.pid=Some(String::from(*pair.get(1).unwrap())),_=>panic!("Found passport code that doesn't match"),}}pass}#[aoc(day4,part1)]fncount_valid_passports(input:&Vec<Passport>)->usize{input.iter().filter(|pass|pass.has_fields()).count()}#[aoc(day4,part2)]fncount_valid_data_passports(input:&Vec<Passport>)->usize{input.iter().filter(|pass|pass.is_valid()).count()}
For further actions, you may consider blocking this person and/or reporting abuse
We're a place where coders share, stay up-to-date and grow their careers.
You're not alone in the ugly feeling. I had a particularly nasty bug that gave me one result too many in part two (realized I had a missing ^ and $ on the regex for
pid
).I see a fair amount of similarities in approach, so I'm glad to see I'm in good company. :D
As always, on Github.