diff --git a/src/day5/mod.rs b/src/day5/mod.rs index 5b598d4..27a2033 100644 --- a/src/day5/mod.rs +++ b/src/day5/mod.rs @@ -1,7 +1,7 @@ -use std::collections::HashMap; use regex::Regex; +use std::collections::HashMap; -use log::{debug, info}; +use log::{debug, info, trace}; use super::utils::Part; @@ -9,14 +9,19 @@ use super::utils::Part; struct Range { range_start: u64, src_range_start: u64, - length: u64 + length: u64, } impl Range { fn map(&self, n: u64) -> Option { - if (self.src_range_start..(self.src_range_start+self.length)).contains(&n) { - debug!("matching range {} -> {} [{:?}]", n, self.range_start + n - self.src_range_start, self); - return Some(self.range_start + n - self.src_range_start ) + if (self.src_range_start..(self.src_range_start + self.length)).contains(&n) { + trace!( + "matching range {} -> {} [{:?}]", + n, + self.range_start + n - self.src_range_start, + self + ); + return Some(self.range_start + n - self.src_range_start); } None } @@ -25,17 +30,19 @@ impl Range { struct Map { start_domain: String, target_domain: String, - ranges: Vec + ranges: Vec, } impl Map { fn new() -> Self { - Map { ..Default::default() } + Map { + ..Default::default() + } } fn map(&self, n: u64) -> u64 { for range in &self.ranges { if let Some(value) = range.map(n) { - return value + return value; } } n @@ -45,77 +52,103 @@ impl Map { #[derive(Default)] struct Dataset { seeds: Vec, - maps: HashMap + maps: HashMap, } impl Dataset { fn new() -> Self { - Dataset { ..Default::default() } + Dataset { + ..Default::default() + } } } pub fn solve(lines: Vec, part: Part) -> u64 { - let parts : Vec = lines.into_iter() - .filter(|l| !l.is_empty()) - .collect(); + let parts: Vec = lines.into_iter().filter(|l| !l.is_empty()).collect(); let mut dataset = Dataset::new(); debug!("{:?}", parts); let (seeds_line, other_lines) = parts.split_at(1); - dataset.seeds = seeds_line.first().unwrap().split(' ').skip(1).map(|e| e.parse().unwrap()).collect(); + dataset.seeds = seeds_line + .first() + .unwrap() + .split(' ') + .skip(1) + .map(|e| e.parse().unwrap()) + .collect(); debug!("Seeds : {:?}", dataset.seeds); - let mut current_map : Map = Map::new(); + let mut current_map: Map = Map::new(); let regex_map_header = Regex::new(r"^(\w*)-to-(\w*)").unwrap(); for line in other_lines { if let Some(captures) = regex_map_header.captures(line) { if !current_map.ranges.is_empty() { debug!("New mapping detected, saving the last one"); - dataset.maps.insert(current_map.start_domain.to_owned(), current_map); + dataset + .maps + .insert(current_map.start_domain.to_owned(), current_map); current_map = Map::new(); } current_map.start_domain = captures[1].to_owned(); current_map.target_domain = captures[2].to_owned(); - }else{ - let components : [u64; 3] = line.split(' ').map(|e| e.parse().unwrap()).collect::>().try_into().unwrap(); + } else { + let components: [u64; 3] = line + .split(' ') + .map(|e| e.parse().unwrap()) + .collect::>() + .try_into() + .unwrap(); debug!("new range: {:?}", components); - current_map.ranges.push( - Range { - range_start: components[0], - src_range_start: components[1], - length: components[2] - } - ); + current_map.ranges.push(Range { + range_start: components[0], + src_range_start: components[1], + length: components[2], + }); } } - dataset.maps.insert(current_map.start_domain.to_owned(), current_map); - + dataset + .maps + .insert(current_map.start_domain.to_owned(), current_map); info!("Loaded {} mapping categories", dataset.maps.len()); for (src, map) in &dataset.maps { - info!("{} -> {} with {} ranges", src, map.target_domain, map.ranges.len()); + info!( + "{} -> {} with {} ranges", + src, + map.target_domain, + map.ranges.len() + ); } - match part { - Part::One => { - let mut min_location = u64::MAX; - for seed in dataset.seeds { - let mut stage = "seed"; - let mut value = seed; - while let Some(map) = dataset.maps.get(stage) { - debug!("Stage {} -> {}", stage, map.target_domain); - value = map.map(value); - stage = &map.target_domain; - } - min_location = min_location.min(value); - info!("Final stage seed {} -> location {}", seed, value); - } + if let Part::Two = part { + // Convert the seeds to the new format ! + let original_seeds = dataset.seeds; + let mut new_seeds : Vec = Vec::new(); - min_location - }, - Part::Two => todo!() + for chunk in original_seeds.chunks_exact(2) { + let range = chunk[0]..(chunk[0]+chunk[1]); + // FIXME : don't do that it will eat all your memory: new_seeds.append(&mut range.collect::>()); + } + debug!("New seeds: {:?}", new_seeds); + + dataset.seeds = new_seeds; } + + let mut min_location = u64::MAX; + for seed in dataset.seeds { + let mut stage = "seed"; + let mut value = seed; + while let Some(map) = dataset.maps.get(stage) { + debug!("Stage {} -> {}", stage, map.target_domain); + value = map.map(value); + stage = &map.target_domain; + } + min_location = min_location.min(value); + info!("Final stage seed {} -> location {}", seed, value); + } + + min_location } #[cfg(test)] @@ -131,22 +164,20 @@ mod tests { map.ranges.push(Range { range_start: 50, src_range_start: 98, - length: 2 + length: 2, }); map.ranges.push(Range { range_start: 52, src_range_start: 50, - length: 48 + length: 48, }); assert_eq!(map.map(1), 1); assert_eq!(map.map(99), 51); assert_eq!(map.map(51), 53); - } #[test] - fn test_part2(){ - } -} \ No newline at end of file + fn test_part2() {} +} diff --git a/src/main.rs b/src/main.rs index deadbd3..f2c4994 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,6 +4,7 @@ mod day1; mod day2; mod day3; mod day4; +mod day5; mod utils; use log::info; use utils::Part; @@ -17,6 +18,13 @@ fn main() { .format_timestamp(None) .init(); + let data = utils::lines_from_file("./datasets/adventofcode.com_2023_day_5_input.txt").expect("Can't load the data"); + //let data = utils::lines_from_file("./datasets/test.txt").expect("Can't load the data"); + let result = day5::solve(data.clone(), Part::One); + let result2 = day5::solve(data, Part::Two); + + info!("Result part 1: {}", result); + info!("Result part 2: {}", result2); }