77 lines
1.9 KiB
Rust
77 lines
1.9 KiB
Rust
use std::{collections::BTreeMap, io::stdin, ops::{Mul, Range}};
|
|
use anyhow::{Result, bail};
|
|
|
|
mod parse;
|
|
|
|
#[derive(Debug)]
|
|
struct MapRange {
|
|
base: usize,
|
|
target: usize,
|
|
}
|
|
|
|
/// Stores a map as a series of contiguous offset ranges.
|
|
#[derive(Debug)]
|
|
struct Map {
|
|
from: String,
|
|
to: String,
|
|
ranges: Vec<MapRange>,
|
|
}
|
|
|
|
|
|
impl Map {
|
|
|
|
fn from_ranges(from: String, to: String, mut v: Vec<(usize,usize,usize)>) -> Self {
|
|
v.sort_by_key(|r| r.1);
|
|
|
|
let mut ranges = Vec::with_capacity(2*v.len() + 1);
|
|
ranges.push(MapRange {base: 0, target: 0 } );
|
|
|
|
for (target, base, len) in v {
|
|
if ranges.last().unwrap().base == base {
|
|
ranges.pop();
|
|
}
|
|
ranges.push(MapRange { base, target });
|
|
ranges.push(MapRange { base: base+len, target: base+len });
|
|
}
|
|
|
|
Self { from, to, ranges }
|
|
}
|
|
|
|
fn range_idx(&self, target: usize) -> usize {
|
|
self.ranges.binary_search_by_key(&target, |r| r.base)
|
|
.unwrap_or_else(|i| i-1)
|
|
}
|
|
|
|
fn lookup(&self, src: usize) -> usize {
|
|
let range = &self.ranges[self.range_idx(src)];
|
|
(src + range.target) - range.base
|
|
}
|
|
}
|
|
|
|
fn main() -> Result<()> {
|
|
let (seeds, maps) = parse::input(stdin().lock())?;
|
|
|
|
eprintln!("{seeds:?}, {maps:?}");
|
|
|
|
let mut current= "seed";
|
|
|
|
for map in &maps {
|
|
if map.from != current { bail!("Wrong map order, expected {current}") }
|
|
current = &map.to;
|
|
}
|
|
|
|
let best = seeds.iter()
|
|
.map(|&s| {
|
|
let mut cur = s;
|
|
eprint!("{cur}");
|
|
for m in &maps {
|
|
cur = m.lookup(cur);
|
|
eprint!(" -> {cur}")
|
|
}
|
|
eprintln!();
|
|
cur
|
|
}).min();
|
|
println!("lowest location: {best:?}");
|
|
Ok(())
|
|
}
|