-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathday10.rs
114 lines (94 loc) · 2.93 KB
/
day10.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
use std::collections::{HashSet, VecDeque};
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
struct Coordinate {
x: i32,
y: i32,
}
impl Coordinate {
pub fn from<T: TryInto<i32>, U: TryInto<i32>>(x: T, y: U) -> Self
where
T::Error: std::fmt::Debug,
U::Error: std::fmt::Debug,
{
Self {
x: x.try_into().unwrap(),
y: y.try_into().unwrap(),
}
}
fn neighbors(&self, boundary: i32) -> Vec<Coordinate> {
vec![
Coordinate::from(self.x - 1, self.y),
Coordinate::from(self.x, self.y + 1),
Coordinate::from(self.x + 1, self.y),
Coordinate::from(self.x, self.y - 1),
]
.into_iter()
.filter(|coord| coord.x >= 0 && coord.y >= 0 && coord.x < boundary && coord.y < boundary)
.collect()
}
}
#[derive(Debug, Clone)]
struct TrailMap {
map: Vec<Vec<u8>>,
start_locations: Vec<Coordinate>,
}
impl TrailMap {
pub fn from_input(input: &Vec<String>) -> Self {
let mut start_locations: Vec<Coordinate> = vec![];
let mut map: Vec<Vec<u8>> = vec![];
for (x, line) in input.iter().enumerate() {
let mut row: Vec<u8> = vec![];
for (y, score_char) in line.chars().enumerate() {
let score = score_char.to_digit(10).unwrap() as u8;
if score == 0 {
start_locations.push(Coordinate::from(x, y))
}
row.push(score);
}
map.push(row);
}
Self { map, start_locations }
}
fn size(&self) -> i32 {
self.map.len() as i32
}
fn score_at(&self, coordinate: &Coordinate) -> u8 {
self.map[coordinate.x as usize][coordinate.y as usize]
}
}
fn solve(start: Coordinate, map: &TrailMap, visit_all: bool) -> u32 {
let mut to_visit = VecDeque::from([start]);
let mut visited = HashSet::from([start]);
let mut count = 0;
let map_size = map.size();
while let Some(coordinate) = to_visit.pop_front() {
let score = map.score_at(&coordinate);
if score == 9 {
count += 1;
continue;
}
for neighbor_coordinate in coordinate.neighbors(map_size) {
if visit_all || !visited.contains(&neighbor_coordinate) {
if map.score_at(&neighbor_coordinate) == score + 1 {
visited.insert(neighbor_coordinate);
to_visit.push_back(neighbor_coordinate);
}
}
}
}
count
}
pub fn part1(input: &Vec<String>) -> i64 {
let map = TrailMap::from_input(input);
map.start_locations
.iter()
.map(|&start| solve(start, &map, false))
.sum::<u32>() as i64
}
pub fn part2(input: &Vec<String>) -> i64 {
let map = TrailMap::from_input(input);
map.start_locations
.iter()
.map(|&start| solve(start, &map, true))
.sum::<u32>() as i64
}