diff --git a/input/02-test b/input/02-test new file mode 100644 index 0000000..1cd7d33 --- /dev/null +++ b/input/02-test @@ -0,0 +1,5 @@ +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 \ No newline at end of file diff --git a/src/bin/02.rs b/src/bin/02.rs new file mode 100644 index 0000000..fc5c8d0 --- /dev/null +++ b/src/bin/02.rs @@ -0,0 +1,93 @@ +const INPUT: &str = include_str!("../../input/02"); +const TEST_INPUT: &str = include_str!("../../input/02-test"); + +fn main() { + assert_eq!(part1(TEST_INPUT), 8); + println!("Part 1: {}", part1(INPUT)); + + assert_eq!(part2(TEST_INPUT), 2286); + println!("Part 2: {}", part2(INPUT)); +} + +fn part1(input: &str) -> u32 { + parse(input) + .filter(|game| game.is_possible()) + .map(|game| game.id) + .sum() +} + +fn part2(input: &str) -> u32 { + parse(input) + .map(|game| game.max_set()) + .map(|set| set.power()) + .sum() +} + +struct Game { + id: u32, + revealed: Vec, +} + +impl Game { + fn is_possible(&self) -> bool { + self.revealed + .iter() + .all(|set| set.r <= 12 && set.g <= 13 && set.b <= 14) + } + + fn max_set(&self) -> Set { + self.revealed.iter().fold(Set::default(), |a, b| Set { + r: a.r.max(b.r), + g: a.g.max(b.g), + b: a.b.max(b.b), + }) + } + + fn parse(line: &str) -> Self { + let (game, revealed) = line.split_once(": ").unwrap(); + let id = game + .split_ascii_whitespace() + .last() + .unwrap() + .parse() + .unwrap(); + let revealed = revealed.split("; ").map(Set::parse).collect(); + + Self { id, revealed } + } +} + +#[derive(Default)] +struct Set { + r: u32, + g: u32, + b: u32, +} + +impl Set { + fn power(&self) -> u32 { + self.r * self.g * self.b + } + + fn parse(s: &str) -> Self { + let colors = s.split(", "); + let mut result = Self::default(); + + for color in colors { + let (count, color) = color.split_once(" ").unwrap(); + let count = count.parse().unwrap(); + match color { + "red" => result.r = count, + "green" => result.g = count, + "blue" => result.b = count, + other => panic!("unknown color: {other}"), + } + } + + result + } +} + +fn parse(input: &str) -> impl Iterator + '_ { + input.lines().map(Game::parse) +}