diff --git a/aoc2020/src/day02.rs b/aoc2020/src/day02.rs index 822d033..28a92c5 100644 --- a/aoc2020/src/day02.rs +++ b/aoc2020/src/day02.rs @@ -71,10 +71,67 @@ impl FromStr for PassPolicy { } } +#[derive(Debug)] +struct PassPolicyNew { + pos1: usize, + pos2: usize, + letter: u8, + password: String, +} + +impl PassPolicyNew { + fn new(pos1: usize, pos2: usize, letter: u8, password: String) -> Self { + Self { + pos1, + pos2, + letter, + password, + } + } + + fn is_valid(&self) -> bool { + let bytes = self.password.as_bytes(); + (bytes[self.pos1 - 1] == self.letter) ^ (bytes[self.pos2 - 1] == self.letter) + } +} + +impl FromStr for PassPolicyNew { + type Err = aoc::Error; + + fn from_str(s: &str) -> Result { + let s = s.trim_end(); + + let space = s + .find(' ') + .ok_or_else(|| err!("couldn't parse password policy: didn't find space"))?; + let dash = s + .find('-') + .ok_or_else(|| err!("couldn't parse password policy: didn't find dash"))?; + + let pos1 = s[..dash] + .parse::() + .map_err(|e| err!("couldn't parse position: {}", e))?; + let pos2 = s[(dash + 1)..space] + .parse::() + .map_err(|e| err!("couldn't parse position: {}", e))?; + + let colon = s + .find(':') + .ok_or_else(|| err!("couldn't parse password policy: didn't find colon"))?; + + let letter = s.as_bytes()[colon - 1]; + + let password = &s[(colon + 2)..]; + + Ok(Self::new(pos1, pos2, letter, password.to_string())) + } +} + pub fn run() -> Result { let mut res = String::with_capacity(128); writeln!(res, "part 1: {}", part1(INPUT)?)?; + writeln!(res, "part 2: {}", part2(INPUT)?)?; Ok(res) } @@ -88,22 +145,44 @@ fn part1(input: &str) -> Result { Ok(policies.iter().filter(|policy| policy.is_valid()).count()) } +fn part2(input: &str) -> Result { + let policies = input + .lines() + .map(|line| line.parse::().map_err(|e| err!("{}", e))) + .collect::>>()?; + + Ok(policies.iter().filter(|policy| policy.is_valid()).count()) +} + #[cfg(test)] mod tests { use super::*; - static PROVIDED: &'static str = "1-3 a: abcde -1-3 b: cdefg -2-9 c: ccccccccc -"; + static PROVIDED1: &'static str = "1-3 a: abcde"; + static PROVIDED2: &'static str = "1-3 b: cdefg"; + static PROVIDED3: &'static str = "2-9 c: ccccccccc"; #[test] fn part1_provided() { - assert_eq!(part1(PROVIDED).unwrap(), 2); + assert!(PROVIDED1.parse::().unwrap().is_valid()); + assert!(!PROVIDED2.parse::().unwrap().is_valid()); + assert!(PROVIDED3.parse::().unwrap().is_valid()); } #[test] fn part1_real() { assert_eq!(part1(INPUT).unwrap(), 556); } + + #[test] + fn part2_provided() { + assert!(PROVIDED1.parse::().unwrap().is_valid()); + assert!(!PROVIDED2.parse::().unwrap().is_valid()); + assert!(!PROVIDED3.parse::().unwrap().is_valid()); + } + + #[test] + fn part2_real() { + assert_eq!(part2(INPUT).unwrap(), 605); + } }