Skip to content

Commit 4374364

Browse files
committed
2025 09.2 TOO SLOW
1 parent 3ba4c17 commit 4374364

File tree

2 files changed

+202
-2
lines changed

2 files changed

+202
-2
lines changed

src/aoc/y2025/day09.rs

Lines changed: 190 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,12 @@
77
// <https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12>.
88
// See the Licence for the specific language governing permissions and limitations under the Licence.
99

10+
use std::{collections::HashMap, fmt::Display};
11+
1012
use itertools::Itertools;
13+
use num::Integer;
1114

12-
use crate::{AoCError, BigCoord2D, Coordinate};
15+
use crate::{AoCError, BigCoord2D, CommonGrid, Coordinate, Coordinate2D, symbols};
1316

1417
pub fn part_1(data: crate::DataIn) -> crate::AoCResult<String> {
1518
let coords: Vec<BigCoord2D> = data.map(|line| line.parse()).try_collect()?;
@@ -33,12 +36,197 @@ pub fn part_1(data: crate::DataIn) -> crate::AoCResult<String> {
3336
Ok(ret.to_string())
3437
}
3538

39+
/// Adapted from http://web.archive.org/web/20080812141848/http://local.wasp.uwa.edu.au/~pbourke/geometry/insidepoly/
40+
fn inside_polygon(point: BigCoord2D, polygon: &[BigCoord2D]) -> bool {
41+
polygon
42+
.iter()
43+
.tuple_windows()
44+
.filter(|(poly_a, poly_b)| {
45+
let poly_min = poly_a.get_min(poly_b);
46+
let poly_max = poly_a.get_max(poly_b);
47+
if point.y <= poly_min.y {
48+
// why does this only check y coords? who knows.
49+
return false;
50+
} else if point.x > poly_max.x || point.y > poly_max.y {
51+
return false;
52+
} else if poly_a.y == poly_b.y {
53+
// ????
54+
return false;
55+
}
56+
// mystery statement
57+
let xinters =
58+
(point.y - poly_a.y) * (poly_b.x - poly_a.x) / (poly_b.y - poly_a.y) + poly_a.x;
59+
poly_a.x == poly_b.x || point.x <= xinters
60+
})
61+
.count()
62+
.is_odd()
63+
}
64+
65+
fn cached_inside_polygon(
66+
point: BigCoord2D,
67+
polygon: &[BigCoord2D],
68+
prechecked: &mut HashMap<BigCoord2D, bool>,
69+
) -> bool {
70+
if let Some(result) = prechecked.get(&point) {
71+
return *result;
72+
}
73+
let result = inside_polygon(point, polygon);
74+
log::trace!(
75+
"Magic function says {point} is {} poly",
76+
if result { "inside" } else { "outside" }
77+
);
78+
prechecked.insert(point, result);
79+
result
80+
}
81+
82+
fn rectangulate(a: &BigCoord2D, b: &BigCoord2D) -> impl Iterator<Item = BigCoord2D> {
83+
log::trace!("wtf wtf {a} {b}");
84+
// I'm moderately sure I've written this code before but I don't know where it is
85+
(a.x..=b.x)
86+
.cartesian_product(a.y..=b.y)
87+
.map(BigCoord2D::from_tuple)
88+
.inspect(|c| log::trace!("wtf {c}"))
89+
}
90+
91+
pub fn part_2(data: crate::DataIn) -> crate::AoCResult<String> {
92+
let coords = {
93+
let mut coords: Vec<BigCoord2D> = data.map(|line| line.parse()).try_collect()?;
94+
// Make it into a closed polygon
95+
coords.push(coords[0]);
96+
coords
97+
};
98+
99+
let mut prechecked: HashMap<BigCoord2D, bool> = coords
100+
.iter()
101+
.tuple_windows()
102+
.flat_map(|(a, b)| {
103+
let (a, b) = (a.get_min(b), a.get_max(b));
104+
log::trace!("ye {a} {b}");
105+
if a.y == b.y {
106+
let y = a.y;
107+
(a.x..=b.x).map(|x| BigCoord2D { x, y }).collect_vec()
108+
} else {
109+
let x = a.x;
110+
(a.y..=b.y).map(|y| BigCoord2D { x, y }).collect_vec()
111+
}
112+
})
113+
.map(|c| (c, true))
114+
.collect();
115+
116+
// stupid test grid
117+
log::debug!("prechecked:\n{}", {
118+
use aoc_macros::VoidState;
119+
120+
use crate::SparseGrid;
121+
122+
#[derive(Debug, VoidState)]
123+
enum GridState {
124+
#[void]
125+
Void,
126+
Red,
127+
Green,
128+
}
129+
130+
impl Display for GridState {
131+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
132+
match self {
133+
Self::Void => symbols::SHADE_LIGHT,
134+
Self::Red => symbols::BLOCK,
135+
Self::Green => symbols::SHADE_MID,
136+
}
137+
.fmt(f)
138+
}
139+
}
140+
141+
let mut grid: SparseGrid<GridState, BigCoord2D> =
142+
prechecked.keys().map(|a| (*a, GridState::Green)).collect();
143+
144+
coords.iter().for_each(|c| {
145+
grid.set(*c, GridState::Red);
146+
});
147+
148+
grid
149+
});
150+
151+
let ret = coords
152+
.iter()
153+
.array_combinations()
154+
.map(|[a, b]| {
155+
let min = a.get_min(b);
156+
let max = a.get_max(b);
157+
((1 + max.x - min.x) * (1 + max.y - min.y), min, max)
158+
})
159+
.sorted_unstable()
160+
.rev()
161+
.inspect(|(dist, a, b)| {
162+
log::debug!("Square of area {dist} between {a} and {b}");
163+
})
164+
.find(|(_, a, b)| {
165+
rectangulate(a, b).all(|point| cached_inside_polygon(point, &coords, &mut prechecked))
166+
})
167+
.map(|(dist, _, _)| dist)
168+
.ok_or(AoCError::new("No valid rectangles?"))?;
169+
170+
// stupid test grid v2
171+
log::debug!("postchecked:\n{}", {
172+
use aoc_macros::VoidState;
173+
174+
use crate::SparseGrid;
175+
176+
#[derive(Debug, VoidState)]
177+
enum GridState {
178+
#[void]
179+
Void,
180+
Red,
181+
Green,
182+
White,
183+
}
184+
185+
impl Display for GridState {
186+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
187+
match self {
188+
Self::Void => symbols::VOID,
189+
Self::Red => symbols::BLOCK,
190+
Self::Green => symbols::SHADE_DARK,
191+
Self::White => symbols::SHADE_LIGHT,
192+
}
193+
.fmt(f)
194+
}
195+
}
196+
197+
let mut grid: SparseGrid<GridState, BigCoord2D> = prechecked
198+
.iter()
199+
.map(|(coord, state)| {
200+
(
201+
*coord,
202+
if *state {
203+
GridState::Green
204+
} else {
205+
GridState::White
206+
},
207+
)
208+
})
209+
.collect();
210+
211+
coords.iter().for_each(|c| {
212+
grid.set(*c, GridState::Red);
213+
});
214+
215+
grid
216+
});
217+
218+
Ok(ret.to_string())
219+
}
220+
36221
inventory::submit!(crate::AoCDay {
37222
year: "2025",
38223
day: "9",
39224
part_1: crate::AoCPart {
40225
main: part_1,
41226
example: part_1
42227
},
43-
part_2: None
228+
part_2: Some(crate::AoCPart {
229+
main: part_2,
230+
example: part_2,
231+
})
44232
});

src/utils/bigcoord2d.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,3 +304,15 @@ impl From<Direction> for BigCoord2D {
304304
(c.x, c.y).into()
305305
}
306306
}
307+
impl Ord for BigCoord2D {
308+
fn cmp(&self, other: &Self) -> cmp::Ordering {
309+
// Incredibly basic comparison - more numbers = more ord
310+
(self.x + self.y).cmp(&(other.x + other.y))
311+
}
312+
}
313+
314+
impl PartialOrd for BigCoord2D {
315+
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
316+
Some(self.cmp(other))
317+
}
318+
}

0 commit comments

Comments
 (0)