Skip to content

Commit 234dc27

Browse files
committed
chore: WIP y2025::day_09::part_2
1 parent 4416b68 commit 234dc27

File tree

1 file changed

+89
-55
lines changed

1 file changed

+89
-55
lines changed

aoclp_solutions/src/y2025/day_09.rs

Lines changed: 89 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
use std::cmp::{max, min};
2-
use std::collections::HashSet;
3-
use std::iter::{once, successors};
2+
use std::collections::{BTreeSet, HashSet};
3+
use std::iter::successors;
44

55
use aoclp::positioning::direction::four_points::Direction4;
66
use aoclp::positioning::pt::{rectangular_area, Pt};
77
use aoclp::solvers_impl::input::safe_get_input_as_many;
88
use itertools::Itertools;
9-
use aoclp::positioning::turtle::Turtle;
9+
use aoclp::positioning::direction::Direction;
1010

1111
pub fn part_1() -> i64 {
1212
input()
@@ -20,74 +20,108 @@ pub fn part_1() -> i64 {
2020
pub fn part_2() -> i64 {
2121
let red_tiles = input();
2222

23-
let red_zone = build_red_zone(&red_tiles);
24-
let rectangle_points = |a: Pt, b: Pt| {
25-
let (left, right, top, bottom) = (min(a.x, b.x), max(a.x, b.x), min(a.y, b.y), max(a.y, b.y));
26-
(left..=right).flat_map(move |x| (top..=bottom).map(move |y| Pt::new(x, y)))
27-
};
28-
let safe_rectangle = |a, b| {
29-
rectangle_points(a, b).all(|p| !red_zone.contains(&p))
23+
let red_zone: BTreeSet<_> = build_red_zone(&red_tiles).collect();
24+
let safe_rectangle = |a: Pt, b: Pt| {
25+
let corners = vec![
26+
Pt::new(min(a.x, b.x), min(a.y, b.y)),
27+
Pt::new(max(a.x, b.x), min(a.y, b.y)),
28+
Pt::new(max(a.x, b.x), max(a.y, b.y)),
29+
Pt::new(max(a.x, b.x), min(a.y, b.y)),
30+
Pt::new(min(a.x, b.x), min(a.y, b.y)),
31+
];
32+
let edges: BTreeSet<_> = corners
33+
.into_iter()
34+
.tuple_windows()
35+
.flat_map(|(a, b)| {
36+
let displacement = Pt::new((b.x - a.x).signum(), (b.y - a.y).signum());
37+
successors(Some(a), move |&p| (p != b).then_some(p + displacement))
38+
})
39+
.collect();
40+
edges.is_disjoint(&red_zone)
3041
};
3142

32-
red_tiles
43+
let (a, b, area) = red_tiles
3344
.into_iter()
3445
.array_combinations()
3546
.map(|[a, b]| (a, b, rectangular_area(a, b)))
3647
.sorted_unstable_by(|(_, _, area_a), (_, _, area_b)| area_b.cmp(area_a))
37-
.filter(|&(a, b, _)| safe_rectangle(a, b))
38-
.map(|(_, _, area)| area)
39-
.next()
40-
.unwrap()
41-
}
48+
.find(|&(a, b, _)| safe_rectangle(a, b))
49+
.unwrap();
50+
println!("Largest rectangle is ({a}, {b}) area: {area}");
4251

43-
fn build_red_zone(red_tiles: &[Pt]) -> HashSet<Pt> {
44-
let path_tiles: HashSet<_> = red_tiles
45-
.iter()
46-
.copied()
47-
.chain(once(red_tiles[0]))
48-
.tuple_windows()
49-
.flat_map(|(a, b)| {
50-
let displacement = Pt::new((b.x - a.x).signum(), (b.y - a.y).signum());
51-
successors(Some(a), move |&p| (p != b).then_some(p + displacement))
52-
.chain(once(b))
53-
})
54-
.collect();
55-
let path_tiles = &path_tiles;
52+
{
53+
let red_tiles = input();
54+
let min_x = red_tiles.iter().map(|a| a.x).min().unwrap() - 2;
55+
let max_x = red_tiles.iter().map(|a| a.x).max().unwrap() - 2;
56+
let min_y = red_tiles.iter().map(|a| a.y).min().unwrap() + 2;
57+
let max_y = red_tiles.iter().map(|a| a.y).max().unwrap() + 2;
58+
let red_tiles: HashSet<_> = red_tiles.iter().copied().collect();
59+
let corners = vec![
60+
Pt::new(min(a.x, b.x), min(a.y, b.y)),
61+
Pt::new(max(a.x, b.x), min(a.y, b.y)),
62+
Pt::new(max(a.x, b.x), max(a.y, b.y)),
63+
Pt::new(max(a.x, b.x), min(a.y, b.y)),
64+
Pt::new(min(a.x, b.x), min(a.y, b.y)),
65+
];
66+
let edges: BTreeSet<_> = corners
67+
.into_iter()
68+
.tuple_windows()
69+
.flat_map(|(a, b)| {
70+
let displacement = Pt::new((b.x - a.x).signum(), (b.y - a.y).signum());
71+
successors(Some(a), move |&p| (p != b).then_some(p + displacement))
72+
})
73+
.collect();
5674

57-
println!("Path tiles count: {}", path_tiles.len());
75+
for y in min_x..=max_y {
76+
for x in min_y..=max_x {
77+
let pt = Pt::new(x, y);
78+
if red_tiles.contains(&pt) {
79+
print!("#");
80+
} else if red_zone.contains(&pt) {
81+
print!("!");
82+
} else if edges.contains(&pt) {
83+
print!("O");
84+
} else {
85+
print!(".");
86+
}
87+
}
88+
println!();
89+
}
90+
println!();
91+
}
5892

93+
area
94+
}
95+
96+
fn build_red_zone(red_tiles: &[Pt]) -> impl Iterator<Item = Pt> + use<'_> {
5997
let starting_point = red_tiles
6098
.iter()
6199
.sorted_by(|a, b| a.x.cmp(&b.x).then(a.y.cmp(&b.y)))
62100
.copied()
63101
.next()
64102
.unwrap();
65103

66-
println!("Starting point: {starting_point}");
67-
68-
let starting_turtle = Turtle::new(starting_point, Direction4::Right);
69-
let turtle_path = successors(Some((starting_turtle, 0usize)), move |&(t, i)| {
70-
if t == starting_turtle && i != 0 {
71-
return None;
72-
}
73-
Some([t, t.turn_left(), t.turn_right()]
74-
.iter()
75-
.map(|next| (next.advance(), i + 1))
76-
.find(|(next, _)| path_tiles.contains(&next.position))
77-
.unwrap())
78-
});
79-
80-
let red_zone: HashSet<_> = turtle_path
81-
.map(|(turtle, _)| turtle.turn_left().advance())
82-
.filter(|turtle| !path_tiles.contains(&turtle.position))
83-
.map(|turtle| turtle.position)
84-
.collect();
85-
86-
if !red_zone.is_empty() {
87-
println!("Red zone tiles count: {}", red_zone.len());
88-
}
89-
90-
red_zone
104+
red_tiles
105+
.iter()
106+
.copied()
107+
.cycle()
108+
.skip_while(move |&p| p != starting_point)
109+
.enumerate()
110+
.take_while(move |&(i, p)| i == 0 || p != starting_point)
111+
.map(|(_, p)| p)
112+
.tuple_windows()
113+
.flat_map(|(a, b)| {
114+
let direction = match ((b.x - a.x).signum(), (b.y - a.y).signum()) {
115+
(1, 0) => Direction4::Right,
116+
(0, 1) => Direction4::Down,
117+
(-1, 0) => Direction4::Left,
118+
(0, -1) => Direction4::Up,
119+
_ => unreachable!(),
120+
};
121+
successors(Some(a), move |&p| (p != b).then_some(p + direction))
122+
.skip(1)
123+
.map(move |p| p + (direction.turn_left()))
124+
})
91125
}
92126

93127
fn input() -> Vec<Pt> {

0 commit comments

Comments
 (0)