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 6 of AoC 2025
jonas.tngl.sh
3 months ago
90705f3d
4412d3ea
1/1
rust.yml
success
3mo ago
+194
-2
4 changed files
expand all
collapse all
unified
split
Cargo.lock
aoc_2025
Cargo.toml
src
day06.rs
main.rs
+1
Cargo.lock
···
149
149
"aoc_companion",
150
150
"aoc_utils",
151
151
"itertools",
152
152
+
"ndarray",
152
153
"num-traits",
153
154
"thiserror",
154
155
"tokio",
+1
aoc_2025/Cargo.toml
···
10
10
aoc_utils = { workspace = true }
11
11
anyhow = { workspace = true }
12
12
itertools = { workspace = true }
13
13
+
ndarray = { workspace = true }
13
14
num-traits = { workspace = true }
14
15
thiserror = { workspace = true }
15
16
tokio = { workspace = true }
+190
aoc_2025/src/day06.rs
···
1
1
+
use aoc_companion::prelude::*;
2
2
+
use itertools::Itertools as _;
3
3
+
4
4
+
#[derive(Debug, PartialEq, Eq)]
5
5
+
pub(crate) struct Door<'input> {
6
6
+
operands: ndarray::Array2<&'input str>,
7
7
+
operators: Vec<Op>,
8
8
+
}
9
9
+
10
10
+
impl<'input> Solution<'input> for Door<'input> {
11
11
+
fn parse(input: &'input str) -> Result<Self> {
12
12
+
let lines: Vec<_> = input.lines().collect();
13
13
+
let Some((operator_line, operand_lines)) = lines.split_last() else {
14
14
+
anyhow::bail!("homework is empty");
15
15
+
};
16
16
+
let column_offsets: Vec<usize> = operator_line
17
17
+
.as_bytes()
18
18
+
.iter()
19
19
+
.positions(|b| *b != b' ')
20
20
+
.collect();
21
21
+
let operators = operator_line
22
22
+
.split_ascii_whitespace()
23
23
+
.map(|op| match op {
24
24
+
"+" => Ok(Op::Add),
25
25
+
"*" => Ok(Op::Mul),
26
26
+
_ => Err(anyhow::anyhow!("invalid operator: {op:?}")),
27
27
+
})
28
28
+
.try_collect()?;
29
29
+
let operands = operand_lines
30
30
+
.iter()
31
31
+
.flat_map(|line| {
32
32
+
column_offsets
33
33
+
.iter()
34
34
+
.tuple_windows()
35
35
+
.map(|(&a, &b)| &line[a..(b - 1)])
36
36
+
.chain(std::iter::once(&line[*column_offsets.last().unwrap()..]))
37
37
+
})
38
38
+
.collect();
39
39
+
40
40
+
Ok(Door {
41
41
+
operands: ndarray::Array2::from_shape_vec(
42
42
+
(operand_lines.len(), column_offsets.len()),
43
43
+
operands,
44
44
+
)?,
45
45
+
operators,
46
46
+
})
47
47
+
}
48
48
+
49
49
+
fn part1(&self) -> Result<u64> {
50
50
+
Ok(self.to_human_math()?.solutions().iter().sum())
51
51
+
}
52
52
+
53
53
+
fn part2(&self) -> Result<u64> {
54
54
+
Ok(self.to_cephalopod_math()?.solutions().iter().sum())
55
55
+
}
56
56
+
}
57
57
+
58
58
+
impl Door<'_> {
59
59
+
fn to_human_math(&self) -> Result<Homework> {
60
60
+
let operands = self
61
61
+
.operands
62
62
+
.columns()
63
63
+
.into_iter()
64
64
+
.map(|col| col.iter().map(|s| s.trim().parse()).try_collect())
65
65
+
.try_collect()?;
66
66
+
Ok(Homework {
67
67
+
operands,
68
68
+
operators: self.operators.clone(),
69
69
+
})
70
70
+
}
71
71
+
72
72
+
fn to_cephalopod_math(&self) -> Result<Homework> {
73
73
+
let operands = self
74
74
+
.operands
75
75
+
.columns()
76
76
+
.into_iter()
77
77
+
.rev()
78
78
+
.map(|col| {
79
79
+
let width = col.get(0).map(|s| s.len()).unwrap_or_default();
80
80
+
(0..width)
81
81
+
.rev()
82
82
+
.map(|i| {
83
83
+
col.iter()
84
84
+
.map(|s| {
85
85
+
s.as_bytes()
86
86
+
.get(i)
87
87
+
.ok_or_else(|| anyhow::anyhow!("uneven column width"))
88
88
+
})
89
89
+
.filter_ok(|b| b.is_ascii_digit())
90
90
+
.try_fold(0, |acc, b| -> Result<u64> {
91
91
+
Ok(acc * 10 + u64::from(b? - b'0'))
92
92
+
})
93
93
+
})
94
94
+
.try_collect()
95
95
+
})
96
96
+
.try_collect()?;
97
97
+
Ok(Homework {
98
98
+
operands,
99
99
+
operators: self.operators.iter().cloned().rev().collect(),
100
100
+
})
101
101
+
}
102
102
+
}
103
103
+
104
104
+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
105
105
+
enum Op {
106
106
+
Add,
107
107
+
Mul,
108
108
+
}
109
109
+
110
110
+
impl Op {
111
111
+
fn neutral_element(&self) -> u64 {
112
112
+
match self {
113
113
+
Op::Add => 0,
114
114
+
Op::Mul => 1,
115
115
+
}
116
116
+
}
117
117
+
}
118
118
+
119
119
+
struct Homework {
120
120
+
operands: Vec<Vec<u64>>,
121
121
+
operators: Vec<Op>,
122
122
+
}
123
123
+
124
124
+
impl Homework {
125
125
+
fn solutions(&self) -> Vec<u64> {
126
126
+
self.operands
127
127
+
.iter()
128
128
+
.zip(self.operators.iter())
129
129
+
.map(|(col, op)| {
130
130
+
col.iter().fold(
131
131
+
op.neutral_element(),
132
132
+
match op {
133
133
+
Op::Add => std::ops::Add::add,
134
134
+
Op::Mul => std::ops::Mul::mul,
135
135
+
},
136
136
+
)
137
137
+
})
138
138
+
.collect()
139
139
+
}
140
140
+
}
141
141
+
142
142
+
#[cfg(test)]
143
143
+
mod tests {
144
144
+
use super::*;
145
145
+
146
146
+
const EXAMPLE_INPUT: &str = "\
147
147
+
123 328 51 64
148
148
+
45 64 387 23
149
149
+
6 98 215 314
150
150
+
* + * + ";
151
151
+
152
152
+
#[test]
153
153
+
fn parse_example_input() {
154
154
+
assert_eq!(
155
155
+
Door::parse(EXAMPLE_INPUT).unwrap(),
156
156
+
Door {
157
157
+
operands: ndarray::array![
158
158
+
["123", "328", " 51", "64 "],
159
159
+
[" 45", "64 ", "387", "23 "],
160
160
+
[" 6", "98 ", "215", "314"],
161
161
+
],
162
162
+
operators: vec![Op::Mul, Op::Add, Op::Mul, Op::Add,]
163
163
+
}
164
164
+
)
165
165
+
}
166
166
+
167
167
+
#[test]
168
168
+
fn example_human_solutions() {
169
169
+
assert_eq!(
170
170
+
Door::parse(EXAMPLE_INPUT)
171
171
+
.unwrap()
172
172
+
.to_human_math()
173
173
+
.unwrap()
174
174
+
.solutions(),
175
175
+
[33210, 490, 4243455, 401]
176
176
+
);
177
177
+
}
178
178
+
179
179
+
#[test]
180
180
+
fn example_cephalopod_solutions() {
181
181
+
assert_eq!(
182
182
+
Door::parse(EXAMPLE_INPUT)
183
183
+
.unwrap()
184
184
+
.to_cephalopod_math()
185
185
+
.unwrap()
186
186
+
.solutions(),
187
187
+
[1058, 3253600, 625, 8544]
188
188
+
);
189
189
+
}
190
190
+
}
+2
-2
aoc_2025/src/main.rs
···
5
5
mod day03;
6
6
mod day04;
7
7
mod day05;
8
8
-
// mod day06;
8
8
+
mod day06;
9
9
// mod day07;
10
10
// mod day08;
11
11
// mod day09;
···
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),
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),