2024-01-14 21:04:10 +00:00
|
|
|
//! Day 02 of 2020.
|
|
|
|
|
2022-10-03 16:02:40 +00:00
|
|
|
use crate::prelude::*;
|
|
|
|
|
2024-01-14 21:04:10 +00:00
|
|
|
/// Get the solution for day 02 of 2020.
|
2022-10-03 16:02:40 +00:00
|
|
|
pub fn solution() -> Solution {
|
|
|
|
Solution::new(Day::new(2, 2020), part_1, part_2).with_expected(638, 699)
|
|
|
|
}
|
|
|
|
|
2024-01-14 21:04:10 +00:00
|
|
|
/// The data for each line of the puzzle input.
|
2022-10-03 16:02:40 +00:00
|
|
|
#[derive(Debug)]
|
|
|
|
struct Item {
|
2024-01-14 21:04:10 +00:00
|
|
|
/// The minimum amount of times the letter has to be in the password.
|
2022-10-03 16:02:40 +00:00
|
|
|
min: usize,
|
2024-01-14 21:04:10 +00:00
|
|
|
/// The maximum amount of times the letter has to be in the password.
|
2022-10-03 16:02:40 +00:00
|
|
|
max: usize,
|
2024-01-14 21:04:10 +00:00
|
|
|
/// The letter that must be in the password.
|
2022-10-03 16:02:40 +00:00
|
|
|
letter: String,
|
2024-01-14 21:04:10 +00:00
|
|
|
/// The password to check.
|
2022-10-03 16:02:40 +00:00
|
|
|
password: String,
|
|
|
|
}
|
|
|
|
|
2024-01-14 21:04:10 +00:00
|
|
|
/// Parse all the [`Item`]s inside the puzzle input.
|
2022-10-03 16:02:40 +00:00
|
|
|
fn parse_items(input: &str) -> Vec<Item> {
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2024-01-14 21:04:10 +00:00
|
|
|
/// The logic to solve part one.
|
2022-10-03 16:02:40 +00:00
|
|
|
fn part_1(input: &str) -> Result<String> {
|
|
|
|
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(),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2024-01-14 21:04:10 +00:00
|
|
|
/// The logic to solve part two.
|
2022-10-03 16:02:40 +00:00
|
|
|
fn part_2(input: &str) -> Result<String> {
|
|
|
|
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(),
|
|
|
|
)
|
|
|
|
}
|