diff --git a/Cargo.lock b/Cargo.lock index 92a3092..08072f6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -33,3 +33,11 @@ version = "0.1.0" [[package]] name = "d04t2" version = "0.1.0" + +[[package]] +name = "d05t1" +version = "0.1.0" + +[[package]] +name = "d05t2" +version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index fe841b6..c4fe8c6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,4 +10,6 @@ members = [ "d03t2", "d04t1", "d04t2", + "d05t1", + "d05t2", ] diff --git a/d05t1/Cargo.toml b/d05t1/Cargo.toml new file mode 100644 index 0000000..c5d2306 --- /dev/null +++ b/d05t1/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "d05t1" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/d05t1/demo_input.txt b/d05t1/demo_input.txt new file mode 100644 index 0000000..bd902a4 --- /dev/null +++ b/d05t1/demo_input.txt @@ -0,0 +1,33 @@ +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 \ No newline at end of file diff --git a/d05t1/src/main.rs b/d05t1/src/main.rs new file mode 100644 index 0000000..f96e0c7 --- /dev/null +++ b/d05t1/src/main.rs @@ -0,0 +1,123 @@ +fn main() { + let input = include_str!("../input.txt"); + println!("d05t1: {}", d05t1(input)); +} + +pub fn d05t1(input: &str) -> usize { + let mut groups = input.split("\n\n"); + let seeds = groups.next().unwrap().replace("seeds: ", ""); + let seeds = seeds + .split_whitespace() + .map(str::parse::) + .map(Result::unwrap) + .collect::>(); + let seed_to_spoil_map = parse_maps(groups.next().unwrap(), "seed-to-soil map:"); + let soil_to_fertilizer_map = parse_maps(groups.next().unwrap(), "soil-to-fertilizer map:"); + let fertilizer_to_water_map = parse_maps(groups.next().unwrap(), "fertilizer-to-water map:"); + let water_to_light_map = parse_maps(groups.next().unwrap(), "water-to-light map:"); + let light_to_temperature_map = parse_maps(groups.next().unwrap(), "light-to-temperature map:"); + let temperature_to_humidity_map = + parse_maps(groups.next().unwrap(), "temperature-to-humidity map:"); + let humidity_to_location_map = parse_maps(groups.next().unwrap(), "humidity-to-location map:"); + assert!(groups.next().is_none()); + let soils = seeds.solve(&seed_to_spoil_map); + let fertilizers = soils.solve(&soil_to_fertilizer_map); + let waters = fertilizers.solve(&fertilizer_to_water_map); + let lights = waters.solve(&water_to_light_map); + let temperatures = lights.solve(&light_to_temperature_map); + let humidities = temperatures.solve(&temperature_to_humidity_map); + let locations = humidities.solve(&humidity_to_location_map); + locations.into_iter().min().unwrap() +} + +#[derive(Debug)] +struct TranslationMap { + dest_range_start: usize, + source_range_start: usize, + range_length: usize, +} + +trait SolveLayer { + fn solve(&self, translation_maps: &Vec) -> Self; +} + +impl SolveLayer for Vec { + fn solve(&self, translation_maps: &Vec) -> Self { + self.into_iter() + .map(|l| translation_maps.translate(*l)) + .collect::>() + } +} + +trait Translate { + fn translate(&self, input: usize) -> usize; +} + +trait Fold { + fn fold(self) -> U; +} + +impl Fold> for Option> { + fn fold(self) -> Option { + if let Some(o) = self { + o + } else { + None + } + } +} +impl Fold> for Vec> { + fn fold(self) -> Vec { + let mut ret = Vec::new(); + for inner in self { + for value in inner { + ret.push(value) + } + } + ret + } +} +impl Translate for Vec { + fn translate(&self, input: usize) -> usize { + self.iter() + .map(|m| m.translate(input)) + .filter(Option::is_some) + .map(Option::unwrap) + .next() + .unwrap_or(input) + } +} +impl TranslationMap { + fn translate(&self, input: usize) -> Option { + if input >= self.source_range_start && input < self.source_range_start + self.range_length { + Some(self.dest_range_start + (input - self.source_range_start)) + } else { + None + } + } +} + +fn parse_maps(input: &str, title: &str) -> Vec { + let mut lines = input.lines(); + assert_eq!(lines.next().unwrap(), title); + lines.map(parse_map).collect::>() +} + +fn parse_map(input: &str) -> TranslationMap { + let mut elems = input.split_whitespace(); + TranslationMap { + dest_range_start: elems.next().unwrap().parse().unwrap(), + source_range_start: elems.next().unwrap().parse().unwrap(), + range_length: elems.next().unwrap().parse().unwrap(), + } +} + +#[cfg(test)] +mod tests { + use super::*; + #[test] + fn test_d05t1() { + let input = include_str!("../demo_input.txt"); + assert_eq!(d05t1(input), 35); + } +} diff --git a/d05t2/Cargo.toml b/d05t2/Cargo.toml new file mode 100644 index 0000000..06cdf8a --- /dev/null +++ b/d05t2/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "d05t2" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/d05t2/demo_input.txt b/d05t2/demo_input.txt new file mode 100644 index 0000000..7db35f0 --- /dev/null +++ b/d05t2/demo_input.txt @@ -0,0 +1,33 @@ +seeds: 82 1 + +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 \ No newline at end of file diff --git a/d05t2/src/main.rs b/d05t2/src/main.rs new file mode 100644 index 0000000..b8eb256 --- /dev/null +++ b/d05t2/src/main.rs @@ -0,0 +1,97 @@ +fn main() { + let input = include_str!("../input.txt"); + println!("d05t2: {}", d05t2(input)); +} + +pub fn d05t2(input: &str) -> usize { + let mut groups = input.split("\n\n"); + let seeds = groups.next().unwrap().replace("seeds: ", ""); + let seeds = seeds + .split_whitespace() + .map(str::parse::) + .map(Result::unwrap) + .collect::>(); + let seeds = seeds + .chunks(2) + .map(|chunk| { + let start = chunk[0]; + let range = chunk[1]; + (start..(start + range)).collect::>() + }) + .flatten(); + let seed_to_spoil_map = parse_maps(groups.next().unwrap(), "seed-to-soil map:"); + let soil_to_fertilizer_map = parse_maps(groups.next().unwrap(), "soil-to-fertilizer map:"); + let fertilizer_to_water_map = parse_maps(groups.next().unwrap(), "fertilizer-to-water map:"); + let water_to_light_map = parse_maps(groups.next().unwrap(), "water-to-light map:"); + let light_to_temperature_map = parse_maps(groups.next().unwrap(), "light-to-temperature map:"); + let temperature_to_humidity_map = + parse_maps(groups.next().unwrap(), "temperature-to-humidity map:"); + let humidity_to_location_map = parse_maps(groups.next().unwrap(), "humidity-to-location map:"); + assert!(groups.next().is_none()); + seeds + .map(|s| seed_to_spoil_map.translate(s)) + .map(|s| soil_to_fertilizer_map.translate(s)) + .map(|f| fertilizer_to_water_map.translate(f)) + .map(|w| water_to_light_map.translate(w)) + .map(|l| light_to_temperature_map.translate(l)) + .map(|t| temperature_to_humidity_map.translate(t)) + .map(|h| humidity_to_location_map.translate(h)) + .min() + .unwrap() +} + +#[derive(Debug)] +struct TranslationMap { + dest_range_start: usize, + source_range_start: usize, + range_length: usize, +} + +trait Translate { + fn translate(&self, input: usize) -> usize; +} + +impl Translate for Vec { + fn translate(&self, input: usize) -> usize { + self.iter() + .map(|m| m.translate(input)) + .filter(Option::is_some) + .map(Option::unwrap) + .next() + .unwrap_or(input) + } +} +impl TranslationMap { + fn translate(&self, input: usize) -> Option { + if input >= self.source_range_start && input < self.source_range_start + self.range_length { + Some(self.dest_range_start + (input - self.source_range_start)) + } else { + None + } + } +} + +fn parse_maps(input: &str, title: &str) -> Vec { + let mut lines = input.lines(); + assert_eq!(lines.next().unwrap(), title); + lines.map(parse_map).collect::>() +} + +fn parse_map(input: &str) -> TranslationMap { + let mut elems = input.split_whitespace(); + TranslationMap { + dest_range_start: elems.next().unwrap().parse().unwrap(), + source_range_start: elems.next().unwrap().parse().unwrap(), + range_length: elems.next().unwrap().parse().unwrap(), + } +} + +#[cfg(test)] +mod tests { + use super::*; + #[test] + fn test_d05t2() { + let input = include_str!("../demo_input.txt"); + assert_eq!(d05t2(input), 46); + } +}