#![feature(iter_array_chunks)] use nom::{Parser, IResult, Finish}; use nom::character::complete::*; use nom::bytes::complete::*; use nom::sequence::*; use nom::multi::*; use std::io::Write; static INPUT: &str = include_str!("input.txt"); #[derive(Debug, Copy, Clone)] struct Entry { source_start: u32, dest_start: u32, len: u32 } fn parse(i: &str) -> IResult<&str, (Vec, Vec>)> { let (i, (_, seeds, mut entries)) = tuple(( tag("seeds: "), separated_list1(tag(" "), digit1.map(|s: &str| s.parse().unwrap())), many1(preceded( tuple((line_ending, line_ending, not_line_ending, line_ending)), separated_list1( line_ending, tuple(( digit1, tag(" "), digit1, tag(" "), digit1)) .map(|(a, _, b, _, c): (&str, _, &str, _, &str)| Entry { dest_start: a.parse().unwrap(), source_start: b.parse().unwrap(), len: c.parse().unwrap() })))))) (i)?; for entry in &mut entries { entry.sort_by_key(|e| e.source_start); } Ok((i, (seeds, entries))) } fn main() { let (seeds, entries) = parse(INPUT).finish().unwrap().1; let map_seed = |s: u32| entries.iter().fold( s, |s, el| { let entry = el.iter().cloned().find( |i| i.source_start <= s && s - i.source_start < i.len) .unwrap_or(Entry { source_start: 0, dest_start: 0, len: u32::MAX }); s - entry.source_start + entry.dest_start }); let min_loc = seeds.iter().cloned().map(map_seed).min().unwrap(); println!("Minimum `location`: {min_loc}"); // [12:48 AM] got p1 // [12:48 AM] oh this sucks // [12:50 AM] do i just // [12:50 AM] brute force it // [12:50 AM] i could like // [12:50 AM] write something clever here // [12:51 AM] like i think i could do something like lifting the mapping between the layers and creating one final mapping, and then just checking against that // [12:51 AM] and just finding the lowest start number within the bounds of all the seed ranges // [12:51 AM] but i dont feel like doing that #[cfg(debug_assertions)] eprintln!("Warning: Debug build detected! This next bit takes a while, so I'd suggest compiling `--release`."); let min_loc_ranged = seeds.iter().array_chunks::<2>() .inspect(|[a, b]| { print!("\x1B[2KChecking {} => {}...\r", *a, *a + *b); std::io::stdout().flush().unwrap(); }) .flat_map(|[a, b]| *a..(*a+*b)) .map(map_seed) .min().unwrap(); println!("Minimum `location` within ranges: {min_loc_ranged}"); }