Skip to content

Commit a6a8e1e

Browse files
committed
chore: y2025::day_09
1 parent 3eb8a61 commit a6a8e1e

File tree

5 files changed

+124
-2
lines changed

5 files changed

+124
-2
lines changed

.run/run_aoc.run.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<component name="ProjectRunConfigurationManager">
22
<configuration default="false" name="run_aoc" type="CargoCommandRunConfiguration" factoryName="Cargo Command">
33
<option name="buildProfileId" value="dev" />
4-
<option name="command" value="run --package aoclp_solutions --bin aoclp_solutions -- --year 2025 --day 8" />
4+
<option name="command" value="run --package aoclp_solutions --bin aoclp_solutions -- --year 2025 --day 9" />
55
<option name="workingDirectory" value="file://$PROJECT_DIR$" />
66
<envs />
77
<option name="emulateTerminal" value="true" />

aoclp/src/positioning/pt.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,15 @@ where
177177
(a.x - b.x).abs() + (a.y - b.y).abs()
178178
}
179179

180+
/// Returns the size of the rectangle formed between two points in 2D space,
181+
/// as if the points were two of the rectangle's opposing corners.
182+
pub fn rectangular_area<T>(a: Pt<T>, b: Pt<T>) -> T
183+
where
184+
T: Signed,
185+
{
186+
((a.x - b.x).abs() + T::one()) * ((a.y - b.y).abs() + T::one())
187+
}
188+
180189
/// Given a two-dimensional matrix of elements, returns a map of
181190
/// [`Pt`] associated with the element at that position in the matrix.
182191
pub fn matrix_to_map<T, M, R, PT>(matrix: M) -> HashMap<Pt<PT>, T>

aoclp_solutions/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,5 @@ pub mod y2025;
1111
build_solvers! {
1212
{ 2017, [01, 02, 03, 04, 05, 06, 07, 08, 09, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25] },
1313
{ 2024, [01, 02, 03, 04, 05, 06, 07, 08, 09, 10] },
14-
{ 2025, [01, 02, 03, 04, 05, 06, 07, 08] }
14+
{ 2025, [01, 02, 03, 04, 05, 06, 07, 08, 09] }
1515
}
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
use std::cmp::{max, min};
2+
use std::collections::BTreeSet;
3+
use std::iter::successors;
4+
5+
use aoclp::positioning::direction::four_points::Direction4;
6+
use aoclp::positioning::direction::{Direction, MovementDirection};
7+
use aoclp::positioning::pt::{rectangular_area, Pt};
8+
use aoclp::solvers_impl::input::safe_get_input_as_many;
9+
use itertools::Itertools;
10+
use strum::IntoEnumIterator;
11+
12+
pub fn part_1() -> i64 {
13+
input()
14+
.into_iter()
15+
.array_combinations()
16+
.map(|[a, b]| rectangular_area(a, b))
17+
.max()
18+
.unwrap()
19+
}
20+
21+
pub fn part_2() -> i64 {
22+
let red_tiles = input();
23+
24+
let red_zone: BTreeSet<_> = build_red_zone(&red_tiles).collect();
25+
let safe_rectangle = |a: Pt, b: Pt| {
26+
let corners = vec![
27+
Pt::new(min(a.x, b.x), min(a.y, b.y)),
28+
Pt::new(max(a.x, b.x), min(a.y, b.y)),
29+
Pt::new(max(a.x, b.x), max(a.y, b.y)),
30+
Pt::new(min(a.x, b.x), max(a.y, b.y)),
31+
Pt::new(min(a.x, b.x), min(a.y, b.y)),
32+
];
33+
let edges: BTreeSet<_> = corners
34+
.into_iter()
35+
.tuple_windows()
36+
.flat_map(|(a, b)| {
37+
let displacement = Pt::new((b.x - a.x).signum(), (b.y - a.y).signum());
38+
successors(Some(a), move |&p| (p != b).then_some(p + displacement))
39+
})
40+
.collect();
41+
edges.is_disjoint(&red_zone)
42+
};
43+
44+
red_tiles
45+
.into_iter()
46+
.array_combinations()
47+
.map(|[a, b]| (a, b, rectangular_area(a, b)))
48+
.sorted_unstable_by(|(_, _, area_a), (_, _, area_b)| area_b.cmp(area_a))
49+
.find(|&(a, b, _)| safe_rectangle(a, b))
50+
.map(|(_, _, area)| area)
51+
.unwrap()
52+
}
53+
54+
fn build_red_zone(red_tiles: &[Pt]) -> impl Iterator<Item = Pt> + use<'_> {
55+
let starting_point = red_tiles
56+
.iter()
57+
.sorted_by(|a, b| a.x.cmp(&b.x).then(a.y.cmp(&b.y)))
58+
.copied()
59+
.next()
60+
.unwrap();
61+
62+
let get_direction = |a: Pt, b: Pt| {
63+
let displacement = Pt::new((b.x - a.x).signum(), (b.y - a.y).signum());
64+
Direction4::iter()
65+
.find(|&d| d.displacement() == displacement)
66+
.unwrap()
67+
};
68+
69+
red_tiles
70+
.iter()
71+
.copied()
72+
.cycle()
73+
.skip_while(move |&p| p != starting_point)
74+
.take(red_tiles.len() + 2)
75+
.tuple_windows()
76+
.flat_map(move |(a, b, c)| {
77+
let direction = get_direction(a, b);
78+
let turning_left = get_direction(b, c) == direction.turn_left();
79+
80+
let tail = if turning_left {
81+
vec![]
82+
} else {
83+
vec![
84+
b + direction.turn_left(),
85+
b + direction + direction.turn_left(),
86+
b + direction,
87+
]
88+
};
89+
90+
successors(Some(a), move |&p| {
91+
let next = p + direction;
92+
(next != b).then_some(next)
93+
})
94+
.skip(1)
95+
.map(move |p| p + (direction.turn_left()))
96+
.chain(tail)
97+
})
98+
}
99+
100+
const EXAMPLE: &str = "\
101+
7,1\n\
102+
11,1\n\
103+
11,7\n\
104+
9,7\n\
105+
9,5\n\
106+
2,5\n\
107+
2,3\n\
108+
7,3";
109+
110+
fn input() -> Vec<Pt> {
111+
safe_get_input_as_many(2025, 9)
112+
}

aoclp_solutions/src/y2025/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ pub mod day_05;
66
pub mod day_06;
77
pub mod day_07;
88
pub mod day_08;
9+
pub mod day_09;

0 commit comments

Comments
 (0)