tangled
alpha
login
or
join now
jonas.tngl.sh
/
advent-of-code
0
fork
atom
Advent of Code solutions in Rust
0
fork
atom
overview
issues
pulls
pipelines
feat: day 2 of AoC 2025
jonas.tngl.sh
3 months ago
cd7c3f65
17dcb061
1/1
rust.yml
success
3mo ago
+116
-2
2 changed files
expand all
collapse all
unified
split
aoc_2025
src
day02.rs
main.rs
+114
aoc_2025/src/day02.rs
···
1
1
+
use std::ops::RangeInclusive;
2
2
+
3
3
+
use aoc_companion::prelude::*;
4
4
+
use itertools::Itertools as _;
5
5
+
use num_traits::Euclid as _;
6
6
+
7
7
+
pub(crate) struct Door {
8
8
+
ranges: Vec<RangeInclusive<u64>>,
9
9
+
}
10
10
+
11
11
+
impl<'input> Solution<'input> for Door {
12
12
+
fn parse(input: &'input str) -> Result<Door> {
13
13
+
parse_ranges(input).map(|ranges| Door { ranges })
14
14
+
}
15
15
+
16
16
+
fn part1(&self) -> u64 {
17
17
+
self.ranges
18
18
+
.iter()
19
19
+
.cloned()
20
20
+
.flatten()
21
21
+
.filter(is_simple_invalid_id)
22
22
+
.sum()
23
23
+
}
24
24
+
25
25
+
fn part2(&self) -> u64 {
26
26
+
self.ranges
27
27
+
.iter()
28
28
+
.cloned()
29
29
+
.flatten()
30
30
+
.filter(is_invalid_id)
31
31
+
.sum()
32
32
+
}
33
33
+
}
34
34
+
35
35
+
fn parse_ranges(s: &str) -> Result<Vec<RangeInclusive<u64>>> {
36
36
+
s.split(',')
37
37
+
.map(|r| {
38
38
+
let Some((lhs, rhs)) = r.split_once('-') else {
39
39
+
anyhow::bail!("missing '-' in range {r:?}");
40
40
+
};
41
41
+
Ok(lhs.parse()?..=rhs.parse()?)
42
42
+
})
43
43
+
.try_collect()
44
44
+
}
45
45
+
46
46
+
fn is_simple_invalid_id(n: &u64) -> bool {
47
47
+
let s = n.to_string();
48
48
+
let (mid, 0) = s.len().div_rem_euclid(&2) else {
49
49
+
return false;
50
50
+
};
51
51
+
let (lhs, rhs) = s.split_at(mid);
52
52
+
lhs == rhs
53
53
+
}
54
54
+
55
55
+
fn is_invalid_id(n: &u64) -> bool {
56
56
+
let s = n.to_string().into_bytes();
57
57
+
58
58
+
(1..=s.len() / 2)
59
59
+
.filter(|c| s.len().is_multiple_of(*c))
60
60
+
.any(|chunk_size| s.chunks(chunk_size).all_equal())
61
61
+
}
62
62
+
63
63
+
#[cfg(test)]
64
64
+
mod tests {
65
65
+
use super::*;
66
66
+
67
67
+
const EXAMPLE_INPUT: &str = "11-22,95-115,998-1012,1188511880-1188511890,222220-222224,1698522-1698528,446443-446449,38593856-38593862,565653-565659,824824821-824824827,2121212118-2121212124";
68
68
+
69
69
+
const EXAMPLE_RANGES: &[RangeInclusive<u64>] = &[
70
70
+
11..=22,
71
71
+
95..=115,
72
72
+
998..=1012,
73
73
+
1188511880..=1188511890,
74
74
+
222220..=222224,
75
75
+
1698522..=1698528,
76
76
+
446443..=446449,
77
77
+
38593856..=38593862,
78
78
+
565653..=565659,
79
79
+
824824821..=824824827,
80
80
+
2121212118..=2121212124,
81
81
+
];
82
82
+
83
83
+
#[test]
84
84
+
fn parse_ranges_in_example_input() {
85
85
+
assert_eq!(parse_ranges(EXAMPLE_INPUT).unwrap(), EXAMPLE_RANGES);
86
86
+
}
87
87
+
88
88
+
#[test]
89
89
+
fn find_simple_invalid_ids_in_ranges() {
90
90
+
itertools::assert_equal(
91
91
+
EXAMPLE_RANGES
92
92
+
.iter()
93
93
+
.cloned()
94
94
+
.flatten()
95
95
+
.filter(is_simple_invalid_id),
96
96
+
[11, 22, 99, 1010, 1188511885, 222222, 446446, 38593859],
97
97
+
);
98
98
+
}
99
99
+
100
100
+
#[test]
101
101
+
fn find_all_invalid_ids_in_ranges() {
102
102
+
itertools::assert_equal(
103
103
+
EXAMPLE_RANGES
104
104
+
.iter()
105
105
+
.cloned()
106
106
+
.flatten()
107
107
+
.filter(is_invalid_id),
108
108
+
[
109
109
+
11, 22, 99, 111, 999, 1010, 1188511885, 222222, 446446, 38593859, 565656,
110
110
+
824824824, 2121212121,
111
111
+
],
112
112
+
);
113
113
+
}
114
114
+
}
+2
-2
aoc_2025/src/main.rs
···
1
1
#![allow(refining_impl_trait_internal)]
2
2
3
3
mod day01;
4
4
-
// mod day02;
4
4
+
mod day02;
5
5
// mod day03;
6
6
// mod day04;
7
7
// mod day05;
···
19
19
async fn main() -> Result<()> {
20
20
aoc_main(&[
21
21
door!(2025-12-01 ~> day01),
22
22
-
// door!(2025-12-02 ~> day02),
22
22
+
door!(2025-12-02 ~> day02),
23
23
// door!(2025-12-03 ~> day03),
24
24
// door!(2025-12-04 ~> day04),
25
25
// door!(2025-12-05 ~> day05),