Skip to content

Commit

Permalink
minor cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
kcaffrey committed Dec 5, 2023
1 parent e3d051f commit 518193e
Showing 1 changed file with 26 additions and 44 deletions.
70 changes: 26 additions & 44 deletions src/bin/05.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,40 +25,18 @@ pub fn part_two(input: &str) -> Option<u32> {
#[derive(Clone, Debug, PartialEq, Eq)]
struct Almanac {
seeds: Vec<u64>,
seed_to_soil: AlmanacMap,
soil_to_fertilizer: AlmanacMap,
fertilizer_to_water: AlmanacMap,
water_to_light: AlmanacMap,
light_to_temperature: AlmanacMap,
temperature_to_humidity: AlmanacMap,
humidity_to_location: AlmanacMap,
maps: Vec<AlmanacMap>,
}

impl Almanac {
pub fn lookup_location(&self, seed: u64) -> u64 {
let soil = self.seed_to_soil.map(seed);
let fertilizer = self.soil_to_fertilizer.map(soil);
let water = self.fertilizer_to_water.map(fertilizer);
let light = self.water_to_light.map(water);
let temperature = self.light_to_temperature.map(light);
let humidity = self.temperature_to_humidity.map(temperature);

self.humidity_to_location.map(humidity)
self.maps.iter().fold(seed, |value, map| map.map(value))
}

pub fn min_location(&self, input: Range<u64>) -> Option<u64> {
let mappings = [
&self.seed_to_soil,
&self.soil_to_fertilizer,
&self.fertilizer_to_water,
&self.water_to_light,
&self.light_to_temperature,
&self.temperature_to_humidity,
&self.humidity_to_location,
];
let mut ranges = vec![input];
let mut next_ranges = vec![];
for mapping in mappings {
for mapping in &self.maps {
for range in ranges.drain(..) {
next_ranges.extend(mapping.map_range(range));
}
Expand All @@ -81,32 +59,43 @@ impl AlmanacMap {
.unwrap_or(input)
}

pub fn map_range(&self, input: Range<u64>) -> Vec<Range<u64>> {
pub fn map_range(&self, input: Range<u64>) -> impl IntoIterator<Item = Range<u64>> + '_ {
let mut input = input;
let mut output = vec![];

// NOTE: we assume the ranges are sorted in ascending order.
for range_mapping in &self.ranges {
if range_mapping.source_range.start >= input.end {
// The input range ends before this range starts, so we can early terminate here.
output.push(input);
return output;
}
if input.start < range_mapping.source_range.start {
// Part of the input precedes this range, so pass that part through as is.
output.push(input.start..range_mapping.source_range.start);
}

// Compute the intersection of the two ranges and add the offset of this mapping.
let start = std::cmp::max(input.start, range_mapping.source_range.start);
let end = std::cmp::min(input.end, range_mapping.source_range.end);
if end > start {
output.push(
(start as i64 + range_mapping.offset) as u64
..(end as i64 + range_mapping.offset) as u64,
);

// Adjust the input to be only the part that comes after the range in this mapping.
if end < input.end {
input = end..input.end;
} else {
return output;
}
}
}
output.push(input);
if input.end > input.start {
// If there is anything leftover after the last mapping, pass that through as-is.
output.push(input);
}
output
}
}
Expand Down Expand Up @@ -145,26 +134,16 @@ impl FromStr for Almanac {
.map(|s| s.parse::<u64>())
.collect::<Result<Vec<_>, _>>()
.map_err(|_| ParseAlmanacErr)?;
let mut maps = parts
let maps = parts
.into_iter()
.skip(1)
.map(|s| {
s.split_once(":\n")
.ok_or(ParseAlmanacErr)
.and_then(|(_, s)| s.parse::<AlmanacMap>())
})
.collect::<Result<Vec<_>, _>>()?
.into_iter();
Ok(Self {
seeds,
seed_to_soil: maps.next().ok_or(ParseAlmanacErr)?,
soil_to_fertilizer: maps.next().ok_or(ParseAlmanacErr)?,
fertilizer_to_water: maps.next().ok_or(ParseAlmanacErr)?,
water_to_light: maps.next().ok_or(ParseAlmanacErr)?,
light_to_temperature: maps.next().ok_or(ParseAlmanacErr)?,
temperature_to_humidity: maps.next().ok_or(ParseAlmanacErr)?,
humidity_to_location: maps.next().ok_or(ParseAlmanacErr)?,
})
.collect::<Result<Vec<_>, _>>()?;
Ok(Self { seeds, maps })
}
}

Expand Down Expand Up @@ -230,10 +209,13 @@ mod tests {
},
],
};
assert_eq!(almananc_map.map_range(79..93), vec![81..95]);
assert_eq!(almananc_map.map_range(90..100), vec![92..100, 50..52]);
assert_eq!(Vec::from_iter(almananc_map.map_range(79..93)), vec![81..95]);
assert_eq!(
Vec::from_iter(almananc_map.map_range(90..100)),
vec![92..100, 50..52]
);
assert_eq!(
almananc_map.map_range(90..102),
Vec::from_iter(almananc_map.map_range(90..102)),
vec![92..100, 50..52, 100..102]
);

Expand All @@ -253,6 +235,6 @@ mod tests {
},
],
};
assert_eq!(almanac_map.map_range(81..95), vec![81..95]);
assert_eq!(Vec::from_iter(almanac_map.map_range(81..95)), vec![81..95]);
}
}

0 comments on commit 518193e

Please sign in to comment.