From a6995cbc515870156bad96ff6202e56abda69e55 Mon Sep 17 00:00:00 2001 From: Timothy Warren Date: Wed, 6 Dec 2023 09:38:40 -0500 Subject: [PATCH] Complete 2023 day 2 --- 2023/day2/src/main.rs | 139 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 123 insertions(+), 16 deletions(-) diff --git a/2023/day2/src/main.rs b/2023/day2/src/main.rs index 8db22e8..eb70cae 100644 --- a/2023/day2/src/main.rs +++ b/2023/day2/src/main.rs @@ -1,12 +1,22 @@ use std::collections::HashMap; + +const FILE_STR: &'static str = include_str!("input.txt"); + #[derive(Debug, PartialOrd, PartialEq)] struct CubeSet { red: usize, - blue: usize, green: usize, + blue: usize, +} + +impl CubeSet { + fn new(red: usize, green: usize, blue: usize) -> Self { + CubeSet { red, green, blue } + } } type CubeMap = HashMap>; +type MinCubeMap = HashMap; fn parse_colors(raw_colors: Vec<&str>) -> CubeSet { let mut red = 0usize; @@ -38,7 +48,7 @@ fn parse_colors(raw_colors: Vec<&str>) -> CubeSet { } } - CubeSet { red, blue, green } + CubeSet::new(red, green, blue) } fn parse_game(line: &str, map: &mut CubeMap) { @@ -67,27 +77,45 @@ fn is_valid(reference: &CubeSet, comparison: &CubeSet) -> bool { && reference.red >= comparison.red } -fn filter_valid_games(reference: &CubeSet, games: CubeMap) -> CubeMap { +fn validate_games(reference: &CubeSet, games: CubeMap) -> Vec { games .into_iter() .filter(|(_, cubes)| cubes.iter().all(|c| is_valid(reference, c))) - .collect() -} - -fn validate_games(reference: &CubeSet, games: CubeMap) -> Vec { - filter_valid_games(reference, games) - .into_iter() .map(|(id, _)| id) .collect() } -fn find_min_cubes(valid_games: &CubeMap) -> CubeMap { - let games = valid_games.clone().to_owned(); - todo!(); +fn find_min_cubes(valid_games: &CubeMap) -> MinCubeMap { + let mut min_cubes = HashMap::new(); + + valid_games.iter().for_each(|(id, set_map)| { + let mut r = 0usize; + let mut g = 0usize; + let mut b = 0usize; + + set_map.iter().for_each(|set| { + if set.red > r { + r = set.red; + } + if set.green > g { + g = set.green; + } + if set.blue > b { + b = set.blue; + } + }); + + min_cubes.insert(*id, CubeSet::new(r, g, b)); + }); + + min_cubes } -fn main() { - let file_str = include_str!("input.txt"); +fn cube_power(cube: &CubeSet) -> usize { + cube.red * cube.green * cube.blue +} + +fn part_one() { let mut map: CubeMap = HashMap::new(); let reference = CubeSet { red: 12, @@ -95,7 +123,7 @@ fn main() { blue: 14, }; - file_str + FILE_STR .split('\n') .for_each(|line| parse_game(line, &mut map)); @@ -105,5 +133,84 @@ fn main() { println!("Part 1 Sum of valid games: {}", sum); } +fn part_two() { + let mut map: CubeMap = HashMap::new(); + FILE_STR + .split('\n') + .for_each(|line| parse_game(line, &mut map)); + + let min_cube_sum: usize = find_min_cubes(&map) + .iter() + .map(|(_, set)| cube_power(set)) + .sum(); + + println!("Part 2 Sum of min cubes: {}", min_cube_sum); +} + +fn main() { + part_one(); + part_two(); +} + #[cfg(test)] -mod tests {} +mod tests { + use super::*; + + #[test] + fn test_min_cubes() { + let games: CubeMap = HashMap::from([ + ( + 1, + Vec::from([ + CubeSet::new(4, 0, 3), + CubeSet::new(1, 2, 0), + CubeSet::new(0, 2, 6), + ]), + ), + ( + 2, + Vec::from([ + CubeSet::new(0, 2, 1), + CubeSet::new(1, 3, 4), + CubeSet::new(0, 1, 1), + ]), + ), + ( + 3, + Vec::from([ + CubeSet::new(20, 8, 6), + CubeSet::new(4, 13, 5), + CubeSet::new(1, 5, 0), + ]), + ), + ( + 4, + Vec::from([ + CubeSet::new(3, 1, 6), + CubeSet::new(6, 3, 0), + CubeSet::new(14, 3, 15), + ]), + ), + (5, Vec::from([CubeSet::new(6, 3, 1), CubeSet::new(1, 2, 2)])), + ]); + + let expected: MinCubeMap = HashMap::from([ + (1, CubeSet::new(4, 2, 6)), + (2, CubeSet::new(1, 3, 4)), + (3, CubeSet::new(20, 13, 6)), + (4, CubeSet::new(14, 3, 15)), + (5, CubeSet::new(6, 3, 2)), + ]); + + let actual = find_min_cubes(&games); + + actual.iter().for_each(|(id, min_cubes)| { + assert_eq!( + min_cubes, + expected.get(id).unwrap(), + "Game {} min cubes", + id + ); + }); + } +}