diff --git a/src/main.rs b/src/main.rs index 61ea42c..f328e4d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1 @@ -use aoc2024::solutions::day_1::part_two; - -fn main() { - println!("{}", part_two()); -} +fn main() {} diff --git a/src/solutions/day_1.rs b/src/solutions/day_1.rs index aa0b32f..bd16b0d 100644 --- a/src/solutions/day_1.rs +++ b/src/solutions/day_1.rs @@ -1,60 +1,67 @@ use std::collections::HashMap; -const INPUT: &str = include_str!("../../input/day1.txt"); +use super::AocSolution; -pub fn part_one() -> u64 { - let (mut left, mut right) = INPUT - .lines() - .filter_map(|s| s.split_once(' ').map(|(s, x)| (s.trim(), x.trim()))) - .filter_map( - |(s, x)| match (s.parse::().ok(), x.parse::().ok()) { - (Some(x), Some(y)) => Some((x, y)), - _ => None, - }, - ) - .fold((Vec::new(), Vec::new()), |(mut v1, mut v2), (x, y)| { - v1.push(x); - v2.push(y); - (v1, v2) - }); +#[derive(Clone, Copy)] +pub struct AocDayOneSolution; - left.sort(); - right.sort(); +impl AocSolution for AocDayOneSolution { + type Output = u64; + const INPUT: &str = include_str!("../../input/day1.txt"); - left.into_iter() - .zip(right) - .map(|(l, r)| if l > r { l - r } else { r - l }) - .sum() -} + fn part_one(&self) -> Self::Output { + let (mut left, mut right) = Self::INPUT + .lines() + .filter_map(|s| s.split_once(' ').map(|(s, x)| (s.trim(), x.trim()))) + .filter_map( + |(s, x)| match (s.parse::().ok(), x.parse::().ok()) { + (Some(x), Some(y)) => Some((x, y)), + _ => None, + }, + ) + .fold((Vec::new(), Vec::new()), |(mut v1, mut v2), (x, y)| { + v1.push(x); + v2.push(y); + (v1, v2) + }); -pub fn part_two() -> u64 { - let mut cache = HashMap::::new(); - let mut similarity_score = 0; + left.sort(); + right.sort(); - let (left, right) = INPUT - .lines() - .filter_map(|s| s.split_once(' ').map(|(s, x)| (s.trim(), x.trim()))) - .filter_map( - |(s, x)| match (s.parse::().ok(), x.parse::().ok()) { - (Some(x), Some(y)) => Some((x, y)), - _ => None, - }, - ) - .fold((Vec::new(), Vec::new()), |(mut v1, mut v2), (x, y)| { - v1.push(x); - v2.push(y); - (v1, v2) - }); - - for key in left { - if let Some(&val) = cache.get(&key) { - similarity_score += key * val; - } else { - let val = right.iter().filter(|e| e.eq(&&key)).count() as u64; - cache.insert(key, val); - similarity_score += key * val; - } + left.into_iter() + .zip(right) + .map(|(l, r)| if l > r { l - r } else { r - l }) + .sum() } + fn part_two(&self) -> Self::Output { + let mut cache = HashMap::::new(); + let mut similarity_score = 0; - similarity_score + let (left, right) = Self::INPUT + .lines() + .filter_map(|s| s.split_once(' ').map(|(s, x)| (s.trim(), x.trim()))) + .filter_map( + |(s, x)| match (s.parse::().ok(), x.parse::().ok()) { + (Some(x), Some(y)) => Some((x, y)), + _ => None, + }, + ) + .fold((Vec::new(), Vec::new()), |(mut v1, mut v2), (x, y)| { + v1.push(x); + v2.push(y); + (v1, v2) + }); + + for key in left { + if let Some(&val) = cache.get(&key) { + similarity_score += key * val; + } else { + let val = right.iter().filter(|e| e.eq(&&key)).count() as u64; + cache.insert(key, val); + similarity_score += key * val; + } + } + + similarity_score + } } diff --git a/src/solutions/day_2.rs b/src/solutions/day_2.rs new file mode 100644 index 0000000..44d1b5b --- /dev/null +++ b/src/solutions/day_2.rs @@ -0,0 +1,68 @@ +use super::AocSolution; + +#[derive(Clone, Copy)] +pub struct AocDayTwoSolution; + +struct LevelValidator; + +impl LevelValidator { + fn is_safe(&self, levels: &[i32]) -> bool { + let dec = levels[0] > levels[1]; + + for (cur, nxt) in levels.windows(2).map(|w| (w[0], w[1])) { + let diff = cur - nxt; + + if diff == 0 || diff.abs() > 3 || (diff > 0) != dec { + return false; + } + } + + true + } + + fn is_safe_with_rem(&self, levels: &[i32]) -> bool { + for i in 0..levels.len() { + let mut lvl = levels[0..i].to_vec(); + lvl.extend_from_slice(&levels[(i + 1)..]); + + if self.is_safe(&lvl) { + return true; + } + } + + false + } +} + +impl AocSolution for AocDayTwoSolution { + type Output = usize; + const INPUT: &str = include_str!("../../input/day2.txt"); + + fn part_one(&self) -> Self::Output { + let validator = LevelValidator; + + Self::INPUT + .lines() + .map(|n| { + n.split_whitespace() + .filter_map(|x| x.parse::().ok()) + .collect::>() + }) + .filter(|s| validator.is_safe(s)) + .count() + } + + fn part_two(&self) -> Self::Output { + let validator = LevelValidator; + + Self::INPUT + .lines() + .map(|n| { + n.split_whitespace() + .filter_map(|x| x.parse::().ok()) + .collect::>() + }) + .filter(|s| validator.is_safe(s) || validator.is_safe_with_rem(s)) + .count() + } +} diff --git a/src/solutions/mod.rs b/src/solutions/mod.rs index cfb592e..7a9aef4 100644 --- a/src/solutions/mod.rs +++ b/src/solutions/mod.rs @@ -1 +1,10 @@ pub mod day_1; +pub mod day_2; + +pub trait AocSolution { + type Output; + const INPUT: &str; + + fn part_one(&self) -> Self::Output; + fn part_two(&self) -> Self::Output; +}