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 1 of AoC 2025
jonas.tngl.sh
3 months ago
17dcb061
0792beff
1/1
rust.yml
success
3m 7s
+150
-2
7 changed files
expand all
collapse all
unified
split
Cargo.lock
Cargo.toml
aoc_2020
Cargo.toml
aoc_2025
Cargo.toml
src
day01.rs
main.rs
aoc_utils
Cargo.toml
+12
Cargo.lock
···
142
142
]
143
143
144
144
[[package]]
145
145
+
name = "aoc_2025"
146
146
+
version = "0.1.0"
147
147
+
dependencies = [
148
148
+
"anyhow",
149
149
+
"aoc_companion",
150
150
+
"aoc_utils",
151
151
+
"itertools",
152
152
+
"num-traits",
153
153
+
"tokio",
154
154
+
]
155
155
+
156
156
+
[[package]]
145
157
name = "aoc_companion"
146
158
version = "0.1.0"
147
159
dependencies = [
+3
Cargo.toml
···
7
7
"aoc_2020",
8
8
"aoc_2022",
9
9
"aoc_2024",
10
10
+
"aoc_2025",
10
11
]
11
12
12
13
[workspace.dependencies]
···
17
18
enum-map = "2.7.3"
18
19
itertools = "0.14.0"
19
20
ndarray = "0.17.1"
21
21
+
num-integer = "0.1.46"
22
22
+
num-traits = "0.2.19"
20
23
proptest = { version = "1.9.0", default-features = false, features = ["std"] }
21
24
rayon = "1.11.0"
22
25
regex = "1.12.2"
+1
-1
aoc_2020/Cargo.toml
···
11
11
anyhow = { workspace = true }
12
12
itertools = { workspace = true }
13
13
ndarray = { workspace = true }
14
14
+
num-integer = { workspace = true }
14
15
regex = { workspace = true }
15
16
thiserror = { workspace = true }
16
17
tokio = { workspace = true }
17
17
-
num-integer = "0.1.46"
18
18
+14
aoc_2025/Cargo.toml
···
1
1
+
[package]
2
2
+
name = "aoc_2025"
3
3
+
version = "0.1.0"
4
4
+
edition = "2024"
5
5
+
6
6
+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7
7
+
8
8
+
[dependencies]
9
9
+
aoc_companion = { workspace = true }
10
10
+
aoc_utils = { workspace = true }
11
11
+
anyhow = { workspace = true }
12
12
+
itertools = { workspace = true }
13
13
+
num-traits = { workspace = true }
14
14
+
tokio = { workspace = true }
+84
aoc_2025/src/day01.rs
···
1
1
+
use anyhow::Context as _;
2
2
+
use aoc_companion::prelude::*;
3
3
+
use itertools::Itertools as _;
4
4
+
use num_traits::Euclid as _;
5
5
+
6
6
+
pub(crate) struct Door {
7
7
+
rotations: Vec<i32>,
8
8
+
}
9
9
+
10
10
+
impl<'input> Solution<'input> for Door {
11
11
+
fn parse(input: &'input str) -> Result<Self> {
12
12
+
Ok(Door {
13
13
+
rotations: input
14
14
+
.lines()
15
15
+
.map(|line| {
16
16
+
let Some((dir, angle)) = line.split_at_checked(1) else {
17
17
+
anyhow::bail!("unexpected empty line");
18
18
+
};
19
19
+
let angle: i32 = angle
20
20
+
.parse()
21
21
+
.with_context(|| anyhow::anyhow!("invalid rotation angle"))?;
22
22
+
match dir {
23
23
+
"L" => Ok(-angle),
24
24
+
"R" => Ok(angle),
25
25
+
_ => Err(anyhow::anyhow!("invalid rotation direction {dir:?}")),
26
26
+
}
27
27
+
})
28
28
+
.try_collect()?,
29
29
+
})
30
30
+
}
31
31
+
32
32
+
fn part1(&self) -> usize {
33
33
+
intermediate_angles(self.rotations.iter().copied())
34
34
+
.filter(|angle| *angle == 0)
35
35
+
.count()
36
36
+
}
37
37
+
38
38
+
fn part2(&self) -> i32 {
39
39
+
dial_crossings(self.rotations.iter().copied()).sum()
40
40
+
}
41
41
+
}
42
42
+
43
43
+
fn intermediate_angles(rotations: impl IntoIterator<Item = i32>) -> impl Iterator<Item = i32> {
44
44
+
rotations.into_iter().scan(50, |angle, rot| {
45
45
+
*angle = (*angle + rot).rem_euclid(100);
46
46
+
Some(*angle)
47
47
+
})
48
48
+
}
49
49
+
50
50
+
fn dial_crossings(rotations: impl IntoIterator<Item = i32>) -> impl Iterator<Item = i32> {
51
51
+
rotations.into_iter().scan(50, |angle, rot| {
52
52
+
let (div, new_angle) = (*angle + rot).div_rem_euclid(&100);
53
53
+
let correction = if rot < 0 {
54
54
+
(new_angle == 0) as i32 - (*angle == 0) as i32
55
55
+
} else {
56
56
+
0
57
57
+
};
58
58
+
*angle = new_angle;
59
59
+
Some(div.abs() + correction)
60
60
+
})
61
61
+
}
62
62
+
63
63
+
#[cfg(test)]
64
64
+
mod tests {
65
65
+
use super::*;
66
66
+
67
67
+
const EXAMPLE_ROTATIONS: &[i32] = &[-68, -30, 48, -5, 60, -55, -1, -99, 14, -82];
68
68
+
69
69
+
#[test]
70
70
+
fn intermediate_angles_in_example() {
71
71
+
itertools::assert_equal(
72
72
+
intermediate_angles(EXAMPLE_ROTATIONS.iter().copied()),
73
73
+
[82, 52, 0, 95, 55, 0, 99, 0, 14, 32],
74
74
+
);
75
75
+
}
76
76
+
77
77
+
#[test]
78
78
+
fn times_dial_reaches_zero() {
79
79
+
itertools::assert_equal(
80
80
+
dial_crossings(EXAMPLE_ROTATIONS.iter().copied()),
81
81
+
[1, 0, 1, 0, 1, 1, 0, 1, 0, 1],
82
82
+
);
83
83
+
}
84
84
+
}
+35
aoc_2025/src/main.rs
···
1
1
+
#![allow(refining_impl_trait_internal)]
2
2
+
3
3
+
mod day01;
4
4
+
// mod day02;
5
5
+
// mod day03;
6
6
+
// mod day04;
7
7
+
// mod day05;
8
8
+
// mod day06;
9
9
+
// mod day07;
10
10
+
// mod day08;
11
11
+
// mod day09;
12
12
+
// mod day10;
13
13
+
// mod day11;
14
14
+
// mod day12;
15
15
+
16
16
+
use aoc_companion::prelude::*;
17
17
+
18
18
+
#[tokio::main(flavor = "current_thread")]
19
19
+
async fn main() -> Result<()> {
20
20
+
aoc_main(&[
21
21
+
door!(2025-12-01 ~> day01),
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),
26
26
+
// door!(2025-12-06 ~> day06),
27
27
+
// door!(2025-12-07 ~> day07),
28
28
+
// door!(2025-12-08 ~> day08),
29
29
+
// door!(2025-12-09 ~> day09),
30
30
+
// door!(2025-12-10 ~> day10),
31
31
+
// door!(2025-12-11 ~> day11),
32
32
+
// door!(2025-12-12 ~> day12),
33
33
+
])
34
34
+
.await
35
35
+
}
+1
-1
aoc_utils/Cargo.toml
···
9
9
assert_matches = { workspace = true }
10
10
itertools = { workspace = true }
11
11
ndarray = { workspace = true }
12
12
-
num-traits = "0.2.19"
12
12
+
num-traits = { workspace = true }
13
13
paste = "1.0.15"
14
14
thiserror = { workspace = true }
15
15