From 5c737ed500e724e845a471fcdf87406571160d15 Mon Sep 17 00:00:00 2001 From: Greg Burri Date: Thu, 15 Dec 2022 18:05:06 +0100 Subject: [PATCH] Day 15 --- data/day15.input | 19 +++++++ src/day15.rs | 141 +++++++++++++++++++++++++++++++++++++++++++++++ src/days.rs | 9 +++ src/main.rs | 2 + 4 files changed, 171 insertions(+) create mode 100644 data/day15.input create mode 100644 src/day15.rs diff --git a/data/day15.input b/data/day15.input new file mode 100644 index 0000000..4c21e04 --- /dev/null +++ b/data/day15.input @@ -0,0 +1,19 @@ +Sensor at x=3482210, y=422224: closest beacon is at x=2273934, y=-202439 +Sensor at x=3679395, y=2737332: closest beacon is at x=4104213, y=2980736 +Sensor at x=3173475, y=3948494: closest beacon is at x=3494250, y=3554521 +Sensor at x=27235, y=3642190: closest beacon is at x=-190885, y=3635525 +Sensor at x=3851721, y=1754784: closest beacon is at x=3145586, y=2167751 +Sensor at x=327074, y=3250656: closest beacon is at x=-190885, y=3635525 +Sensor at x=3499970, y=3186179: closest beacon is at x=3494250, y=3554521 +Sensor at x=150736, y=2522778: closest beacon is at x=-85806, y=2000000 +Sensor at x=3000768, y=3333983: closest beacon is at x=2564067, y=3163630 +Sensor at x=1751302, y=1660540: closest beacon is at x=3145586, y=2167751 +Sensor at x=2591068, y=2923079: closest beacon is at x=2564067, y=3163630 +Sensor at x=48946, y=3999178: closest beacon is at x=-190885, y=3635525 +Sensor at x=3695475, y=3863101: closest beacon is at x=3494250, y=3554521 +Sensor at x=1504031, y=2760: closest beacon is at x=2273934, y=-202439 +Sensor at x=3021186, y=2667125: closest beacon is at x=3145586, y=2167751 +Sensor at x=1514629, y=3771171: closest beacon is at x=2564067, y=3163630 +Sensor at x=234064, y=616106: closest beacon is at x=-85806, y=2000000 +Sensor at x=3990843, y=3393575: closest beacon is at x=4104213, y=2980736 +Sensor at x=768875, y=2665271: closest beacon is at x=-85806, y=2000000 \ No newline at end of file diff --git a/src/day15.rs b/src/day15.rs new file mode 100644 index 0000000..80cd727 --- /dev/null +++ b/src/day15.rs @@ -0,0 +1,141 @@ +use itertools::Itertools; +use regex::Regex; + +#[derive(Debug)] +pub struct Sensor { + x: i64, + y: i64, + radius: i64, +} + +#[derive(PartialEq)] +pub struct Beacon { + x: i64, + y: i64, +} + +pub fn parse(input: &str) -> (Vec, Vec) { + let regex = + Regex::new(r"Sensor at x=(-?{1}\d+), y=(-?\d+): closest beacon is at x=(-?\d+), y=(-?\d+)") + .unwrap(); + let mut sensors = Vec::new(); + let mut beacons = Vec::new(); + for l in input.lines() { + let captures = regex.captures(l).unwrap(); + + let (s_x, s_y) = ( + captures[1].parse::().unwrap(), + captures[2].parse::().unwrap(), + ); + let (b_x, b_y) = ( + captures[3].parse::().unwrap(), + captures[4].parse::().unwrap(), + ); + + sensors.push(Sensor { + x: s_x, + y: s_y, + radius: (s_x - b_x).abs() + (s_y - b_y).abs(), + }); + + let beacon = Beacon { x: b_x, y: b_y }; + if !beacons.contains(&beacon) { + beacons.push(Beacon { x: b_x, y: b_y }); + } + } + + (sensors, beacons) +} + +pub fn number_of_position_without_beacon(sensors: &[Sensor], beacons: &[Beacon], row: i64) -> i64 { + let nb_beacons_on_row = beacons + .into_iter() + .filter_map(|b| if b.y == row { Some(b.x) } else { None }) + .count() as i64; + + let segments = sensors + .into_iter() + .filter_map(|s| { + let dx = s.radius - (s.y - row).abs(); + if dx >= 0 { + Some((s.x - dx, s.x + dx)) + } else { + None + } + }) + .sorted(); + + [(i64::MIN, i64::MIN)] + .into_iter() + .chain(segments) + .tuple_windows() + .fold(-nb_beacons_on_row + 1, |sum, (seg1, seg2)| { + sum + if seg2.0 > seg1.1 { + seg2.1 - seg2.0 + } else if seg2.1 > seg1.1 { + seg2.1 - seg1.1 + } else { + 0 + } + }) +} + +pub fn tuning_frequency(sensors: &[Sensor], limit: i64) -> i64 { + for s in sensors.iter() { + for x in s.x - s.radius - 1..=s.x + s.radius + 1 { + if x > limit { + break; + } else if x < 0 { + continue; + } + + let dy = s.radius - (x - s.x).abs() + 1; + 'a: for y in [s.y + dy, s.y - dy] { + if y <= limit && y >= 0 { + for s2 in sensors.iter() { + if (s2.x - x).abs() + (s2.y - y).abs() <= s2.radius { + break 'a; + } + } + return x * 4_000_000 + y; + } + } + } + } + 0 +} + +#[cfg(test)] +mod tests { + use super::*; + + static SCAN: &str = "Sensor at x=2, y=18: closest beacon is at x=-2, y=15 + Sensor at x=9, y=16: closest beacon is at x=10, y=16 + Sensor at x=13, y=2: closest beacon is at x=15, y=3 + Sensor at x=12, y=14: closest beacon is at x=10, y=16 + Sensor at x=10, y=20: closest beacon is at x=10, y=16 + Sensor at x=14, y=17: closest beacon is at x=10, y=16 + Sensor at x=8, y=7: closest beacon is at x=2, y=10 + Sensor at x=2, y=0: closest beacon is at x=2, y=10 + Sensor at x=0, y=11: closest beacon is at x=2, y=10 + Sensor at x=20, y=14: closest beacon is at x=25, y=17 + Sensor at x=17, y=20: closest beacon is at x=21, y=22 + Sensor at x=16, y=7: closest beacon is at x=15, y=3 + Sensor at x=14, y=3: closest beacon is at x=15, y=3 + Sensor at x=20, y=1: closest beacon is at x=15, y=3"; + + #[test] + fn part1() { + let (sensors, beacons) = parse(SCAN); + assert_eq!( + number_of_position_without_beacon(&sensors, &beacons, 10), + 26 + ); + } + + #[test] + fn part2() { + let (sensors, _) = parse(SCAN); + assert_eq!(tuning_frequency(&sensors, 20), 56_000_011); + } +} diff --git a/src/days.rs b/src/days.rs index 704e5b2..45a6b9b 100644 --- a/src/days.rs +++ b/src/days.rs @@ -151,3 +151,12 @@ pub fn day14() -> String { first_grain_touching_floor, last_grain ) } + +pub fn day15() -> String { + let (sensors, beacons) = day15::parse(&fs::read_to_string("data/day15.input").unwrap()); + format!( + "part1: {}, part2: {}", + day15::number_of_position_without_beacon(&sensors, &beacons, 2_000_000), + day15::tuning_frequency(&sensors, 4_000_000) + ) +} diff --git a/src/main.rs b/src/main.rs index 1229242..c56644b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -17,6 +17,7 @@ mod day11; mod day12; mod day13; mod day14; +mod day15; mod days; #[derive(Parser, Debug)] @@ -47,6 +48,7 @@ fn main() { days::day12, days::day13, days::day14, + days::day15, ]; let args = Args::parse(); -- 2.45.2