aoc2020/src/bin/day2.rs

69 lines
1.7 KiB
Rust

use std::convert::TryInto;
const INPUT: &str = include_str!("../../data/day2");
struct Policy {
min: usize,
max: usize,
chr: char,
}
impl Policy {
fn parse(text: &str) -> Self {
let tokens: Vec<_> = text.trim().split_whitespace().collect();
let [range, chr]: [&str; 2] = tokens.try_into().unwrap();
let tokens: Vec<_> = range.split("-").collect();
let [min, max]: [&str; 2] = tokens.try_into().unwrap();
assert!(chr.len() == 1);
let chr = chr.chars().next().unwrap();
let min = min.parse::<usize>().unwrap();
let max = max.parse::<usize>().unwrap();
Self { min, max, chr }
}
fn test(&self, input: &str) -> bool {
let count = input.chars().filter(|&c| c == self.chr).count();
count >= self.min && count <= self.max
}
fn test_crazy(&self, input: &str) -> bool {
let chars: Vec<_> = input.chars().collect();
assert!(self.min > 0 && self.max > 0);
assert!(self.min <= chars.len() && self.max <= chars.len());
(chars[self.min-1] == self.chr) != (chars[self.max-1] == self.chr)
}
}
struct Entry {
policy: Policy,
password: String,
}
impl Entry {
fn parse(line: &str) -> Self {
let tokens: Vec<_> = line.split(":").collect();
let [policy, password]: [&str; 2] = tokens.try_into().unwrap();
Self {
policy: Policy::parse(policy),
password: password.trim().into(),
}
}
fn parse_list(input: &str) -> Vec<Self> {
input.lines().map(Self::parse).collect()
}
fn valid(&self) -> bool {
self.policy.test(&self.password)
}
fn valid_crazy(&self) -> bool {
self.policy.test_crazy(&self.password)
}
}
fn main() {
let entries = Entry::parse_list(INPUT);
println!("Valid entries: {}", entries.iter().filter(|e| e.valid()).count());
println!("Crazy valid entries: {}", entries.iter().filter(|e| e.valid_crazy()).count());
}