2020: day02: part 2

This commit is contained in:
Antoine Martin 2020-12-02 13:10:04 +01:00
parent e5a5c638f6
commit 43cca9e93f

View file

@ -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<Self> {
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::<usize>()
.map_err(|e| err!("couldn't parse position: {}", e))?;
let pos2 = s[(dash + 1)..space]
.parse::<usize>()
.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<String> { pub fn run() -> Result<String> {
let mut res = String::with_capacity(128); let mut res = String::with_capacity(128);
writeln!(res, "part 1: {}", part1(INPUT)?)?; writeln!(res, "part 1: {}", part1(INPUT)?)?;
writeln!(res, "part 2: {}", part2(INPUT)?)?;
Ok(res) Ok(res)
} }
@ -88,22 +145,44 @@ fn part1(input: &str) -> Result<usize> {
Ok(policies.iter().filter(|policy| policy.is_valid()).count()) Ok(policies.iter().filter(|policy| policy.is_valid()).count())
} }
fn part2(input: &str) -> Result<usize> {
let policies = input
.lines()
.map(|line| line.parse::<PassPolicyNew>().map_err(|e| err!("{}", e)))
.collect::<Result<Vec<PassPolicyNew>>>()?;
Ok(policies.iter().filter(|policy| policy.is_valid()).count())
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
static PROVIDED: &'static str = "1-3 a: abcde static PROVIDED1: &'static str = "1-3 a: abcde";
1-3 b: cdefg static PROVIDED2: &'static str = "1-3 b: cdefg";
2-9 c: ccccccccc static PROVIDED3: &'static str = "2-9 c: ccccccccc";
";
#[test] #[test]
fn part1_provided() { fn part1_provided() {
assert_eq!(part1(PROVIDED).unwrap(), 2); assert!(PROVIDED1.parse::<PassPolicy>().unwrap().is_valid());
assert!(!PROVIDED2.parse::<PassPolicy>().unwrap().is_valid());
assert!(PROVIDED3.parse::<PassPolicy>().unwrap().is_valid());
} }
#[test] #[test]
fn part1_real() { fn part1_real() {
assert_eq!(part1(INPUT).unwrap(), 556); assert_eq!(part1(INPUT).unwrap(), 556);
} }
#[test]
fn part2_provided() {
assert!(PROVIDED1.parse::<PassPolicyNew>().unwrap().is_valid());
assert!(!PROVIDED2.parse::<PassPolicyNew>().unwrap().is_valid());
assert!(!PROVIDED3.parse::<PassPolicyNew>().unwrap().is_valid());
}
#[test]
fn part2_real() {
assert_eq!(part2(INPUT).unwrap(), 605);
}
} }