diff --git a/day-05/Cargo.toml b/day-05/Cargo.toml index 328edc6..715c989 100644 --- a/day-05/Cargo.toml +++ b/day-05/Cargo.toml @@ -6,3 +6,4 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +indicatif = { version = "0.17.7", features = ["rayon"] } diff --git a/day-05/src/main.rs b/day-05/src/main.rs index 19fa454..1116857 100644 --- a/day-05/src/main.rs +++ b/day-05/src/main.rs @@ -1,15 +1,17 @@ +use indicatif::ProgressIterator; use std::collections::BTreeMap; +use std::collections::BinaryHeap; -const SOIL: &'static str = "seed-to-soil"; -const FERT: &'static str = "soil-to-fertilizer"; -const WATER: &'static str = "fertilizer-to-water"; -const LIGHT: &'static str = "water-to-light"; -const TEMP: &'static str = "light-to-temperature"; -const HUMIDITY: &'static str = "temperature-to-humidity"; -const LOC: &'static str = "humidity-to-location"; +const SOIL: &str = "seed-to-soil"; +const FERT: &str = "soil-to-fertilizer"; +const WATER: &str = "fertilizer-to-water"; +const LIGHT: &str = "water-to-light"; +const TEMP: &str = "light-to-temperature"; +const HUMIDITY: &str = "temperature-to-humidity"; +const LOC: &str = "humidity-to-location"; fn extract_seeds(input: &str) -> Vec { - let line = input.lines().nth(0).unwrap(); + let line = input.lines().next().unwrap(); let (_, values) = line.split_once(':').unwrap(); values .split_whitespace() @@ -30,8 +32,8 @@ fn extract_map_lines(input: &str, key: &'static str) -> Vec { lines } -fn lookup(input: &str, source: usize, map: &'static str) -> usize { - let map_lines = extract_map_lines(input, map); +fn lookup(maps: &BTreeMap<&'static str, Vec>, source: usize, map: &'static str) -> usize { + let map_lines = maps.get(map).unwrap(); for line in map_lines { let values: Vec = line @@ -52,39 +54,118 @@ fn lookup(input: &str, source: usize, map: &'static str) -> usize { source } -fn lookup_location(input: &str, seed: usize) -> usize { - dbg!(&seed); - let soil = lookup(input, seed, SOIL); - dbg!(&soil); +fn rev_lookup(maps: &BTreeMap<&'static str, Vec>, dest: usize, map: &'static str) -> usize { + let map_lines = maps.get(map).unwrap(); - let fert = lookup(input, soil, FERT); - dbg!(&fert); - let water = lookup(input, fert, WATER); - dbg!(&water); - let light = lookup(input, water, LIGHT); - dbg!(&light); - let temp = lookup(input, light, TEMP); - dbg!(&temp); - let humidity = lookup(input, temp, HUMIDITY); - dbg!(&humidity); - let loc = lookup(input, humidity, LOC); - dbg!(&loc); + for line in map_lines { + let values: Vec = line + .split_whitespace() + .map(|s| s.parse::().unwrap()) + .collect(); - loc + let dest_range_start = values[0]; + let source_range_start = values[1]; + let range_length = values[2]; + + let dest_range_end = dest_range_start + range_length; + if dest >= dest_range_start && dest < dest_range_end { + return source_range_start + (dest - dest_range_start); + } + } + + dest +} + +fn lookup_location(maps: &BTreeMap<&'static str, Vec>, seed: usize) -> usize { + let soil = lookup(maps, seed, SOIL); + + let fert = lookup(maps, soil, FERT); + let water = lookup(maps, fert, WATER); + let light = lookup(maps, water, LIGHT); + let temp = lookup(maps, light, TEMP); + let humidity = lookup(maps, temp, HUMIDITY); + + + lookup(maps, humidity, LOC) +} + +fn rev_lookup_location(maps: &BTreeMap<&'static str, Vec>, loc: usize) -> usize { + let humidity = rev_lookup(maps, loc, LOC); + let temp = rev_lookup(maps, humidity, HUMIDITY); + let light = rev_lookup(maps, temp, TEMP); + let water = rev_lookup(maps, light, LIGHT); + let fert = rev_lookup(maps, water, WATER); + let soil = rev_lookup(maps, fert, FERT); + + + rev_lookup(maps, soil, SOIL) +} + +fn extract_maps(input: &str) -> BTreeMap<&'static str, Vec> { + let mut maps = BTreeMap::new(); + maps.insert(SOIL, extract_map_lines(input, SOIL)); + maps.insert(FERT, extract_map_lines(input, FERT)); + maps.insert(WATER, extract_map_lines(input, WATER)); + maps.insert(LIGHT, extract_map_lines(input, LIGHT)); + maps.insert(TEMP, extract_map_lines(input, TEMP)); + maps.insert(HUMIDITY, extract_map_lines(input, HUMIDITY)); + maps.insert(LOC, extract_map_lines(input, LOC)); + maps } fn part_1(input: &str) -> u32 { + let maps = extract_maps(input); let seeds = extract_seeds(input); let mut locs = Vec::new(); for seed in seeds { - locs.push(lookup_location(input, seed)); + locs.push(lookup_location(&maps, seed)); } - locs.iter().min().unwrap().clone() as u32 + *locs.iter().min().unwrap() as u32 +} + +fn part_2(input: &str) -> usize { + let maps = extract_maps(input); + let seed_pairs = extract_seeds(input); + + let mut ranges = Vec::new(); + for chunk in seed_pairs.chunks(2) { + let start = chunk[0]; + let size = chunk[1]; + ranges.push(start..start + size); + } + + let mut h2l = maps.get(LOC).unwrap().iter().collect::>(); + + let line = h2l.pop().unwrap(); + let values: Vec = line + .split_whitespace() + .map(|s| s.parse::().unwrap()) + .collect(); + + let dest_range_start = values[0]; + let range_length = values[2]; + + let rng = 0..dest_range_start + range_length; + + rng.into_iter() + .progress() + .find(|loc| { + let seed = rev_lookup_location(&maps, *loc); + for range in &ranges { + if range.contains(&seed) { + return true; + } + } + false + }) + .unwrap() + // 0 } fn main() { let input = include_str!("../input.txt"); println!("Part 1: {}", part_1(input)); + println!("Part 2: {}", part_2(input)); } #[cfg(test)] @@ -108,20 +189,33 @@ mod tests { #[test] fn test_lookup_location() { let input = include_str!("../test-input.txt"); + let maps = extract_maps(input); - assert_eq!(lookup_location(input, 79), 82); - assert_eq!(lookup_location(input, 14), 43); - assert_eq!(lookup_location(input, 55), 86); - assert_eq!(lookup_location(input, 13), 35); + assert_eq!(lookup_location(&maps, 79), 82); + assert_eq!(lookup_location(&maps, 14), 43); + assert_eq!(lookup_location(&maps, 55), 86); + assert_eq!(lookup_location(&maps, 13), 35); + } + + #[test] + fn test_reverse_lookup() { + let input = include_str!("../test-input.txt"); + let maps = extract_maps(input); + + assert_eq!(rev_lookup_location(&maps, 82), 79); + assert_eq!(rev_lookup_location(&maps, 43), 14); + assert_eq!(rev_lookup_location(&maps, 86), 55); + assert_eq!(rev_lookup_location(&maps, 35), 13); } #[test] fn test_lookup() { let input = include_str!("../test-input.txt"); - assert_eq!(lookup(input, 79, SOIL), 81); - assert_eq!(lookup(input, 14, SOIL), 14); - assert_eq!(lookup(input, 55, SOIL), 57); - assert_eq!(lookup(input, 13, SOIL), 13); + let maps = extract_maps(input); + assert_eq!(lookup(&maps, 79, SOIL), 81); + assert_eq!(lookup(&maps, 14, SOIL), 14); + assert_eq!(lookup(&maps, 55, SOIL), 57); + assert_eq!(lookup(&maps, 13, SOIL), 13); } #[test] @@ -129,4 +223,10 @@ mod tests { let input = include_str!("../test-input.txt"); assert_eq!(part_1(input), 35); } + + #[test] + fn test_part_2() { + let input = include_str!("../test-input.txt"); + assert_eq!(part_2(input), 46); + } }