Add 9 first days
This commit is contained in:
111
2-password_philosophy/src/main.rs
Normal file
111
2-password_philosophy/src/main.rs
Normal file
@@ -0,0 +1,111 @@
|
||||
use std::ops::RangeInclusive;
|
||||
use anyhow::Result;
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
struct PasswordPolicy {
|
||||
char: u8,
|
||||
range: RangeInclusive<usize>,
|
||||
}
|
||||
|
||||
impl PasswordPolicy {
|
||||
fn check_password(&self, password: &str) -> bool {
|
||||
self.range.contains(
|
||||
&password
|
||||
.as_bytes()
|
||||
.iter().
|
||||
filter(|&&c| c == self.char)
|
||||
.count()
|
||||
)
|
||||
}
|
||||
|
||||
fn check_password_newpolicy(&self, password: &str) -> bool {
|
||||
(password.chars().nth(self.range.start()-1).unwrap() as u8 == self.char) ^ (password.chars().nth(self.range.end()-1).unwrap() as u8 == self.char)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
enum ParseError {
|
||||
#[error("Expected {0}")]
|
||||
Expected(&'static str)
|
||||
}
|
||||
|
||||
fn parse_line(line: &str) -> Result<(PasswordPolicy,String)> {
|
||||
let (policy_s, password) = {
|
||||
let mut tokens = line.split(": ");
|
||||
(
|
||||
tokens.next().ok_or(ParseError::Expected("Coucou"))?,
|
||||
tokens.next().ok_or(ParseError::Expected("Coincoin"))?,
|
||||
)
|
||||
};
|
||||
let policy = {
|
||||
let (range_s, char_s) = {
|
||||
let mut tokens = policy_s.split(' ');
|
||||
(
|
||||
tokens.next().ok_or(ParseError::Expected("Range"))?,
|
||||
tokens.next().ok_or(ParseError::Expected("Char"))?,
|
||||
)
|
||||
};
|
||||
let (min_s, max_s) = {
|
||||
let mut tokens = range_s.split('-');
|
||||
(
|
||||
tokens.next().ok_or(ParseError::Expected("Min"))?,
|
||||
tokens.next().ok_or(ParseError::Expected("Max"))?,
|
||||
)
|
||||
};
|
||||
PasswordPolicy {
|
||||
char: if char_s.len() == 1 {
|
||||
char_s.as_bytes()[0]
|
||||
} else {
|
||||
// return Err(ParseError::Expected("policy byte to be exactly one byte"));
|
||||
return Err(ParseError::Expected("password policy byte to be exactly 1 byte").into());
|
||||
},
|
||||
range: (min_s.parse()?)..=(max_s.parse()?),
|
||||
}
|
||||
};
|
||||
Ok((policy, password.to_string()))
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let count = include_str!("../data/input.txt")
|
||||
.lines()
|
||||
.map(parse_line)
|
||||
.map(Result::unwrap)
|
||||
.filter(|(policy,password)| policy.check_password(password))
|
||||
.count();
|
||||
println!("{} passes are valid", count);
|
||||
let count_new_policy = include_str!("../data/input.txt")
|
||||
.lines()
|
||||
.map(parse_line)
|
||||
.map(Result::unwrap)
|
||||
.filter(|(policy,password)| policy.check_password_newpolicy(password))
|
||||
.count();
|
||||
println!("{} passes are valid with new policy", count_new_policy);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_is_valid() {
|
||||
let policy = PasswordPolicy{ char: b'b', range: 1..=4 };
|
||||
assert_eq!(policy.check_password("boumbaby"), true);
|
||||
assert_eq!(policy.check_password("b-b-b-boumbaby"), false);
|
||||
assert_eq!(policy.check_password("oumay"), false);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_line() {
|
||||
assert_eq!(
|
||||
parse_line("1-5 b: boulbi").unwrap(),
|
||||
(
|
||||
PasswordPolicy {
|
||||
char: b'b',
|
||||
range: 1..=5,
|
||||
},
|
||||
"boulbi".to_owned(),
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user