diff --git a/2023/day5/src/main.rs b/2023/day5/src/main.rs index e14ff27..828d1b8 100644 --- a/2023/day5/src/main.rs +++ b/2023/day5/src/main.rs @@ -1,9 +1,8 @@ use std::collections::{HashMap, VecDeque}; use std::ops::Range; -use crate::DataType::Soil; +use DataType::*; const FILE_STR: &'static str = include_str!("input.txt"); -const EXAMPLE_FILE_STR: &'static str = include_str!("example-input.txt"); #[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)] enum DataType { @@ -20,14 +19,14 @@ enum DataType { impl DataType { fn try_from(s: &str) -> Option { match s { - "seed" => Some(Self::Seed), - "soil" => Some(Self::Soil), - "fertilizer" => Some(Self::Fertilizer), - "water" => Some(Self::Water), - "light" => Some(Self::Light), - "temperature" => Some(Self::Temperature), - "humidity" => Some(Self::Humidity), - "location" => Some(Self::Location), + "seed" => Some(Seed), + "soil" => Some(Soil), + "fertilizer" => Some(Fertilizer), + "water" => Some(Water), + "light" => Some(Light), + "temperature" => Some(Temperature), + "humidity" => Some(Humidity), + "location" => Some(Location), _ => None, } } @@ -50,32 +49,16 @@ impl DataMap { } } - fn get_dest_idx(&self, src_value: u64) -> u64 { - let src_index = src_value.checked_sub(self.to_range.start); - let dest_index = if let Some(idx) = src_index { - self.from_range.start.checked_add(idx) - } else { - Some(src_value) - }; - - match dest_index { - Some(n) => n, - None => src_value, + fn get_dest_idx(&self, src_value: u64) -> Option { + if let Some(idx) = src_value.checked_sub(self.to_range.start) { + if let Some(new_idx) = self.from_range.start.checked_add(idx) { + if new_idx < self.from_range.end { + return Some(new_idx); + } + } } - } - fn get_src_idx(&self, dest_value: u64) -> u64 { - let dest_index = dest_value.checked_sub(self.from_range.start); - let src_index = if let Some(idx) = dest_index { - self.to_range.start.checked_add(idx) - } else { - Some(dest_value) - }; - - match src_index { - Some(n) => n, - None => dest_value, - } + None } } @@ -115,6 +98,7 @@ impl Almanac { let (from, to) = (types[0], types[1]); let mappings: Vec = lines .into_iter() + .filter(|l| l.len() > 0) .map(|line| { line.split_whitespace() .map(|s| s.trim()) @@ -133,8 +117,21 @@ impl Almanac { } fn x_from_y(&self, x: DataType, y: DataType, search: u64) -> u64 { - let maps = self.maps.get(&(y, x)).expect(&format!("Missing mapping from {:?} to {:?}", x, y)); - todo!(); + let maps = self + .maps + .get(&(y, x)) + .expect(&format!("Missing mapping from {:?} to {:?}", x, y)); + let mut mapped_value: Vec> = maps + .into_iter() + .map(|dm| dm.get_dest_idx(search)) + .filter(|r| r.is_some()) + .collect(); + + if mapped_value.is_empty() { + return search; + } + + mapped_value.pop().unwrap().unwrap() } fn soil_from_seed(&self, seed: u64) -> u64 { @@ -142,17 +139,73 @@ impl Almanac { self.x_from_y(Soil, Seed, seed) } + + fn fertilizer_from_soil(&self, soil: u64) -> u64 { + self.x_from_y(Fertilizer, Soil, soil) + } + + fn location_from_seed(&self, seed: u64) -> u64 { + let soil = self.soil_from_seed(seed); + let fert = self.fertilizer_from_soil(soil); + let water = self.x_from_y(Water, Fertilizer, fert); + let light = self.x_from_y(Light, Water, water); + let temp = self.x_from_y(Temperature, Light, light); + let humid = self.x_from_y(Humidity, Temperature, temp); + + self.x_from_y(Location, Humidity, humid) + } + + fn locations_from_seeds(&self) -> HashMap { + self.seeds + .iter() + .map(|s| (*s, self.location_from_seed(*s))) + .collect() + } + + fn lowest_seed_location(&self) -> u64 { + self.locations_from_seeds() + .iter() + .map(|(_, l)| *l) + .min() + .unwrap() + } +} + +fn part_one() { + let almanac = Almanac::parse(FILE_STR); + println!("Part 1: Lowest seed location: {}", almanac.lowest_seed_location()); } fn main() { - let almanac = Almanac::parse(EXAMPLE_FILE_STR); - let soil = almanac.soil_from_seed(79); + part_one(); } #[cfg(test)] mod tests { + use crate::Almanac; + use std::collections::HashMap; + const EXAMPLE_FILE_STR: &'static str = include_str!("example-input.txt"); #[test] - fn test_parse() {} + fn test_location_from_seed() { + let almanac = Almanac::parse(EXAMPLE_FILE_STR); + assert_eq!(82, almanac.location_from_seed(79)); + assert_eq!(43, almanac.location_from_seed(14)); + assert_eq!(86, almanac.location_from_seed(55)); + assert_eq!(35, almanac.location_from_seed(13)); + } + + #[test] + fn test_locations_from_seeds() { + let almanac = Almanac::parse(EXAMPLE_FILE_STR); + let expected = HashMap::from([(79, 82), (14, 43), (55, 86), (13, 35)]); + assert_eq!(expected, almanac.locations_from_seeds()); + } + + #[test] + fn test_lowest_seed_location() { + let almanac = Almanac::parse(EXAMPLE_FILE_STR); + assert_eq!(35, almanac.lowest_seed_location()); + } }