From f55cfaccce683a6c528f026f49b111af06656517 Mon Sep 17 00:00:00 2001 From: Joscha Date: Thu, 15 Dec 2022 10:16:25 +0100 Subject: [PATCH] [rs] Solve 2022_15 part 2 --- inputs/2022/2022_15.solution | 2 +- rs/src/y2022/d15.rs | 80 ++++++++++++++++++++++++++---------- 2 files changed, 60 insertions(+), 22 deletions(-) diff --git a/inputs/2022/2022_15.solution b/inputs/2022/2022_15.solution index d6820f8..a690121 100644 --- a/inputs/2022/2022_15.solution +++ b/inputs/2022/2022_15.solution @@ -1,2 +1,2 @@ Part 1: 4811413 -Part 2: ??? +Part 2: 13171855019123 diff --git a/rs/src/y2022/d15.rs b/rs/src/y2022/d15.rs index aecab4b..22bc4b4 100644 --- a/rs/src/y2022/d15.rs +++ b/rs/src/y2022/d15.rs @@ -11,10 +11,44 @@ fn parse_coord(coord: &str) -> i32 { coord.parse().unwrap() } +fn line_ranges(sensors: &[Sensor], y: i32) -> Vec<(i32, i32)> { + let mut raw_ranges = vec![]; + for sensor in sensors { + let dy = (y - sensor.pos.1).abs(); + if dy > sensor.dist { + continue; + } + let dx = sensor.dist - dy; + raw_ranges.push((sensor.pos.0 - dx, sensor.pos.0 + dx)); + } + raw_ranges.sort(); + + let mut ranges = vec![]; + let mut raw_ranges = raw_ranges.into_iter(); + if let Some(mut cur) = raw_ranges.next() { + for range in raw_ranges { + if cur.0 <= range.0 && range.0 <= cur.1 { + cur.1 = cur.1.max(range.1); + } else { + ranges.push(cur); + cur = range; + } + } + ranges.push(cur); + } + ranges +} + pub fn solve(input: String) { let sensors = input .lines() .map(|l| { + // A beacon exactly dist away has 1 field, i. e. x±0 + // A beacon exactly dist-1 away has 3 fields, i. e. x±1 + // ... + // A beacon exactly 0 away has 2dist+1 fields, i. e. x±dist + // + // Formula: Go from x-(dist-dy) to x+(dist-dy) let parts = l.split_whitespace().collect::>(); let pos = (parse_coord(parts[2]), parse_coord(parts[3])); let beac = (parse_coord(parts[8]), parse_coord(parts[9])); @@ -23,30 +57,34 @@ pub fn solve(input: String) { }) .collect::>(); - // A beacon exactly dist away has 1 field, i. e. x±0 - // A beacon exactly dist-1 away has 3 fields, i. e. x±1 - // ... - // A beacon exactly 0 away has 2dist+1 fields, i. e. x±dist - // - // Formula: Go from x-(dist-dy) to x+(dist-dy) let line_at_y = 2000000; - let mut part1 = HashSet::new(); - for (i, sensor) in sensors.iter().enumerate() { - eprintln!("Sensor {}", i + 1); - let dy = (line_at_y - sensor.pos.1).abs(); - if dy > sensor.dist { - continue; + let part1_ranges = line_ranges(&sensors, line_at_y); + let part1_beacons = sensors + .iter() + .filter(|s| s.beac.1 == line_at_y) + .map(|s| s.beac.0) + .collect::>(); + let mut part1 = 0; + for range in part1_ranges { + part1 += range.1 - range.0 + 1; + for beacon in &part1_beacons { + if range.0 <= *beacon && *beacon <= range.1 { + part1 -= 1; + } } + } + println!("Part 1: {part1}"); - let dx = sensor.dist - dy; - for x in (sensor.pos.0 - dx)..=(sensor.pos.0 + dx) { - part1.insert(x); + for y in 0..=4000000 { + let mut ranges = line_ranges(&sensors, y); + ranges.retain(|(s, e)| *s <= 4000000 && 0 <= *e); + if ranges.len() != 1 { + // Found our beacon! + assert_eq!(ranges.len(), 2); + let x = ranges[0].1 + 1; + let tuning_frequency = x as i64 * 4000000 + y as i64; + println!("Part 2: {tuning_frequency}"); + break; } } - for sensor in &sensors { - if sensor.beac.1 == line_at_y { - part1.remove(&sensor.beac.0); - } - } - println!("Part 1: {}", part1.len()); }