From fba8779f72eda37a75992c47420f43fcb1ad4e80 Mon Sep 17 00:00:00 2001 From: Ty Date: Mon, 4 Dec 2023 06:42:50 -0700 Subject: [PATCH] Day 4 --- src/day4/mod.rs | 106 ++++++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 22 ++++++++-- 2 files changed, 124 insertions(+), 4 deletions(-) create mode 100644 src/day4/mod.rs diff --git a/src/day4/mod.rs b/src/day4/mod.rs new file mode 100644 index 0000000..7080942 --- /dev/null +++ b/src/day4/mod.rs @@ -0,0 +1,106 @@ +use std::collections::HashMap; + +use crate::utils::Day; + +#[derive(Debug)] +pub struct Day4 { + pub input: String, + pub acc: usize, + pub cards: HashMap:: /* (won card indexes) */> +} + +impl Day4 { + fn recurse(&mut self, cards: &Vec) { + for card in cards { + self.acc += 1; + + if let Some(won_cards) = self.cards.get(card) { + self.recurse(&won_cards.clone()) + } + } + } +} + +impl Day for Day4 { + fn part1(&mut self) -> String { + let mut sum = 0usize; + + for line in self.input.lines() { + let (winning, numbers) = line.split_once(": ").unwrap().1.split_once(" | ").unwrap(); + let winning = winning.split_whitespace().collect::>(); + + let mut winning_numbers = Vec::<&str>::new(); + for number in numbers.split_whitespace() { + if winning.contains(&number) && !winning_numbers.contains(&number) { + winning_numbers.push(number); + } + } + + if winning_numbers.len() != 0 { + sum += winning_numbers.iter().skip(1).fold(1usize, |acc, _| acc * 2); + } + } + + sum.to_string() + } + + fn part2(&mut self) -> String { + self.cards = HashMap:: /* won card indexes */>::new(); + for (i, line) in self.input.lines().enumerate() { + let (winning, numbers) = line.split_once(": ").unwrap().1.split_once(" | ").unwrap(); + let winning = winning.split_whitespace().collect::>(); + + let mut winning_numbers = Vec::<&str>::new(); + for number in numbers.split_whitespace() { + if winning.contains(&number) && !winning_numbers.contains(&number) { + winning_numbers.push(number); + } + } + + self.cards.insert(i + 1, winning_numbers.into_iter().enumerate().map(|(j, _)| (i + 1) + (j + 1)).collect()); + } + + self.recurse(&self.cards.keys().map(|e| *e).collect::>()); + + self.acc.to_string() + } +} + +#[cfg(test)] +mod tests { + use std::collections::HashMap; + + use crate::{day4::Day4, utils::Day}; + + #[test] + fn passes_example_1() { + dbg!(Day4 { + input: r#"Card 1: 41 48 83 86 17 | 83 86 6 31 17 9 48 53 +Card 2: 13 32 20 16 61 | 61 30 68 82 17 32 24 19 +Card 3: 1 21 53 59 44 | 69 82 63 72 16 21 14 1 +Card 4: 41 92 73 84 69 | 59 84 76 51 58 5 54 83 +Card 5: 87 83 26 28 32 | 88 30 70 12 93 22 82 36 +Card 6: 31 18 13 56 72 | 74 77 10 23 35 67 36 11"# + .to_string(), + acc: 0usize, + cards: HashMap::new() + } + .solve(1)); + } + + #[test] + fn passes_example_2() { + dbg!(Day4 { + input: r#"Card 1: 41 48 83 86 17 | 83 86 6 31 17 9 48 53 +Card 2: 13 32 20 16 61 | 61 30 68 82 17 32 24 19 +Card 3: 1 21 53 59 44 | 69 82 63 72 16 21 14 1 +Card 4: 41 92 73 84 69 | 59 84 76 51 58 5 54 83 +Card 5: 87 83 26 28 32 | 88 30 70 12 93 22 82 36 +Card 6: 31 18 13 56 72 | 74 77 10 23 35 67 36 11"# + .to_string(), + acc: 0usize, + cards: HashMap::new() + } + .solve(2)); + } +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 706d6f6..e319fa4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,15 +1,16 @@ use std::{ io::Write, - time::{Duration, Instant}, + time::{Duration, Instant}, collections::HashMap, }; use clap::{Parser, Subcommand}; -use crate::{day1::Day1, day2::Day2, day3::Day3, utils::Day}; +use crate::{day1::Day1, day2::Day2, day3::Day3, utils::Day, day4::Day4}; pub mod day1; pub mod day2; pub mod day3; +pub mod day4; pub mod utils; #[derive(Parser)] @@ -76,13 +77,25 @@ async fn main() { games: vec![], }), 3 => Box::new(Day3 { input: response }), + 4 => Box::new(Day4 { input: response, acc: 0usize, cards: HashMap::new() }), _ => panic!("Invalid day #"), }; let start = std::time::Instant::now(); let result = day.solve(part); let end = std::time::Instant::now(); println!("Solution: {result}"); - println!("Solved in {}ns", (end - start).as_nanos() as f64 / 1000.0); + + let timing = (end - start).as_nanos(); + let (timing, timing_units) = if timing >= 1000000000 { + (timing as f64 / 1000000000.0, "s") + } else if timing >= 1000000 { + (timing as f64 / 1000000.0, "ms") + } else if timing >= 1000 { + (timing as f64 / 1000.0, "µs") + } else { + (timing as f64, "ns") + }; + println!("Solved in {timing}{timing_units}"); } Subcommands::Benchmark { day, @@ -109,6 +122,7 @@ async fn main() { games: vec![], }), 3 => Box::new(Day3 { input: response }), + 4 => Box::new(Day4 { input: response, acc: 0usize, cards: HashMap::new() }), _ => panic!("Invalid day #"), }; let mut timings = Vec::::new(); @@ -121,7 +135,7 @@ async fn main() { day.solve(part); let end = Instant::now(); timings.push(end - start); - + print!("\r{:.2}%", (i as f32 / n as f32) * 100.0); let _ = std::io::stdout().flush(); }