Skip to content

Commit 036ab12

Browse files
committed
Day 10
1 parent e6564f1 commit 036ab12

File tree

3 files changed

+138
-1
lines changed

3 files changed

+138
-1
lines changed

README.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,9 @@ Solutions for [Advent of Code](https://adventofcode.com/) in [Rust](https://www.
3434
| [Day 7](./src/bin/07.rs) | `80.3µs` | `113.7µs` |
3535
| [Day 8](./src/bin/08.rs) | `10.2µs` | `12.4µs` |
3636
| [Day 9](./src/bin/09.rs) | `2.9ms` | `49.1ms` |
37+
| [Day 10](./src/bin/10.rs) | `95.6µs` | `96.8µs` |
3738

38-
**Total: 175.92ms**
39+
**Total: 176.11ms**
3940
<!--- benchmarking table --->
4041

4142
---

data/examples/10.txt

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
89010123
2+
78121874
3+
87430965
4+
96549874
5+
45678903
6+
32019012
7+
01329801
8+
10456732

src/bin/10.rs

+128
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
use std::collections::HashSet;
2+
use itertools::Itertools;
3+
4+
advent_of_code::solution!(10);
5+
6+
const DIRECTIONS: [(isize, isize); 4] = [
7+
(0, -1),
8+
(1, 0),
9+
(0, 1),
10+
(-1, 0),
11+
];
12+
13+
#[derive(Debug)]
14+
struct Map {
15+
width: usize,
16+
height: usize,
17+
heightmap: Vec<u8>,
18+
trailheads: Vec<usize>,
19+
}
20+
21+
impl Map {
22+
fn parse(input: &str) -> Map {
23+
let width = input.lines().next().unwrap_or_default().len();
24+
let mut trailheads = Vec::new();
25+
let heightmap = input.lines()
26+
.flat_map(|line| line.chars())
27+
.map(|char| char.to_digit(10).unwrap() as u8)
28+
.enumerate()
29+
.map(|(index, height)| {
30+
if height == 0 { trailheads.push(index) }
31+
height
32+
})
33+
.collect_vec();
34+
let height = heightmap.len() / width;
35+
Map {
36+
height,
37+
width,
38+
heightmap,
39+
trailheads,
40+
}
41+
}
42+
43+
fn xy_to_index(&self, pos: (usize, usize)) -> Option<usize> {
44+
if (0..self.width).contains(&pos.0) && (0..self.height).contains(&pos.1) {
45+
Some(pos.1 * self.width + pos.0)
46+
} else {
47+
None
48+
}
49+
}
50+
51+
fn index_to_xy(&self, index: &usize) -> Option<(usize, usize)> {
52+
if index < &(self.width * self.height) {
53+
Some((index % self.width, index / self.width))
54+
} else {
55+
None
56+
}
57+
}
58+
59+
fn score(&self, pos: (usize, usize), current: u8, visited: &mut HashSet<(usize, usize)>) {
60+
if self.xy_to_index(pos).map(|index| self.heightmap[index]).is_none_or(|height| current != height) {
61+
return;
62+
}
63+
if current == 9 {
64+
visited.insert(pos);
65+
return;
66+
}
67+
for direction in DIRECTIONS {
68+
let Some(pos) = offset(&pos, &direction) else { continue };
69+
self.score(pos, current + 1, visited);
70+
}
71+
}
72+
73+
fn rating(&self, pos: (usize, usize), current: u8) -> u32 {
74+
if self.xy_to_index(pos).map(|index| self.heightmap[index]).is_none_or(|height| current != height) {
75+
return 0;
76+
}
77+
if current == 9 {
78+
return 1;
79+
}
80+
let mut sum = 0;
81+
for direction in DIRECTIONS {
82+
let Some(pos) = offset(&pos, &direction) else { continue };
83+
sum += self.rating(pos, current + 1);
84+
}
85+
sum
86+
}
87+
}
88+
89+
fn offset(pos: &(usize, usize), direction: &(isize, isize)) -> Option<(usize, usize)> {
90+
let x = pos.0.checked_add_signed(direction.0)?;
91+
let y = pos.1.checked_add_signed(direction.1)?;
92+
Some((x, y))
93+
}
94+
95+
pub fn part_one(input: &str) -> Option<u32> {
96+
let map = Map::parse(input);
97+
Some(map.trailheads.iter()
98+
.map(|trailhead| {
99+
let mut visited = HashSet::new();
100+
map.score(map.index_to_xy(trailhead).unwrap(), 0, &mut visited);
101+
visited.len() as u32
102+
})
103+
.sum())
104+
}
105+
106+
pub fn part_two(input: &str) -> Option<u32> {
107+
let map = Map::parse(input);
108+
Some(map.trailheads.iter()
109+
.map(|trailhead| map.rating(map.index_to_xy(trailhead).unwrap(), 0))
110+
.sum())
111+
}
112+
113+
#[cfg(test)]
114+
mod tests {
115+
use super::*;
116+
117+
#[test]
118+
fn test_part_one() {
119+
let result = part_one(&advent_of_code::template::read_file("examples", DAY));
120+
assert_eq!(result, Some(36));
121+
}
122+
123+
#[test]
124+
fn test_part_two() {
125+
let result = part_two(&advent_of_code::template::read_file("examples", DAY));
126+
assert_eq!(result, Some(81));
127+
}
128+
}

0 commit comments

Comments
 (0)