From 6b7afc5a93ebe41c65a127282c4aeb228b45576e Mon Sep 17 00:00:00 2001 From: Pascal Phelipot Date: Wed, 6 Dec 2023 23:53:06 +0100 Subject: [PATCH] Part 1 day 5 --- src/day5/mod.rs | 152 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 152 insertions(+) create mode 100644 src/day5/mod.rs diff --git a/src/day5/mod.rs b/src/day5/mod.rs new file mode 100644 index 0000000..5b598d4 --- /dev/null +++ b/src/day5/mod.rs @@ -0,0 +1,152 @@ +use std::collections::HashMap; +use regex::Regex; + +use log::{debug, info}; + +use super::utils::Part; + +#[derive(Debug)] +struct Range { + range_start: u64, + src_range_start: 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 ) + } + None + } +} +#[derive(Default)] +struct Map { + start_domain: String, + target_domain: String, + ranges: Vec +} +impl Map { + fn new() -> Self { + Map { ..Default::default() } + } + + fn map(&self, n: u64) -> u64 { + for range in &self.ranges { + if let Some(value) = range.map(n) { + return value + } + } + n + } +} + +#[derive(Default)] +struct Dataset { + seeds: Vec, + maps: HashMap +} + +impl Dataset { + fn new() -> Self { + Dataset { ..Default::default() } + } +} + +pub fn solve(lines: Vec, part: Part) -> u64 { + 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(); + debug!("Seeds : {:?}", dataset.seeds); + + 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); + 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(); + debug!("new range: {:?}", components); + 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); + + + info!("Loaded {} mapping categories", dataset.maps.len()); + for (src, map) in &dataset.maps { + 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); + } + + min_location + }, + Part::Two => todo!() + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_range_mapping() { + let mut map = Map::new(); + map.start_domain = "seed".to_owned(); + map.target_domain = "soil".to_owned(); + + map.ranges.push(Range { + range_start: 50, + src_range_start: 98, + length: 2 + }); + + map.ranges.push(Range { + range_start: 52, + src_range_start: 50, + 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