AoC2020/src/day2.rs

123 lines
2.8 KiB
Rust

use std::io::BufRead;
use std::str::FromStr;
use std::num::ParseIntError;
#[derive(Debug, PartialEq)]
struct Policy {
letter: char,
first: usize,
second: usize,
}
#[derive(Debug, PartialEq)]
struct Entry {
policy: Policy,
password: String
}
impl FromStr for Policy {
type Err = ParseIntError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let policy: Vec<_> = s.split(' ').collect();
let letter = policy[1].parse().unwrap();
let count: Vec<_> = policy[0].split('-').collect();
Ok(Policy {
letter,
first: count[0].parse()?,
second: count[1].parse()?,
})
}
}
impl FromStr for Entry {
type Err = ParseIntError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let entry: Vec<_> = s.split(':').collect();
Ok(Entry {
policy: entry[0].parse()?,
password: entry[1].trim().into(),
})
}
}
impl Entry {
fn is_valid_first(&self) -> bool {
let count = self.password.chars()
.filter(|c| *c == self.policy.letter)
.count();
self.policy.first <= count && count <= self.policy.second
}
fn is_valid_second(&self) -> bool {
(
self.password.chars().nth(self.policy.first - 1).unwrap() == self.policy.letter
) ^ (
self.password.chars().nth(self.policy.second - 1).unwrap() == self.policy.letter
)
}
}
fn count_valid_first<F: BufRead> (input: F) -> usize {
input.lines()
.filter_map(|line| line.unwrap().parse::<Entry>().ok())
.filter(|entry| entry.is_valid_first())
.count()
}
fn count_valid_second<F: BufRead> (input: F) -> usize {
input.lines()
.filter_map(|line| line.unwrap().parse::<Entry>().ok())
.filter(|entry| entry.is_valid_second())
.count()
}
pub fn part1<F: BufRead> (input: F) {
println!("{}", count_valid_first(input))
}
pub fn part2<F: BufRead> (input: F) {
println!("{}", count_valid_second(input))
}
#[cfg(test)]
mod test {
use super::*;
#[test]
pub fn test_parse() {
let res: Entry = "10-16 c: ccccqccchcccccjlc".parse().unwrap();
let expected = Entry {
password: "ccccqccchcccccjlc".into(),
policy: Policy {
first: 10,
second: 16,
letter: 'c'
}
};
assert_eq!(res, expected)
}
#[test]
pub fn test_count_valid_first() {
let input = r#"1-3 a: abcde
1-3 b: cdefg
2-9 c: ccccccccc
"#.as_bytes();
assert_eq!(count_valid_first(input), 2)
}
#[test]
pub fn test_count_valid_second() {
let input = r#"1-3 a: abcde
1-3 b: cdefg
2-9 c: ccccccccc
"#.as_bytes();
assert_eq!(count_valid_second(input), 1)
}
}