aoc2023/day5/src/main.rs
2023-12-08 23:00:32 +01:00

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