diff --git a/src/day4/mod.rs b/src/day4/mod.rs index 7080942..2157f68 100644 --- a/src/day4/mod.rs +++ b/src/day4/mod.rs @@ -6,14 +6,14 @@ use crate::utils::Day; pub struct Day4 { pub input: String, pub acc: usize, - pub cards: HashMap:: /* (won card indexes) */> + 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()) } @@ -24,7 +24,7 @@ impl Day4 { 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::>(); @@ -37,7 +37,10 @@ impl Day for Day4 { } if winning_numbers.len() != 0 { - sum += winning_numbers.iter().skip(1).fold(1usize, |acc, _| acc * 2); + sum += winning_numbers + .iter() + .skip(1) + .fold(1usize, |acc, _| acc * 2); } } @@ -57,7 +60,14 @@ impl Day for Day4 { } } - self.cards.insert(i + 1, winning_numbers.into_iter().enumerate().map(|(j, _)| (i + 1) + (j + 1)).collect()); + 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::>()); @@ -98,9 +108,9 @@ 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() + acc: 0usize, + cards: HashMap::new() } .solve(2)); } -} \ No newline at end of file +} diff --git a/src/day5/mod.rs b/src/day5/mod.rs new file mode 100644 index 0000000..72a0a1a --- /dev/null +++ b/src/day5/mod.rs @@ -0,0 +1,233 @@ +use std::collections::HashMap; + +use crate::utils::Day; + +#[derive(Debug)] +pub struct Day5 { + pub input: String, +} + +impl Day for Day5 { + fn part1(&mut self) -> String { + let groups = self.input.split("\n\n").skip(1).map(|g| { + let mut lines = g.lines(); + (lines.next().unwrap(), lines.collect::>()) + }); + + let seeds = self + .input + .lines() + .next() + .unwrap() + .split_once(": ") + .unwrap() + .1 + .split_whitespace() + .map(|s| s.parse::().unwrap()); + let groups = groups + .map(|(name, list)| { + ( + name.split_once(' ').unwrap().0.split_once("-to-").unwrap(), + list.into_iter().map(|line| { + let nums = line.split_whitespace() + .map(|n| n.parse::().unwrap()) + .collect::>(); + (nums[0], nums[1], nums[2]) + }).collect::>(), + ) + }) + .map(|((from, to), mappings)| ( + from, + ( + to, + mappings + ) + )) + .collect::)>>(); + + let mut locations = Vec::::new(); + + for seed in seeds { + let (mut category, mut value) = ("seed", seed); + while category != "location" { + let (new_category, mappings) = groups.get(category).unwrap(); + category = new_category; + + for (destination_start, source_start, length) in mappings { + if (source_start..&(source_start + length)).contains(&&value) { + let delta = *source_start as isize - *destination_start as isize; + value = (value as isize - delta) as usize; + break; + } + } + } + + locations.push(value) + } + + locations.into_iter().min().unwrap().to_string() + } + + /// Yes my solution was to brute force it + /// Yes it worked + /// Yes it only took 13m and 31s to solve + /// No I will not elaborate on why I felt the need to do it this way + /// Yes I should probably solve it correctly at some point + fn part2(&mut self) -> String { + let groups = self.input.split("\n\n").skip(1).map(|g| { + let mut lines = g.lines(); + (lines.next().unwrap(), lines.collect::>()) + }); + + let seeds = self + .input + .lines() + .next() + .unwrap() + .split_once(": ") + .unwrap() + .1 + .split_whitespace() + .map(|s| s.parse::().unwrap()) + .collect::>(); + let seeds = seeds + .as_slice() + .chunks(2); + + let groups = groups + .map(|(name, list)| { + ( + name.split_once(' ').unwrap().0.split_once("-to-").unwrap(), + list.into_iter().map(|line| { + let nums = line.split_whitespace() + .map(|n| n.parse::().unwrap()) + .collect::>(); + (nums[0], nums[1], nums[2]) + }).collect::>(), + ) + }) + .map(|((from, to), mappings)| ( + from, + ( + to, + mappings + ) + )) + .collect::)>>(); + + let mut location = 100000000usize; + let seedslen = seeds.len(); + + for (i, chunk) in seeds.enumerate() { + let (initial, range) = (chunk[0], chunk[1]); + for (j, seed) in (initial..(initial + range)).enumerate() { + if j % 1000 == 0 { + println!("Chunk {}/{}, Seed {}/{} ({:.2}%)", i, seedslen, j, range, j as f64 / range as f64 * 100.0); + } + let (mut category, mut value) = ("seed", seed); + while category != "location" { + let (new_category, mappings) = groups.get(category).unwrap(); + category = new_category; + + for (destination_start, source_start, length) in mappings { + if (source_start..&(source_start + length)).contains(&&value) { + let delta = *source_start as isize - *destination_start as isize; + value = (value as isize - delta) as usize; + break; + } + } + } + + if location > value { location = value } + } + } + + location.to_string() + } +} + + +#[cfg(test)] +mod tests { + use crate::{day5::Day5, utils::Day}; + + #[test] + fn passes_example_1() { + dbg!(Day5 { + input: r#"seeds: 79 14 55 13 + +seed-to-soil map: +50 98 2 +52 50 48 + +soil-to-fertilizer map: +0 15 37 +37 52 2 +39 0 15 + +fertilizer-to-water map: +49 53 8 +0 11 42 +42 0 7 +57 7 4 + +water-to-light map: +88 18 7 +18 25 70 + +light-to-temperature map: +45 77 23 +81 45 19 +68 64 13 + +temperature-to-humidity map: +0 69 1 +1 0 69 + +humidity-to-location map: +60 56 37 +56 93 4"#.to_string(), + } + .solve(1)); + } + + #[test] + fn passes_example_2() { + dbg!(Day5 { + input: r#"seeds: 79 14 55 13 + +seed-to-soil map: +50 98 2 +52 50 48 + +soil-to-fertilizer map: +0 15 37 +37 52 2 +39 0 15 + +fertilizer-to-water map: +49 53 8 +0 11 42 +42 0 7 +57 7 4 + +water-to-light map: +88 18 7 +18 25 70 + +light-to-temperature map: +45 77 23 +81 45 19 +68 64 13 + +temperature-to-humidity map: +0 69 1 +1 0 69 + +humidity-to-location map: +60 56 37 +56 93 4"#.to_string(), + } + .solve(2)); + } +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 209894e..6daa101 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,12 +6,13 @@ use std::{ use clap::{Parser, Subcommand}; -use crate::{day1::Day1, day2::Day2, day3::Day3, day4::Day4, utils::Day}; +use crate::{day1::Day1, day2::Day2, day3::Day3, day4::Day4, day5::Day5, utils::Day}; pub mod day1; pub mod day2; pub mod day3; pub mod day4; +pub mod day5; pub mod fetcher; pub mod utils; @@ -91,6 +92,7 @@ async fn main() { acc: 0usize, cards: HashMap::new(), }), + 5 => Box::new(Day5 { input: response }), _ => panic!("Invalid day #"), }; let start = std::time::Instant::now(); @@ -140,6 +142,7 @@ async fn main() { acc: 0usize, cards: HashMap::new(), }), + 5 => Box::new(Day5 { input: response }), _ => panic!("Invalid day #"), }; let mut timings = Vec::::new();