2022 Day 15 Part 2
This commit is contained in:
parent
dc88470d1c
commit
f2e4b01536
1 changed files with 117 additions and 4 deletions
|
|
@ -2,10 +2,13 @@ use std::collections::HashSet;
|
||||||
|
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
|
|
||||||
const INPUT: &str = include_str!("../../input/day15.txt");
|
// const INPUT: (&str, i32, i32) = (include_str!("../../input/day15-ex.txt"), 10, 20);
|
||||||
|
const INPUT: (&str, i32, i32) = (include_str!("../../input/day15.txt"), 2_000_000, 4_000_000);
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
println!("{}", part1(INPUT, 2_000_000));
|
let (input, y, max) = INPUT;
|
||||||
|
println!("Part 1: {}", part1(input, y));
|
||||||
|
println!("Part 2: {}", part2(input, max));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
|
|
@ -50,8 +53,8 @@ fn part1(input: &str, yy: i32) -> usize {
|
||||||
.cloned()
|
.cloned()
|
||||||
.filter(|(s, b)| {
|
.filter(|(s, b)| {
|
||||||
let d_cover = s.pos.distance(b.pos);
|
let d_cover = s.pos.distance(b.pos);
|
||||||
let d_line = s.pos.distance(Pos::new(s.pos.x, yy));
|
let dy = s.pos.distance(Pos::new(s.pos.x, yy));
|
||||||
d_line <= d_cover
|
dy <= d_cover
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
|
@ -99,3 +102,113 @@ fn parse_line(line: &str) -> (Sensor, Beacon) {
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
struct Range {
|
||||||
|
start: i32,
|
||||||
|
end: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Range {
|
||||||
|
fn new(start: i32, end: i32) -> Self {
|
||||||
|
Self { start, end }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn union(&self, other: &Self) -> Option<Self> {
|
||||||
|
let adjacent = self.end + 1 >= other.start;
|
||||||
|
if adjacent {
|
||||||
|
use std::cmp::{max, min};
|
||||||
|
let start = min(self.start, other.start);
|
||||||
|
let end = max(self.end, other.end);
|
||||||
|
Some(Self { start, end })
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn merge_left(mut rs: Vec<Self>) -> Self {
|
||||||
|
rs.sort_by_key(|r| r.start);
|
||||||
|
|
||||||
|
let mut merged = rs[0];
|
||||||
|
|
||||||
|
for r in rs[1..].iter() {
|
||||||
|
if let Some(new) = merged.union(r) {
|
||||||
|
merged = new;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
merged
|
||||||
|
}
|
||||||
|
|
||||||
|
fn len(&self) -> i32 {
|
||||||
|
1 + self.end - self.start
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
struct Coverage {
|
||||||
|
ranges: Vec<Range>,
|
||||||
|
max: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Coverage {
|
||||||
|
fn new(max: i32) -> Self {
|
||||||
|
Self {
|
||||||
|
ranges: vec![],
|
||||||
|
max,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn insert(&mut self, r: Range) {
|
||||||
|
// Clip!
|
||||||
|
let r = Range {
|
||||||
|
start: r.start.max(0),
|
||||||
|
end: r.end.min(self.max),
|
||||||
|
};
|
||||||
|
|
||||||
|
if r.start <= r.end {
|
||||||
|
self.ranges.push(r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn defrag(&self) -> Option<i32> {
|
||||||
|
let merged = Range::merge_left(self.ranges.clone());
|
||||||
|
if merged.len() == self.max + 1 {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(merged.end + 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn part2(input: &str, max: i32) -> i64 {
|
||||||
|
let pairs: Vec<(Sensor, Beacon)> = aoc::lines(input).map(parse_line).collect();
|
||||||
|
|
||||||
|
for yy in 0..=max {
|
||||||
|
let mut coverage = Coverage::new(max);
|
||||||
|
|
||||||
|
for (s, b) in &pairs {
|
||||||
|
let d_cover = s.pos.distance(b.pos);
|
||||||
|
|
||||||
|
let projected = Pos::new(s.pos.x, yy);
|
||||||
|
let dy = s.pos.distance(projected);
|
||||||
|
let dx = d_cover - dy;
|
||||||
|
|
||||||
|
if dx < 0 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let x = s.pos.x;
|
||||||
|
let r = Range::new(x - dx, x + dx);
|
||||||
|
|
||||||
|
coverage.insert(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(xx) = coverage.defrag() {
|
||||||
|
return 4_000_000 * (xx as i64) + (yy as i64);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
panic!("No solution? Must be the input! :P")
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue