day 5 part 2
This commit is contained in:
parent
89734cdd86
commit
ee317153e6
1 changed files with 186 additions and 39 deletions
221
src/main.rs
221
src/main.rs
|
@ -1,55 +1,126 @@
|
|||
use std::cmp::{max, min};
|
||||
use std::{collections::HashMap, io::stdin};
|
||||
|
||||
use anyhow::Result;
|
||||
use regex::Regex;
|
||||
//
|
||||
// #[derive(Debug)]
|
||||
// struct Seed(i64);
|
||||
//
|
||||
// #[derive(Debug)]
|
||||
// struct Soil(i64);
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
struct Range {
|
||||
start: i64,
|
||||
len: i64,
|
||||
}
|
||||
|
||||
impl Range {
|
||||
fn intersection(&self, other: &Range) -> Option<Range> {
|
||||
let i1 = max(self.start, other.start);
|
||||
let i2 = min(self.start + self.len, other.start + other.len);
|
||||
|
||||
if i1 >= i2 {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(Range {
|
||||
start: i1,
|
||||
len: i2 - i1,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
struct RangeMap {
|
||||
from: i64,
|
||||
to: i64,
|
||||
len: i64,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Map {
|
||||
ranges: Vec<(i64, i64, i64)>,
|
||||
struct SeedsMap {
|
||||
range_maps: Vec<RangeMap>,
|
||||
}
|
||||
|
||||
impl Map {
|
||||
fn new() -> Map {
|
||||
Map { ranges: vec![] }
|
||||
impl SeedsMap {
|
||||
fn new() -> SeedsMap {
|
||||
SeedsMap { range_maps: vec![] }
|
||||
}
|
||||
|
||||
fn add_range(&mut self, range: (i64, i64, i64)) {
|
||||
self.ranges.push(range);
|
||||
self.range_maps.push(RangeMap {
|
||||
from: range.1,
|
||||
to: range.0,
|
||||
len: range.2,
|
||||
});
|
||||
self.range_maps.sort_by_key(|r| r.from);
|
||||
}
|
||||
fn map(&self, value: i64) -> i64 {
|
||||
for (to, from, len) in &self.ranges {
|
||||
if value >= *from && value < (from + len) {
|
||||
return to + (value - from);
|
||||
|
||||
fn map(&self, ranges: &[Range]) -> Vec<Range> {
|
||||
let mut result = vec![];
|
||||
for r in ranges {
|
||||
result.extend(self.map_single_range(r));
|
||||
}
|
||||
result
|
||||
}
|
||||
value
|
||||
|
||||
fn map_single_range(&self, range: &Range) -> Vec<Range> {
|
||||
if self.range_maps.is_empty() {
|
||||
return vec![*range];
|
||||
}
|
||||
|
||||
let mut result = vec![];
|
||||
let first = self.range_maps.first().unwrap();
|
||||
let last = self.range_maps.last().unwrap();
|
||||
let left = min(range.start, first.from);
|
||||
let right = max(range.start + range.len, last.from + last.len);
|
||||
|
||||
let mut last = left;
|
||||
for rm in &self.range_maps {
|
||||
// first, a range from last to rm.start, with no mapping
|
||||
let r = Range {
|
||||
start: last,
|
||||
len: rm.from - last,
|
||||
};
|
||||
if let Some(i) = r.intersection(range) {
|
||||
result.push(i);
|
||||
}
|
||||
// second, a range from rm.start, with mapping
|
||||
let r = Range {
|
||||
start: rm.from,
|
||||
len: rm.len,
|
||||
};
|
||||
if let Some(i) = r.intersection(range) {
|
||||
result.push(Range {
|
||||
start: rm.to + i.start - rm.from,
|
||||
len: i.len,
|
||||
});
|
||||
last = i.start + i.len;
|
||||
}
|
||||
}
|
||||
|
||||
// impl Seed {
|
||||
// fn to_soil(self) -> Soil {
|
||||
// Soil(seed_to_soil
|
||||
// }
|
||||
// }
|
||||
let r = Range {
|
||||
start: last,
|
||||
len: right - last,
|
||||
};
|
||||
if let Some(i) = r.intersection(range) {
|
||||
result.push(i);
|
||||
}
|
||||
|
||||
// type RangeMap = Vec<(i64, i64, i64)>;
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let mut maps: HashMap<String, Map> = HashMap::new();
|
||||
fn parse_input(seed_ranges: &mut Vec<Range>, maps: &mut HashMap<String, SeedsMap>) -> Result<()> {
|
||||
let numbers = Regex::new(r"(\d+)")?;
|
||||
let pairs = Regex::new(r"(\d+) (\d+)")?;
|
||||
let mut current_map = String::new();
|
||||
let mut seeds: Vec<i64> = vec![];
|
||||
|
||||
for line in stdin().lines().map_while(Result::ok) {
|
||||
if line.starts_with("seeds:") {
|
||||
seeds = numbers
|
||||
*seed_ranges = pairs
|
||||
.captures_iter(&line)
|
||||
.map(|c| c.get(1).unwrap().as_str().parse())
|
||||
.map(|c| -> Result<Range> {
|
||||
Ok(Range {
|
||||
start: c.get(1).unwrap().as_str().parse()?,
|
||||
len: c.get(2).unwrap().as_str().parse()?,
|
||||
})
|
||||
})
|
||||
.map_while(Result::ok)
|
||||
.collect();
|
||||
} else if line.ends_with(" map:") {
|
||||
|
@ -65,11 +136,22 @@ fn main() -> Result<()> {
|
|||
.map_while(Result::ok)
|
||||
.collect();
|
||||
if nums.len() == 3 {
|
||||
let map = maps.entry(current_map.clone()).or_insert_with(Map::new);
|
||||
let map = maps
|
||||
.entry(current_map.clone())
|
||||
.or_insert_with(SeedsMap::new);
|
||||
map.add_range((nums[0], nums[1], nums[2]));
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let mut maps: HashMap<String, SeedsMap> = HashMap::new();
|
||||
let mut seed_ranges: Vec<Range> = vec![];
|
||||
|
||||
parse_input(&mut seed_ranges, &mut maps)?;
|
||||
|
||||
let map_names = [
|
||||
"seed-to-soil",
|
||||
"soil-to-fertilizer",
|
||||
|
@ -79,17 +161,82 @@ fn main() -> Result<()> {
|
|||
"temperature-to-humidity",
|
||||
"humidity-to-location",
|
||||
];
|
||||
|
||||
let mut locations = vec![];
|
||||
for seed in &seeds {
|
||||
let mut step = *seed;
|
||||
for range in seed_ranges {
|
||||
let mut mapped_ranges = vec![range];
|
||||
for map_name in map_names {
|
||||
let mapped = maps.get(map_name).unwrap().map(step);
|
||||
println!("mapped {step} using {map_name} to {mapped}");
|
||||
step = mapped;
|
||||
let mapped = maps.get(map_name).unwrap().map(&mapped_ranges);
|
||||
mapped_ranges = mapped;
|
||||
}
|
||||
locations.push(step);
|
||||
println!();
|
||||
locations.extend(mapped_ranges.iter().map(|r| r.start));
|
||||
}
|
||||
println!("{}", locations.iter().min().unwrap());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_intersections() {
|
||||
let l = |r1: &Range, r2: &Range| r1.intersection(r2);
|
||||
assert_eq!(
|
||||
l(&Range { start: 1, len: 3 }, &Range { start: 1, len: 3 }),
|
||||
Some(Range { start: 1, len: 3 })
|
||||
);
|
||||
assert_eq!(
|
||||
l(&Range { start: 1, len: 2 }, &Range { start: 1, len: 3 }),
|
||||
Some(Range { start: 1, len: 2 })
|
||||
);
|
||||
assert_eq!(
|
||||
l(&Range { start: 2, len: 4 }, &Range { start: 0, len: 3 }),
|
||||
Some(Range { start: 2, len: 1 })
|
||||
);
|
||||
assert_eq!(
|
||||
l(&Range { start: 0, len: 3 }, &Range { start: 2, len: 4 }),
|
||||
Some(Range { start: 2, len: 1 })
|
||||
);
|
||||
assert_eq!(
|
||||
l(&Range { start: 3, len: 4 }, &Range { start: 0, len: 3 }),
|
||||
None
|
||||
);
|
||||
assert_eq!(
|
||||
l(&Range { start: 0, len: 10 }, &Range { start: 4, len: 4 }),
|
||||
Some(Range { start: 4, len: 4 })
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_range_map() {
|
||||
let mut m = SeedsMap::new();
|
||||
m.add_range((52, 50, 48));
|
||||
m.add_range((50, 98, 2));
|
||||
let r = m.map_single_range(&Range { start: 79, len: 14 });
|
||||
assert_eq!(r, [Range { start: 81, len: 14 }]);
|
||||
|
||||
let mut m = SeedsMap::new();
|
||||
m.add_range((39, 0, 15));
|
||||
m.add_range((0, 15, 37));
|
||||
m.add_range((37, 52, 2));
|
||||
let r = m.map_single_range(&Range { start: 81, len: 14 });
|
||||
assert_eq!(r, [Range { start: 81, len: 14 }]);
|
||||
|
||||
let mut m = SeedsMap::new();
|
||||
m.add_range((88, 18, 7));
|
||||
m.add_range((18, 25, 70));
|
||||
let r = m.map_single_range(&Range { start: 81, len: 14 });
|
||||
assert_eq!(r, [Range { start: 74, len: 14 }]);
|
||||
|
||||
let mut m = SeedsMap::new();
|
||||
m.add_range((81, 45, 19));
|
||||
m.add_range((68, 64, 13));
|
||||
m.add_range((45, 77, 23));
|
||||
let r = m.map_single_range(&Range { start: 74, len: 14 });
|
||||
assert_eq!(
|
||||
r,
|
||||
[Range { start: 78, len: 3 }, Range { start: 45, len: 11 }]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue