pub fn part1(input: &str) -> isize { get_empty_ranges(&parse(input), 2000000).iter() .map(|(s, e)| e - s) .sum() } pub fn part2(input: &str) -> isize { std::iter::once(parse(input)).map(|sensors| ( sensors.iter().fold(( std::collections::BTreeMap::<isize, isize>::new(), std::collections::BTreeMap::<isize, isize>::new(), ), |(mut a, mut b), s| { for i in 0..4 { match i { 0 => *a.entry(s.y - s.x + s.r + 1).or_default() += 1, 1 => *a.entry(s.y - s.x - s.r - 1).or_default() += 1, 2 => *b.entry(s.x + s.y + s.r + 1).or_default() += 1, _ => *b.entry(s.x + s.y - s.r - 1).or_default() += 1, } } (a, b) }), sensors, )).map(|((a, b), sensors)| ( a.into_iter() .filter_map(|(k, v)| (v > 1).then_some(k)), b.into_iter() .filter_map(|(k, v)| (v > 1).then_some(k)) .collect::<Vec<_>>(), sensors, )).fold(0, |_, (a, b, sensors)| a.flat_map(|x| std::iter::repeat(x).zip(b.iter())) .map(|(a, b)| ((b - a) / 2, (a + b) / 2)) .find_map(|(x, y)| ( x.min(y) > 0 && x.max(y) < 4000000 && sensors.iter().all(|s| distance((s.x, s.y), (x, y)) > s.r) ).then_some(x * 4000000 + y)) .unwrap_or_default()) } fn parse(input: &str) -> Vec<Sensor> { input.lines() .flat_map(|l| TryInto::<[_; 4]>::try_into( l.split(|c: char| !c.is_ascii_digit() && c != '-') .flat_map(|p| p.parse::<isize>().ok()) .collect::<Vec<_>>())) .map(|[x, y, bx, by]| Sensor { x, y, r: distance((x, y), (bx, by)), }) .collect() } fn get_empty_ranges(sensors: &[Sensor], row: isize) -> Vec<(isize, isize)> { flatten_ranges(&sensors.iter() .filter_map(|s| std::iter::once((s.y - row).abs()) .find_map(|d| (d <= s.r).then_some(( s.x - (s.r - d), s.x + (s.r - d), )))) .collect::<std::collections::BinaryHeap<_>>() .into_sorted_vec()) } // https://www.geeksforgeeks.org/merging-intervals/ fn flatten_ranges(ranges: &[(isize, isize)]) -> Vec<(isize, isize)> { (!ranges.is_empty()).then_some(ranges.iter() .skip(1) .fold(vec![ranges[0]], |flat, &r| std::iter::once(flat.len() - 1).fold(flat, |mut flat, last| { match flat[last].0 <= r.0 && r.0 <= flat[last].1 { true => flat[last].1 = flat[last].1.max(r.1), _ => flat.push(r), } flat }))) .unwrap_or_default() } fn distance(a: (isize, isize), b: (isize, isize)) -> isize { (a.0 - b.0).abs() + (a.1 - b.1).abs() } #[derive(Debug, Clone, Copy)] struct Sensor { x: isize, y: isize, r: isize, }