Create unusably inefficient solution to 2023 day5 part 2

This commit is contained in:
Timothy Warren 2023-12-13 16:13:02 -05:00
parent ba4e489cdb
commit 6d9aaf081d
2 changed files with 102 additions and 31 deletions

View File

@ -130,3 +130,26 @@ number**. In this example, the corresponding types are:
So, the lowest location number in this example is `**35**`.
**What is the lowest location number that corresponds to any of the initial seed numbers?**
## Part 2
Everyone will starve if you only plant such a small number of seeds. Re-reading the almanac, it looks like the seeds:
line actually describes ranges of seed numbers.
The values on the initial seeds: line come in pairs. Within each pair, the first value is the start of the range and
the second value is the length of the range. So, in the first line of the example above:
`seeds: 79 14 55 13`
This line describes two ranges of seed numbers to be planted in the garden. The first range starts with seed number `79`
and contains 14 values: `79`, `80`, ..., `91`, `92`. The second range starts with seed number `55` and contains `13`
values: `55`, `56`, ..., `66`, `67`.
Now, rather than considering four seed numbers, you need to consider a total of **27** seed numbers.
In the above example, the lowest location number can be obtained from seed number `82`, which corresponds to soil `84`,
fertilizer `84`, water `84`, light `77`, temperature `45`, humidity `46`, and location `46`.
So, the lowest location number is `46`.
Consider all of the initial seed numbers listed in the ranges on the first line of the almanac.
**What is the lowest location number that corresponds to any of the initial seed numbers?**

View File

@ -50,9 +50,13 @@ impl DataMap {
}
fn get_dest_idx(&self, src_value: u64) -> Option<u64> {
if !self.to_range.contains(&src_value) {
return None;
}
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 {
if self.from_range.contains(&new_idx) {
return Some(new_idx);
}
}
@ -67,6 +71,7 @@ type MapMap = HashMap<(DataType, DataType), Vec<DataMap>>;
#[derive(Debug, Default)]
struct Almanac {
seeds: Vec<u64>,
seed_ranges: Vec<Range<u64>>,
maps: MapMap,
}
@ -85,6 +90,22 @@ impl Almanac {
.map(|s| s.parse::<u64>().unwrap())
.collect();
let even_seeds: Vec<_> = seeds
.iter()
.enumerate()
.filter_map(|(i, s)| if i % 2 == 0 { Some(*s) } else { None })
.collect();
let odd_seeds: Vec<_> = seeds
.iter()
.enumerate()
.filter_map(|(i, s)| if i % 2 == 1 { Some(*s) } else { None })
.collect();
let seed_ranges = even_seeds
.into_iter()
.enumerate()
.map(|(i, s)| s..(s + odd_seeds[i]))
.collect();
let maps = data_chunks
.into_iter()
.map(|chunk| {
@ -113,40 +134,26 @@ impl Almanac {
})
.collect();
Almanac { seeds, maps }
Almanac {
seeds,
seed_ranges,
maps,
}
}
fn x_from_y(&self, x: DataType, y: DataType, search: u64) -> u64 {
let maps = self
.maps
self.maps
.get(&(y, x))
.expect(&format!("Missing mapping from {:?} to {:?}", x, y));
let mut mapped_value: Vec<Option<u64>> = maps
.expect(&format!("Missing mapping from {:?} to {:?}", x, y))
.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 {
use DataType::*;
self.x_from_y(Soil, Seed, seed)
}
fn fertilizer_from_soil(&self, soil: u64) -> u64 {
self.x_from_y(Fertilizer, Soil, soil)
.filter(|dm| dm.to_range.contains(&search))
.find_map(|dm| dm.get_dest_idx(search))
.unwrap_or_else(|| search)
}
fn location_from_seed(&self, seed: u64) -> u64 {
let soil = self.soil_from_seed(seed);
let fert = self.fertilizer_from_soil(soil);
let soil = self.x_from_y(Soil, Seed, seed);
let fert = self.x_from_y(Fertilizer, 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);
@ -169,15 +176,38 @@ impl Almanac {
.min()
.unwrap()
}
fn lowest_seed_range_location(&self) -> u64 {
self.seed_ranges
.iter()
.map(|r| {
r.clone()
.into_iter()
.map(|s| self.location_from_seed(s))
.min()
.unwrap()
})
.min()
.unwrap()
}
}
fn part_one() {
let almanac = Almanac::parse(FILE_STR);
println!("Part 1: Lowest seed location: {}", almanac.lowest_seed_location());
fn part_one(a: &Almanac) {
println!("Part 1: Lowest seed location: {}", a.lowest_seed_location());
}
fn part_two(a: &Almanac) {
/* println!("{:#?}", a.seed_ranges); */
println!(
"Part 2: Lowest seed range location: {}",
a.lowest_seed_range_location()
);
}
fn main() {
part_one();
let almanac = Almanac::parse(FILE_STR);
part_one(&almanac);
part_two(&almanac);
}
#[cfg(test)]
@ -208,4 +238,22 @@ mod tests {
let almanac = Almanac::parse(EXAMPLE_FILE_STR);
assert_eq!(35, almanac.lowest_seed_location());
}
#[test]
fn test_seed_ranges() {
let almanac = Almanac::parse(EXAMPLE_FILE_STR);
let range1 = 79u64..93;
let range2 = 55u64..68;
assert!(almanac.seed_ranges.contains(&range1));
assert!(almanac.seed_ranges.contains(&range2))
}
#[test]
fn test_lowest_seed_range_location() {
let almanac = Almanac::parse(EXAMPLE_FILE_STR);
assert_ne!(45, almanac.lowest_seed_range_location());
assert_eq!(46, almanac.lowest_seed_range_location());
assert_ne!(47, almanac.lowest_seed_range_location());
}
}