Solution for 2022/day15-part2
This commit is contained in:
parent
b447d67a07
commit
c9d9dc1275
8
2022/day15-part2/Cargo.toml
Normal file
8
2022/day15-part2/Cargo.toml
Normal file
@ -0,0 +1,8 @@
|
||||
[package]
|
||||
name = "day15-part2"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
117
2022/day15-part2/src/main.rs
Normal file
117
2022/day15-part2/src/main.rs
Normal file
@ -0,0 +1,117 @@
|
||||
use std::collections::VecDeque;
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
struct Sensor {
|
||||
sx: isize,
|
||||
sy: isize,
|
||||
bx: isize,
|
||||
by: isize,
|
||||
}
|
||||
|
||||
impl Sensor {
|
||||
// Determine the distance between sensor and beacon, using Manhattan metric.
|
||||
fn beacon_distance(&self) -> isize {
|
||||
(self.sx - self.bx).abs() + (self.sy - self.by).abs()
|
||||
}
|
||||
|
||||
// fn beacon_impossible(&self, x: isize, y: isize) -> bool {
|
||||
// let d = (self.sx - x).abs() + (self.sy - y).abs();
|
||||
// d <= self.beacon_distance()
|
||||
// }
|
||||
|
||||
// Return a range for a given y-coordinate where no beacon could
|
||||
// possibly be present for this sensor.
|
||||
fn covered_in_line(&self, y: isize) -> Option<(isize, isize)> {
|
||||
let d = self.beacon_distance() - (self.sy - y).abs();
|
||||
if d < 0 {
|
||||
None
|
||||
} else {
|
||||
Some(((self.sx - d), (self.sx + d)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Collapse multiple ranges into the minimal set of ranges.
|
||||
fn collapse_ranges(ranges: &mut VecDeque<(isize, isize)>) {
|
||||
// First, sort by minimal value..
|
||||
ranges
|
||||
.make_contiguous()
|
||||
.sort_unstable_by(|a, b| a.0.cmp(&b.0));
|
||||
|
||||
// Then continually merge pairs throughout the VecDeque.
|
||||
let mut idx: usize = 0;
|
||||
while idx + 1 < ranges.len() {
|
||||
// Grab the current pair.
|
||||
let a = ranges[idx];
|
||||
let b = ranges[idx + 1];
|
||||
// Check if the minimal vaue of b is contained in a.
|
||||
// In that case we can merge the two.
|
||||
if a.0 <= b.0 && b.0 <= a.1 + 1 {
|
||||
// Remove the first of the pair.
|
||||
ranges.remove(idx);
|
||||
// And update the second element.
|
||||
// (which just moved from idx+1 to idx)
|
||||
ranges[idx] = (a.0, a.1.max(b.1));
|
||||
} else {
|
||||
// If no merge took place, move on to the next pair.
|
||||
idx += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// Use command line arguments to specify the input filename.
|
||||
let args: Vec<String> = std::env::args().collect();
|
||||
if args.len() < 2 {
|
||||
panic!("Usage: ./main <input-file>\nNo input file provided. Exiting.");
|
||||
}
|
||||
|
||||
// Next, read the contents of the input file into a string for easier processing.
|
||||
let input = std::fs::read_to_string(&args[1]).expect("Error opening file");
|
||||
|
||||
// --- TASK BEGIN ---
|
||||
|
||||
// Parse the input.
|
||||
let mut sensors: Vec<Sensor> = Vec::new();
|
||||
for line in input.lines() {
|
||||
let line = line
|
||||
.split('=')
|
||||
.skip(1)
|
||||
.map(|x| {
|
||||
x.chars()
|
||||
.take_while(|c| *c != ',' && *c != ':')
|
||||
.collect::<String>()
|
||||
})
|
||||
.map(|e| e.parse::<isize>().unwrap())
|
||||
.collect::<Vec<_>>();
|
||||
sensors.push(Sensor {
|
||||
sx: line[0],
|
||||
sy: line[1],
|
||||
bx: line[2],
|
||||
by: line[3],
|
||||
})
|
||||
}
|
||||
|
||||
// Iterate over all possible lines.
|
||||
for y in 0..4000000 {
|
||||
// Collect all the ranges in line y where no beacons could be.
|
||||
let mut ranges: VecDeque<(isize, isize)> = VecDeque::new();
|
||||
for s in &sensors {
|
||||
let r = s.covered_in_line(y);
|
||||
// Only collect non-empty ranges, ofc.
|
||||
if let Some(sr) = r {
|
||||
ranges.push_back(sr);
|
||||
}
|
||||
}
|
||||
// Next up, sort + collapse the ranges.
|
||||
collapse_ranges(&mut ranges);
|
||||
// Check if there is a gap in the ranges.
|
||||
// This is likely the spot we're looking for.
|
||||
if ranges.len() > 1 {
|
||||
// dbg!(&ranges);
|
||||
let x = ranges[0].1 + 1;
|
||||
println!("Gap spotted: ({},{})", x, y);
|
||||
println!("Tuning frequency: {}", x * 4000000 + y);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user