From d149df9b4e6da83aed6769b839d3ef5712771f3f Mon Sep 17 00:00:00 2001 From: Kevin Caffrey Date: Sat, 2 Dec 2023 13:56:29 -0500 Subject: [PATCH] Day 2 --- README.md | 5 +- data/examples/02.txt | 5 ++ src/bin/02.rs | 135 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 143 insertions(+), 2 deletions(-) create mode 100644 data/examples/02.txt create mode 100644 src/bin/02.rs diff --git a/README.md b/README.md index c79963e..768d2c8 100644 --- a/README.md +++ b/README.md @@ -17,9 +17,10 @@ Solutions for [Advent of Code](https://adventofcode.com/) in [Rust](https://www. | Day | Part 1 | Part 2 | | :---: | :---: | :---: | -| [Day 1](./src/bin/01.rs) | `40.4µs` | `80.7µs` | +| [Day 1](./src/bin/01.rs) | `32.9µs` | `81.1µs` | +| [Day 2](./src/bin/02.rs) | `43.6µs` | `42.6µs` | -**Total: 0.12ms** +**Total: 0.20ms** --- diff --git a/data/examples/02.txt b/data/examples/02.txt new file mode 100644 index 0000000..1cd7d33 --- /dev/null +++ b/data/examples/02.txt @@ -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..7849b2d --- /dev/null +++ b/src/bin/02.rs @@ -0,0 +1,135 @@ +use std::str::FromStr; + +advent_of_code::solution!(2); + +pub fn part_one(input: &str) -> Option { + Some( + input + .lines() + .filter_map(|line| line.parse::().ok()) + .filter(|game| { + game.possible(Colors { + red: 12, + green: 13, + blue: 14, + }) + }) + .map(|game| game.id) + .sum(), + ) +} + +pub fn part_two(input: &str) -> Option { + Some( + input + .lines() + .filter_map(|line| line.parse::().ok()) + .filter_map(|game| { + game.reveals + .iter() + .copied() + .reduce(|acc, reveal| acc.maximum(reveal)) + }) + .map(Colors::power) + .sum(), + ) +} + +#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd)] +struct Colors { + red: u32, + green: u32, + blue: u32, +} + +#[derive(Clone, Debug, Eq, PartialEq)] +struct Game { + id: u32, + reveals: Vec, +} + +impl Game { + pub fn possible(&self, bag: Colors) -> bool { + self.reveals + .iter() + .all(|reveal| reveal.possible_reveal(bag)) + } +} + +impl Colors { + pub fn possible_reveal(self, bag: Colors) -> bool { + self.red <= bag.red && self.green <= bag.green && self.blue <= bag.blue + } + + pub fn maximum(self, other: Self) -> Self { + Self { + red: self.red.max(other.red), + green: self.green.max(other.green), + blue: self.blue.max(other.blue), + } + } + + pub fn power(self) -> u32 { + self.red * self.green * self.blue + } +} + +struct ParseGameErr; + +impl FromStr for Game { + type Err = ParseGameErr; + + fn from_str(s: &str) -> Result { + let (game_id, reveal_str) = s.split_once(':').ok_or(ParseGameErr)?; + if game_id.len() < 6 { + return Err(ParseGameErr); + } + let id = game_id[5..].parse::().map_err(|_| ParseGameErr)?; + let reveals = reveal_str + .trim() + .split(';') + .map(|reveal| reveal.parse::()) + .collect::, ParseGameErr>>()?; + Ok(Self { id, reveals }) + } +} + +impl FromStr for Colors { + type Err = ParseGameErr; + + fn from_str(s: &str) -> Result { + let mut ret = Colors { + red: 0, + green: 0, + blue: 0, + }; + for part in s.split(',') { + let (num_str, color) = part.trim().split_once(' ').ok_or(ParseGameErr)?; + let num = num_str.parse::().map_err(|_| ParseGameErr)?; + match color { + "red" => ret.red += num, + "green" => ret.green += num, + "blue" => ret.blue += num, + _ => return Err(ParseGameErr), + }; + } + Ok(ret) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_part_one() { + let result = part_one(&advent_of_code::template::read_file("examples", DAY)); + assert_eq!(result, Some(8)); + } + + #[test] + fn test_part_two() { + let result = part_two(&advent_of_code::template::read_file("examples", DAY)); + assert_eq!(result, Some(2286)); + } +}