Skip to content

Commit 04d9f50

Browse files
committed
chore: WIP for y2025::day_09::part_2
1 parent c70ddce commit 04d9f50

File tree

1 file changed

+69
-42
lines changed

1 file changed

+69
-42
lines changed
Lines changed: 69 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
use std::cmp::{max, min};
2-
use std::collections::{HashSet, VecDeque};
2+
use std::collections::HashMap;
33
use std::iter::{once, successors};
4-
54
use aoclp::positioning::pt::{rectangular_area, Pt};
65
use aoclp::solvers_impl::input::safe_get_input_as_many;
76
use itertools::Itertools;
8-
use aoclp::num::Zero;
7+
use aoclp::positioning::direction::four_points::Direction4;
98

109
pub fn part_1() -> i64 {
1110
input()
@@ -18,56 +17,84 @@ pub fn part_1() -> i64 {
1817

1918
pub fn part_2() -> i64 {
2019
let red_tiles = input();
20+
let path = build_path(&red_tiles);
2121

22-
let path: HashSet<_> = red_tiles
23-
.iter()
24-
.copied()
25-
.chain(once(red_tiles[0]))
26-
.enumerate()
27-
.tuple_windows()
28-
.flat_map(|((ia, a), (ib, b))| {
29-
let displacement = Pt::new((b.x - a.x).signum(), (b.y - a.y).signum());
30-
if displacement.x != 0 && displacement.y != 0 {
31-
panic!("Pair {} (#{ia}), {} (#{ib}) have wrong displacement", a.to_string(), b.to_string())
32-
}
33-
successors(Some(a), move |&p| (p != b).then_some(p + displacement))
34-
.chain(once(b))
35-
})
36-
.collect();
37-
38-
let floor_width = red_tiles.iter().map(|p| p.x).max().unwrap() + 2;
39-
let floor_height = red_tiles.iter().map(|p| p.y).max().unwrap() + 2;
40-
41-
let mut lava = HashSet::new();
42-
let mut q = VecDeque::new();
43-
q.push_back(Pt::zero());
44-
while let Some(p) = q.pop_front() {
45-
if !p.within(0..floor_width, 0..floor_height) || path.contains(&p) {
46-
continue;
47-
}
48-
if lava.insert(p) {
49-
q.extend(p.four_neighbours());
22+
let safe_line = red_tiles.iter().map(|p| p.y).min().unwrap() - 1;
23+
let mut pt_safety = HashMap::new();
24+
let mut safe_pt = |p: Pt| {
25+
if let Some(&safe) = pt_safety.get(&p) {
26+
return safe;
5027
}
51-
}
5228

53-
let safe_rectangle = |a: Pt, b: Pt| -> bool {
54-
(min(a.y, b.y)..=max(a.y, b.y))
55-
.into_iter()
56-
.flat_map(|y| {
57-
(min(a.x, b.x)..=max(a.x, b.x)).into_iter().map(move |x| Pt::new(x, y))
58-
})
59-
.all(|p| !lava.contains(&p))
29+
let safe = successors(Some(p), |&p| (p.y > safe_line).then_some(p + Direction4::Up))
30+
.filter(|p| path.get(p).is_some_and(|&step| step == PathStep::LeftRight))
31+
.count() % 2 != 0;
32+
pt_safety.insert(p, safe);
33+
safe
34+
};
35+
let mut safe_line = |a: Pt, b: Pt| -> bool {
36+
let displacement = Pt::new((b.x - a.x).signum(), (b.y - a.y).signum());
37+
successors(Some(a), |&p| (p != b).then_some(p + displacement)).chain(Some(b))
38+
.all(|p| safe_pt(p))
39+
};
40+
let mut safe_rectangle = |a: Pt, b: Pt| {
41+
let corners = [
42+
Pt::new(min(a.x, b.x), min(a.y, b.y)),
43+
Pt::new(min(a.x, b.x), max(a.y, b.y)),
44+
Pt::new(max(a.x, b.x), max(a.y, b.y)),
45+
Pt::new(max(a.x, b.x), min(a.y, b.y)),
46+
Pt::new(min(a.x, b.x), min(a.y, b.y)),
47+
];
48+
corners
49+
.iter()
50+
.tuple_windows()
51+
.all(|(&a, &b)| safe_line(a, b))
6052
};
6153

6254
red_tiles
6355
.into_iter()
6456
.array_combinations()
65-
.filter(|&[a, b]| safe_rectangle(a, b))
66-
.map(|[a, b]| rectangular_area(a, b))
67-
.max()
57+
.map(|[a, b]| (a, b, rectangular_area(a, b)))
58+
.sorted_unstable_by(|(_, _, area_a), (_, _, area_b)| area_b.cmp(area_a))
59+
.filter(|&(a, b, _)| safe_rectangle(a, b))
60+
.map(|(_, _, area)| area)
61+
.next()
6862
.unwrap()
6963
}
7064

65+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
66+
enum PathStep {
67+
Corner,
68+
LeftRight,
69+
TopDown,
70+
}
71+
72+
impl PathStep {
73+
fn for_pair(a: Pt, b: Pt) -> Self {
74+
if (a.x - b.x).abs().signum() != 0 {
75+
Self::LeftRight
76+
} else {
77+
Self::TopDown
78+
}
79+
}
80+
}
81+
82+
fn build_path(red_tiles: &[Pt]) -> HashMap<Pt, PathStep> {
83+
red_tiles
84+
.iter()
85+
.copied()
86+
.chain(once(red_tiles[0]))
87+
.tuple_windows()
88+
.flat_map(|(a, b)| {
89+
let step = PathStep::for_pair(a, b);
90+
let displacement = Pt::new((b.x - a.x).signum(), (b.y - a.y).signum());
91+
successors(Some((a, PathStep::Corner)), move |&(p, _)| {
92+
(p != b).then_some((p + displacement, step))
93+
}).chain(once((b, PathStep::Corner)))
94+
})
95+
.collect()
96+
}
97+
7198
fn input() -> Vec<Pt> {
7299
safe_get_input_as_many(2025, 9)
73100
}

0 commit comments

Comments
 (0)