Watch
1
0
Fork
You've already forked advent-of-code
0

2022 Day 15 Part 2

This commit is contained in:
Jeremy Kaplan 2022-12-15 09:40:38 -08:00
commit f2e4b01536

View file

@ -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")
}