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…
	
	Add table
		Add a link
		
	
		Reference in a new issue