//! Day 02 of 2020. use crate::prelude::*; /// Get the solution for day 02 of 2020. pub fn solution() -> Solution { Solution::new(Day::new(2, 2020), part_1, part_2).with_expected(638, 699) } /// The data for each line of the puzzle input. #[derive(Debug)] struct Item { /// The minimum amount of times the letter has to be in the password. min: usize, /// The maximum amount of times the letter has to be in the password. max: usize, /// The letter that must be in the password. letter: String, /// The password to check. password: String, } /// Parse all the [`Item`]s inside the puzzle input. fn parse_items(input: &str) -> Vec { let mut items = vec![]; for line in input.lines() { // TODO: Replace with regex. let min = &line[0..line.find('-').unwrap()]; let max = &line[line.find('-').unwrap() + 1..line.find(' ').unwrap()]; let letter = &line[line.find(' ').unwrap() + 1..line.find(':').unwrap()]; let password = &line[line.find(": ").unwrap() + 2..]; items.push(Item { min: min.parse().unwrap(), max: max.parse().unwrap(), letter: letter.to_string(), password: password.to_string(), }) } items } /// The logic to solve part one. fn part_1(input: &str) -> Result { Ok( parse_items(input) .into_iter() .filter(|item| item.password.matches(&item.letter).count() >= item.min) .filter(|item| item.password.matches(&item.letter).count() <= item.max) .count() .to_string(), ) } /// The logic to solve part two. fn part_2(input: &str) -> Result { Ok( parse_items(input) .into_iter() .filter(|item| { let letter = item.letter.chars().next(); let target_one = item.password.chars().nth(item.min - 1); let target_two = item.password.chars().nth(item.max - 1); target_one != target_two && (target_one == letter || target_two == letter) }) .count() .to_string(), ) }