Add 9 first days

This commit is contained in:
2021-01-08 23:41:37 +11:00
parent 4846e7c811
commit 2fd73ae5d1
49 changed files with 9734 additions and 0 deletions

View 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(),
)
)
}
}