Skip to content

Commit f69df6e

Browse files
committed
chore: add y2024::day_08
1 parent 0fcaec5 commit f69df6e

File tree

5 files changed

+129
-5
lines changed

5 files changed

+129
-5
lines changed

aoclp/src/positioning/pt.rs

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
use std::collections::HashMap;
2+
use std::convert::Infallible;
23
use std::fmt::{Debug, Display, Formatter};
34
use std::hash::Hash;
4-
use std::ops::{Add, AddAssign, Sub, SubAssign};
5+
use std::ops::{Add, AddAssign, RangeBounds, Sub, SubAssign};
56
use std::str::FromStr;
67
use std::sync::OnceLock;
78

@@ -47,6 +48,19 @@ where
4748
}
4849
}
4950

51+
impl<T> Pt<T>
52+
where
53+
T: PartialOrd,
54+
{
55+
pub fn within<XR, YR>(&self, x_bounds: XR, y_bounds: YR) -> bool
56+
where
57+
XR: RangeBounds<T>,
58+
YR: RangeBounds<T>,
59+
{
60+
x_bounds.contains(&self.x) && y_bounds.contains(&self.y)
61+
}
62+
}
63+
5064
impl<T, U, V> From<(U, V)> for Pt<T>
5165
where
5266
U: Into<T>,
@@ -72,7 +86,7 @@ impl<T> FromStr for Pt<T>
7286
where
7387
T: FromStr,
7488
{
75-
type Err = ();
89+
type Err = Infallible;
7690

7791
/// Parses a [`Pt`] from a string in the form `(x, y)`.
7892
/// Parentheses and whitespace are optional.

aoclp/src/positioning/pt_3d.rs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1+
use std::convert::Infallible;
12
use std::fmt::{Display, Formatter};
2-
use std::ops::{Add, AddAssign, Sub, SubAssign};
3+
use std::ops::{Add, AddAssign, RangeBounds, Sub, SubAssign};
34
use std::str::FromStr;
45
use std::sync::OnceLock;
56

@@ -21,6 +22,20 @@ impl<T> Pt3d<T> {
2122
}
2223
}
2324

25+
impl<T> Pt3d<T>
26+
where
27+
T: PartialOrd,
28+
{
29+
pub fn within<XR, YR, ZR>(&self, x_bounds: XR, y_bounds: YR, z_bounds: ZR) -> bool
30+
where
31+
XR: RangeBounds<T>,
32+
YR: RangeBounds<T>,
33+
ZR: RangeBounds<T>,
34+
{
35+
x_bounds.contains(&self.x) && y_bounds.contains(&self.y) && z_bounds.contains(&self.z)
36+
}
37+
}
38+
2439
impl<T, U, V, W> From<(U, V, W)> for Pt3d<T>
2540
where
2641
U: Into<T>,
@@ -47,7 +62,7 @@ impl<T> FromStr for Pt3d<T>
4762
where
4863
T: FromStr,
4964
{
50-
type Err = ();
65+
type Err = Infallible;
5166

5267
/// Parses a [`Pt3d`] from a string in the form `(x, y, z)`.
5368
/// Parentheses and whitespace are optional.

aoclp_solutions/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,6 @@ pub mod y2025;
1010

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] },
13-
{ 2024, [01, 02, 03, 04, 05, 06, 07] },
13+
{ 2024, [01, 02, 03, 04, 05, 06, 07, 08] },
1414
{ 2025, [01, 02, 03] }
1515
}
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
use std::collections::HashMap;
2+
use std::iter::successors;
3+
use std::ops::Range;
4+
5+
use aoclp::positioning::pt::{matrix_to_map, Pt};
6+
use aoclp::solvers_impl::input::safe_get_input_as_terrain;
7+
use itertools::Itertools;
8+
9+
pub fn part_1() -> usize {
10+
Map::default().antinodes(false).count()
11+
}
12+
13+
pub fn part_2() -> usize {
14+
Map::default().antinodes(true).count()
15+
}
16+
17+
#[derive(Debug)]
18+
struct Map {
19+
x_bounds: Range<i64>,
20+
y_bounds: Range<i64>,
21+
antennas: HashMap<Pt, char>,
22+
}
23+
24+
impl Map {
25+
fn antinodes(&self, resonating: bool) -> impl Iterator<Item = Pt> {
26+
let antinodes = self
27+
.antennas
28+
.iter()
29+
.sorted_by_key(|&(_, &freq)| freq)
30+
.chunk_by(|&(_, &freq)| freq)
31+
.into_iter()
32+
.flat_map(|(_, antennas)| {
33+
let antennas = antennas.map(|(&pt, _)| pt).collect_vec();
34+
let antinodes = antennas
35+
.iter()
36+
.cartesian_product(antennas.iter())
37+
.filter(|(p1, p2)| p1 != p2)
38+
.flat_map(|(&p1, &p2)| {
39+
let antinodes = match resonating {
40+
true => self.resonating_antinodes_for(p1, p2).collect_vec(),
41+
false => self.dull_antinodes_for(p1, p2).collect_vec(),
42+
};
43+
antinodes.into_iter()
44+
})
45+
.collect_vec();
46+
antinodes.into_iter()
47+
})
48+
.unique()
49+
.filter(|pt| pt.within(self.x_bounds.clone(), self.y_bounds.clone()))
50+
.collect_vec();
51+
antinodes.into_iter()
52+
}
53+
54+
fn dull_antinodes_for(&self, p1: Pt, p2: Pt) -> impl Iterator<Item = Pt> {
55+
let diff = p1 - p2;
56+
let anti1 = p1 + diff;
57+
let anti2 = p2 - diff;
58+
[anti1, anti2].into_iter()
59+
}
60+
61+
fn resonating_antinodes_for(&self, p1: Pt, p2: Pt) -> impl Iterator<Item = Pt> + use<'_> {
62+
let diff = p1 - p2;
63+
let from_p1 = successors(Some(p1), move |&pt| {
64+
let next = pt + diff;
65+
next.within(self.x_bounds.clone(), self.y_bounds.clone())
66+
.then_some(next)
67+
});
68+
let from_p2 = successors(Some(p2), move |&pt| {
69+
let next = pt - diff;
70+
next.within(self.x_bounds.clone(), self.y_bounds.clone())
71+
.then_some(next)
72+
});
73+
from_p1.chain(from_p2)
74+
}
75+
}
76+
77+
impl Default for Map {
78+
fn default() -> Self {
79+
let antennas_matrix = input();
80+
81+
let y_bounds = 0..antennas_matrix.len() as i64;
82+
let x_bounds = 0..antennas_matrix[0].len() as i64;
83+
let antennas = matrix_to_map(antennas_matrix)
84+
.into_iter()
85+
.filter(|&(_, c)| c != '.')
86+
.collect();
87+
88+
Self { x_bounds, y_bounds, antennas }
89+
}
90+
}
91+
92+
fn input() -> Vec<Vec<char>> {
93+
safe_get_input_as_terrain(2024, 8)
94+
}

aoclp_solutions/src/y2024/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@ pub mod day_04;
55
pub mod day_05;
66
pub mod day_06;
77
pub mod day_07;
8+
pub mod day_08;

0 commit comments

Comments
 (0)