Skip to content

Commit be0df1f

Browse files
committed
Day 07
1 parent 49dba43 commit be0df1f

File tree

3 files changed

+162
-8
lines changed

3 files changed

+162
-8
lines changed

README.md

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,7 @@ By default, `cargo time` does not write to the readme. In order to do so, append
204204
| [Day 4](https://adventofcode.com/2025/day/4) |||
205205
| [Day 5](https://adventofcode.com/2025/day/5) |||
206206
| [Day 6](https://adventofcode.com/2025/day/6) |||
207+
| [Day 7](https://adventofcode.com/2025/day/7) |||
207208

208209
<!--- advent_readme_stars table --->
209210

@@ -213,13 +214,14 @@ By default, `cargo time` does not write to the readme. In order to do so, append
213214

214215
| Day | Part 1 | Part 2 |
215216
| :----------------------: | :-------: | :-------: |
216-
| [Day 1](./src/bin/01.rs) | `54.8µs` | `38.0µs` |
217-
| [Day 2](./src/bin/02.rs) | `27.5ms` | `117.3ms` |
218-
| [Day 3](./src/bin/03.rs) | `34.8µs` | `58.8µs` |
219-
| [Day 4](./src/bin/04.rs) | `123.5µs` | `4.0ms` |
220-
| [Day 5](./src/bin/05.rs) | `90.8µs` | `28.2µs` |
221-
| [Day 6](./src/bin/06.rs) | `146.8µs` | `69.3µs` |
222-
223-
**Total: 149.44ms**
217+
| [Day 1](./src/bin/01.rs) | `84.3µs` | `95.3µs` |
218+
| [Day 2](./src/bin/02.rs) | `45.9ms` | `188.4ms` |
219+
| [Day 3](./src/bin/03.rs) | `63.3µs` | `102.3µs` |
220+
| [Day 4](./src/bin/04.rs) | `204.2µs` | `5.9ms` |
221+
| [Day 5](./src/bin/05.rs) | `194.8µs` | `57.2µs` |
222+
| [Day 6](./src/bin/06.rs) | `202.3µs` | `139.5µs` |
223+
| [Day 7](./src/bin/07.rs) | `178.7µs` | `303.8µs` |
224+
225+
**Total: 241.83ms**
224226

225227
<!--- benchmarking table --->

data/examples/07.txt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
.......S.......
2+
...............
3+
.......^.......
4+
...............
5+
......^.^......
6+
...............
7+
.....^.^.^.....
8+
...............
9+
....^.^...^....
10+
...............
11+
...^.^...^.^...
12+
...............
13+
..^...^.....^..
14+
...............
15+
.^.^.^.^.^...^.
16+
...............

src/bin/07.rs

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
use std::collections::{HashMap, HashSet, VecDeque};
2+
3+
advent_of_code::solution!(7);
4+
5+
pub fn part_one(input: &str) -> Option<u64> {
6+
let grid = parse_grid(input);
7+
let start = find_start(&grid)?;
8+
let result = simulate_beams(&grid, start);
9+
Some(result)
10+
}
11+
12+
pub fn part_two(input: &str) -> Option<u64> {
13+
let grid = parse_grid(input);
14+
let start = find_start(&grid)?;
15+
16+
let mut memo = HashMap::new();
17+
let result = count_paths(&grid, start, &mut memo);
18+
19+
Some(result)
20+
}
21+
22+
fn parse_grid(input: &str) -> Vec<Vec<char>> {
23+
input.lines().map(|line| line.chars().collect()).collect()
24+
}
25+
26+
fn find_start(grid: &[Vec<char>]) -> Option<(usize, usize)> {
27+
for (row, line) in grid.iter().enumerate() {
28+
for (col, &ch) in line.iter().enumerate() {
29+
if ch == 'S' {
30+
return Some((row, col));
31+
}
32+
}
33+
}
34+
None
35+
}
36+
37+
fn simulate_beams(grid: &[Vec<char>], start: (usize, usize)) -> u64 {
38+
let mut count = 0;
39+
let mut active = VecDeque::new();
40+
let mut visited = HashSet::new();
41+
42+
active.push_back((start.0, start.1));
43+
44+
while let Some(beam_pos) = active.pop_front() {
45+
if let Some(splitter_pos) = find_next(grid, beam_pos)
46+
&& visited.insert(splitter_pos)
47+
{
48+
count += 1;
49+
add_split_beams(grid, splitter_pos, &mut active);
50+
}
51+
}
52+
53+
count
54+
}
55+
56+
fn find_next(grid: &[Vec<char>], start: (usize, usize)) -> Option<(usize, usize)> {
57+
let (mut row, col) = start;
58+
59+
loop {
60+
row += 1;
61+
62+
if row >= grid.len() || col >= grid[row].len() {
63+
return None;
64+
}
65+
66+
if grid[row][col] == '^' {
67+
return Some((row, col));
68+
}
69+
}
70+
}
71+
72+
fn add_split_beams(
73+
grid: &[Vec<char>],
74+
splitter: (usize, usize),
75+
beams: &mut VecDeque<(usize, usize)>,
76+
) {
77+
let (row, col) = splitter;
78+
79+
if col > 0 {
80+
beams.push_back((row, col - 1));
81+
}
82+
83+
if col < grid[row].len() - 1 {
84+
beams.push_back((row, col + 1));
85+
}
86+
}
87+
88+
fn count_paths(
89+
grid: &[Vec<char>],
90+
pos: (usize, usize),
91+
memo: &mut std::collections::HashMap<(usize, usize), u64>,
92+
) -> u64 {
93+
if let Some(&cached) = memo.get(&pos) {
94+
return cached;
95+
}
96+
97+
let result = if let Some(splitter) = find_next(grid, pos) {
98+
let (row, col) = splitter;
99+
let mut total = 0;
100+
101+
// Count paths going left
102+
if col > 0 {
103+
total += count_paths(grid, (row, col - 1), memo);
104+
}
105+
106+
// Count paths going right
107+
if col < grid[row].len() - 1 {
108+
total += count_paths(grid, (row, col + 1), memo);
109+
}
110+
111+
total
112+
} else {
113+
// Exited the grid - this counts as 1 timeline
114+
1
115+
};
116+
117+
memo.insert(pos, result);
118+
result
119+
}
120+
121+
#[cfg(test)]
122+
mod tests {
123+
use super::*;
124+
125+
#[test]
126+
fn test_part_one() {
127+
let result = part_one(&advent_of_code::template::read_file("examples", DAY));
128+
assert_eq!(result, Some(21));
129+
}
130+
131+
#[test]
132+
fn test_part_two() {
133+
let result = part_two(&advent_of_code::template::read_file("examples", DAY));
134+
assert_eq!(result, Some(40));
135+
}
136+
}

0 commit comments

Comments
 (0)