177 lines
4.6 KiB
Rust
177 lines
4.6 KiB
Rust
use nom::{
|
|
bytes::streaming::tag,
|
|
character::complete::{self, multispace1},
|
|
multi::separated_list1,
|
|
sequence::{preceded, separated_pair},
|
|
IResult,
|
|
};
|
|
use priority_queue::PriorityQueue;
|
|
use std::collections::HashSet;
|
|
|
|
fn parse_input(input: &str) -> IResult<&str, Vec<((i32, i32), (i32, i32))>> {
|
|
let (input, coords) = separated_list1(
|
|
multispace1,
|
|
preceded(
|
|
tag("Sensor at x="),
|
|
separated_pair(
|
|
separated_pair(complete::i32, tag(", y="), complete::i32),
|
|
tag(": closest beacon is at x="),
|
|
separated_pair(complete::i32, tag(", y="), complete::i32),
|
|
),
|
|
),
|
|
)(input)?;
|
|
|
|
Ok((input, coords))
|
|
}
|
|
|
|
fn manhattan_dist(a: (i32, i32), b: (i32, i32)) -> i32 {
|
|
return (a.0 - b.0).abs() + (a.1 - b.1).abs();
|
|
}
|
|
|
|
fn _fill_map(
|
|
beacon_map: &mut HashSet<(i32, i32)>,
|
|
sensor_coord: (i32, i32),
|
|
beacon_coord: (i32, i32),
|
|
) {
|
|
let dist = manhattan_dist(sensor_coord, beacon_coord);
|
|
let (sx, sy) = sensor_coord;
|
|
|
|
for i in 0..=dist {
|
|
for j in 0..=i {
|
|
beacon_map.insert((sx + i, sy + j));
|
|
beacon_map.insert((sx - i, sy + j));
|
|
beacon_map.insert((sx + i, sy - j));
|
|
beacon_map.insert((sx - i, sy - j));
|
|
}
|
|
}
|
|
}
|
|
|
|
fn fill_line(
|
|
beacon_line: &mut HashSet<i32>,
|
|
sensor_coord: (i32, i32),
|
|
beacon_coord: (i32, i32),
|
|
test_line: i32,
|
|
) {
|
|
let dist = manhattan_dist(sensor_coord, beacon_coord);
|
|
let (sx, sy) = sensor_coord;
|
|
|
|
let cross_section_len = dist - (test_line - sy).abs();
|
|
if cross_section_len >= 0 {
|
|
for i in 0..=cross_section_len {
|
|
beacon_line.insert(sx + i);
|
|
beacon_line.insert(sx - i);
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(PartialEq, Eq, Hash)]
|
|
enum EventType {
|
|
Start,
|
|
Intersection,
|
|
Middle,
|
|
End,
|
|
}
|
|
|
|
#[derive(PartialEq, Eq, Hash)]
|
|
struct Event {
|
|
coord: (i32, i32),
|
|
t: EventType,
|
|
line_id: u32,
|
|
}
|
|
|
|
fn main() {
|
|
let test_y = 2000000;
|
|
|
|
let input_text = include_str!("../input.txt");
|
|
let (_rest, coord_list) = parse_input(input_text).unwrap();
|
|
|
|
// Testing the parsing
|
|
|
|
// for ((sx, sy), (bx, by)) in coord_list {
|
|
// println!("Sensor at x={sx}, y={sy}: closest beacon is at x={bx}, y={by}");
|
|
// }
|
|
|
|
// Naive method
|
|
|
|
// let mut beacon_map = HashSet::new();
|
|
|
|
// for (sensor, beacon) in coord_list {
|
|
// fill_map(&mut beacon_map, sensor, beacon);
|
|
// }
|
|
|
|
// let positions = beacon_map.into_iter().filter(|(_, y)| *y == test_y).count();
|
|
|
|
// println!("Number of positions with y={test_y}: {positions}");
|
|
|
|
// A slightly less naive approach
|
|
|
|
let mut beacon_line = HashSet::new();
|
|
|
|
for (sensor, beacon) in coord_list.clone() {
|
|
fill_line(&mut beacon_line, sensor, beacon, test_y);
|
|
}
|
|
|
|
println!(
|
|
"Number of positions with y={test_y}: {}",
|
|
beacon_line.len() - 1
|
|
);
|
|
|
|
// Part 2
|
|
//
|
|
// Ik denk dat dit misschien wel met een sweep line zou moeten kunnen.
|
|
// Je weet immers waar alle ruiten liggen en je kan die hele mik sorteren.
|
|
// Je krijgt dan 3 event-types: start van een lijnstuk, een kruising en het einde van een lijnstuk.
|
|
// Enige is dat je alleen in de daadwerkelijke coordinaat-range zoals in de opgave dingen wilt
|
|
// mee laten tellen.
|
|
const MAX_COORD: i32 = 8000000;
|
|
|
|
let mut event_queue: PriorityQueue<Event, (i32, i32)> = PriorityQueue::new();
|
|
let mut line_id = 0;
|
|
for &(sensor, beacon) in coord_list.iter() {
|
|
let sensor = (sensor.0 * 2, sensor.1 * 2);
|
|
let beacon = (beacon.0 * 2, beacon.1 * 2);
|
|
|
|
let dist = manhattan_dist(sensor, beacon);
|
|
|
|
let begin = (sensor.0 + dist, sensor.1);
|
|
let middle_1 = (sensor.0, sensor.1 - dist);
|
|
let middle_2 = (sensor.0, sensor.1 + dist);
|
|
let end = (sensor.0 - dist, sensor.1);
|
|
|
|
event_queue.push(
|
|
Event {
|
|
coord: begin,
|
|
t: EventType::Start,
|
|
line_id,
|
|
},
|
|
begin,
|
|
);
|
|
event_queue.push(
|
|
Event {
|
|
coord: middle_1,
|
|
t: EventType::Middle,
|
|
line_id,
|
|
},
|
|
middle_1,
|
|
);
|
|
event_queue.push(
|
|
Event {
|
|
coord: middle_2,
|
|
t: EventType::Middle,
|
|
line_id,
|
|
},
|
|
middle_2,
|
|
);
|
|
event_queue.push(
|
|
Event {
|
|
coord: end,
|
|
t: EventType::End,
|
|
line_id,
|
|
},
|
|
end,
|
|
);
|
|
|
|
line_id += 1;
|
|
}
|
|
}
|