AOC_2023/src/day2/mod.rs

166 lines
4.4 KiB
Rust

use log::debug;
#[derive(Default, Debug)]
struct Set {
red: u32,
green: u32,
blue: u32,
}
#[derive(Debug)]
struct Game {
id: u32,
sets: Vec<Set>,
}
impl Game {
fn get_max(&self) -> Set {
let mut max_red: u32 = 0;
let mut max_green: u32 = 0;
let mut max_blue: u32 = 0;
self.sets.iter().for_each(|set: &Set| {
if max_red < set.red {
max_red = set.red;
}
if max_green < set.green {
max_green = set.green;
}
if max_blue < set.blue {
max_blue = set.blue;
}
});
Set {
red: max_red,
green: max_green,
blue: max_blue,
}
}
}
impl From<String> for Game {
fn from(line: String) -> Self {
let game_string: (&str, &str) = line.split_once(':').unwrap();
let game_number: String = game_string.0.chars().filter(|c| c.is_numeric()).collect();
let sets: Vec<Set> = game_string
.1
.split(';')
.map(|set: &str| {
let explodes: Vec<&str> = set.split(' ').collect();
let mut number: u32 = 0;
let mut green: u32 = 0;
let mut blue: u32 = 0;
let mut red: u32 = 0;
for part in explodes {
if part.is_empty() {
continue;
}
if part.parse::<u32>().is_ok() {
number = part.parse::<u32>().unwrap();
continue;
}
let color = part.trim().replace(',', "");
match color.as_str() {
"green" => {
green = number;
}
"red" => {
red = number;
}
"blue" => {
blue = number;
}
_ => debug!("Part is wrong: {}", part),
}
}
let set_obj: Set = Set { blue, green, red };
debug!("String Set: {} to {:?}", set, set_obj);
set_obj
})
.collect();
Game {
id: game_number.parse::<u32>().unwrap(),
sets,
}
}
}
fn part2(input: String) -> u32 {
let games: Vec<Game> = input
.lines()
.map(|line: &str| -> Game { Game::from(line.to_owned()) })
.collect();
games
.into_iter()
.map(|game: Game| game.get_max())
.map(|set| set.blue * set.green * set.red)
.sum()
}
fn part1(input: String) -> u32 {
let games: Vec<Game> = input
.lines()
.map(|line: &str| -> Game { Game::from(line.to_owned()) })
.collect();
games
.into_iter()
.filter(|game: &Game| {
let filterd: Vec<&Set> = game
.sets
.iter()
.filter(|set| !(set.green <= 13 && set.red <= 12 && set.blue <= 14))
.collect();
filterd.is_empty()
})
.map(|game| {
debug!("Valid Game: {:?}", game);
game.id
})
.sum()
}
pub fn day2(input: String) {
let input_clone = input.clone();
let result1 = part1(input);
let result2 = part2(input_clone);
println!("Result day 2: [{}] [{}]", result1, result2);
}
#[cfg(test)]
mod day2_test {
use crate::day2::{part1, part2};
#[test]
fn test1() {
let input = "Game 1: 3 blue, 4 red; 1 red, 2 green, 6 blue; 2 green
Game 2: 1 blue, 2 green; 3 green, 4 blue, 1 red; 1 green, 1 blue
Game 3: 8 green, 6 blue, 20 red; 5 blue, 4 red, 13 green; 5 green, 1 red
Game 4: 1 green, 3 red, 6 blue; 3 green, 6 red; 3 green, 15 blue, 14 red
Game 5: 6 red, 1 blue, 3 green; 2 blue, 1 red, 2 green";
assert_eq!(8, part1(input.to_string()));
}
#[test]
fn test2() {
let input = "Game 1: 3 blue, 4 red; 1 red, 2 green, 6 blue; 2 green
Game 2: 1 blue, 2 green; 3 green, 4 blue, 1 red; 1 green, 1 blue
Game 3: 8 green, 6 blue, 20 red; 5 blue, 4 red, 13 green; 5 green, 1 red
Game 4: 1 green, 3 red, 6 blue; 3 green, 6 red; 3 green, 15 blue, 14 red
Game 5: 6 red, 1 blue, 3 green; 2 blue, 1 red, 2 green";
assert_eq!(2286, part2(input.to_string()));
}
}