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(()) }