summaryrefslogtreecommitdiff
path: root/2023/src/bin/day_2.rs
diff options
context:
space:
mode:
Diffstat (limited to '2023/src/bin/day_2.rs')
-rw-r--r--2023/src/bin/day_2.rs109
1 files changed, 109 insertions, 0 deletions
diff --git a/2023/src/bin/day_2.rs b/2023/src/bin/day_2.rs
new file mode 100644
index 0000000..6f19c1d
--- /dev/null
+++ b/2023/src/bin/day_2.rs
@@ -0,0 +1,109 @@
+use nom::{
+ bytes::complete::tag,
+ character::complete::{alpha1, line_ending, u32 as nom_u32},
+ combinator::map,
+ multi::separated_list1,
+ sequence::tuple,
+ IResult,
+};
+use std::fs;
+
+fn main() -> Result<(), Box<dyn std::error::Error>> {
+ let input = fs::read_to_string("inputs/day_2.txt")?;
+ let parsed = Games::parser(&input).unwrap().1;
+ let max_pull = Pull {
+ red: 12,
+ green: 13,
+ blue: 14,
+ };
+ dbg!(&parsed.valid_game_id_sum(&max_pull));
+ dbg!(&parsed.power_sum());
+
+ Ok(())
+}
+
+#[derive(Debug)]
+struct Games(Vec<Game>);
+
+#[derive(Debug)]
+struct Game {
+ id: u32,
+ pulls: Vec<Pull>,
+}
+
+#[derive(Debug, Default)]
+struct Pull {
+ red: u32,
+ green: u32,
+ blue: u32,
+}
+
+impl Games {
+ fn parser(input: &str) -> IResult<&str, Self> {
+ map(separated_list1(line_ending, Game::parser), Games)(input)
+ }
+
+ fn valid_game_id_sum(&self, max_pull: &Pull) -> u32 {
+ self.0
+ .iter()
+ .filter(|game| game.is_valid(max_pull))
+ .map(|game| game.id)
+ .sum()
+ }
+
+ fn power_sum(&self) -> u32 {
+ self.0.iter().map(|game| game.min_pull().power()).sum()
+ }
+}
+
+impl Game {
+ fn parser(input: &str) -> IResult<&str, Self> {
+ map(
+ tuple((
+ tag("Game "),
+ nom_u32,
+ tag(": "),
+ separated_list1(tag("; "), Pull::parser),
+ )),
+ |(_, id, _, pulls)| Game { id, pulls },
+ )(input)
+ }
+
+ fn is_valid(&self, max_pull: &Pull) -> bool {
+ self.pulls.iter().all(|pull| {
+ pull.red <= max_pull.red && pull.blue <= max_pull.blue && pull.green <= max_pull.green
+ })
+ }
+
+ fn min_pull(&self) -> Pull {
+ Pull {
+ red: self.pulls.iter().map(|p| p.red).max().unwrap_or(0),
+ blue: self.pulls.iter().map(|p| p.blue).max().unwrap_or(0),
+ green: self.pulls.iter().map(|p| p.green).max().unwrap_or(0),
+ }
+ }
+}
+
+impl Pull {
+ fn parser(input: &str) -> IResult<&str, Self> {
+ map(
+ separated_list1(tag(", "), tuple((nom_u32, tag(" "), alpha1))),
+ |stones| {
+ let mut pull = Pull::default();
+ for (quantity, _, colour) in stones {
+ match colour {
+ "red" => pull.red += quantity,
+ "blue" => pull.blue += quantity,
+ "green" => pull.green += quantity,
+ other => panic!("Unexpected colour, {}", other),
+ };
+ }
+ pull
+ },
+ )(input)
+ }
+
+ fn power(&self) -> u32 {
+ self.red * self.blue * self.green
+ }
+}