Skip to content

Commit 9063166

Browse files
committed
Day 10
1 parent a8f86f8 commit 9063166

File tree

2 files changed

+195
-1
lines changed

2 files changed

+195
-1
lines changed

src/day10.rs

Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
use std::{collections::HashSet, fs};
2+
3+
pub fn day10(input_path: String) {
4+
let content = fs::read_to_string(input_path).unwrap();
5+
6+
let map = Map::new(&content);
7+
8+
println!("{:?}", part1(&map));
9+
println!("{:?}", part2(&map));
10+
}
11+
12+
fn part1(map: &Map) -> usize {
13+
map.iter()
14+
// These are the trailheads
15+
.filter_map(|(p, v)| if v == 0 { Some(p) } else { None })
16+
.map(|p| map.reachable_from(p).filter(|&p| map.at(p) == 9).count())
17+
.sum()
18+
}
19+
20+
fn part2(map: &Map) -> usize {
21+
map.iter()
22+
// These are the trailheads
23+
.filter_map(|(p, v)| if v == 0 { Some(p) } else { None })
24+
.map(|p| map.all_paths_from(p).filter(|&p| map.at(p) == 9).count())
25+
.sum()
26+
}
27+
28+
type Position = (usize, usize);
29+
30+
#[derive(Debug)]
31+
struct Map {
32+
data: Vec<Vec<u32>>,
33+
max: Position,
34+
}
35+
36+
impl Map {
37+
fn new(s: &str) -> Map {
38+
let data: Vec<Vec<_>> = s
39+
.lines()
40+
.map(|l| l.chars().map(|c| c.to_digit(10).unwrap()).collect())
41+
.collect();
42+
43+
// 0-size Maps are disallowed
44+
let max = (data.len(), data[0].len());
45+
46+
data.iter().for_each(|l| {
47+
if l.len() != max.1 {
48+
panic!();
49+
}
50+
});
51+
Map { data, max }
52+
}
53+
54+
fn at(&self, p: Position) -> u32 {
55+
self.data[p.0][p.1]
56+
}
57+
58+
fn neighbors(&self, p: Position) -> Vec<Position> {
59+
let mut neighbors = Vec::new();
60+
if p.0 > 0 {
61+
neighbors.push((p.0 - 1, p.1));
62+
}
63+
if p.0 < self.max.0 - 1 {
64+
neighbors.push((p.0 + 1, p.1))
65+
}
66+
if p.1 > 0 {
67+
neighbors.push((p.0, p.1 - 1));
68+
}
69+
if p.1 < self.max.1 - 1 {
70+
neighbors.push((p.0, p.1 + 1))
71+
}
72+
neighbors
73+
}
74+
75+
fn reachable_neighbors(&self, p: Position) -> Vec<Position> {
76+
let here = self.at(p);
77+
self.neighbors(p)
78+
.into_iter()
79+
.filter(|&p| here + 1 == self.at(p))
80+
.collect()
81+
}
82+
83+
fn iter(&self) -> MapIter {
84+
self.into_iter()
85+
}
86+
87+
fn reachable_from(&self, p: Position) -> PathIter {
88+
PathIter::new(self, p)
89+
}
90+
91+
fn all_paths_from(&self, p: Position) -> AllPathIter {
92+
AllPathIter::new(self, p)
93+
}
94+
}
95+
96+
impl<'a> IntoIterator for &'a Map {
97+
type Item = (Position, u32);
98+
type IntoIter = MapIter<'a>;
99+
100+
fn into_iter(self) -> Self::IntoIter {
101+
MapIter::new(self)
102+
}
103+
}
104+
105+
struct MapIter<'a> {
106+
map: &'a Map,
107+
current: Position,
108+
}
109+
110+
impl<'a> MapIter<'a> {
111+
fn new(map: &'a Map) -> MapIter<'a> {
112+
MapIter {
113+
map,
114+
current: (0, 0),
115+
}
116+
}
117+
}
118+
119+
impl<'a> Iterator for MapIter<'a> {
120+
type Item = (Position, u32);
121+
122+
fn next(&mut self) -> Option<Self::Item> {
123+
let mut next = (self.current.0, self.current.1 + 1);
124+
if next.1 >= self.map.max.1 {
125+
next.0 += 1;
126+
next.1 = 0;
127+
}
128+
if next.0 >= self.map.max.0 {
129+
return None;
130+
}
131+
self.current = next;
132+
Some((self.current, self.map.at(self.current)))
133+
}
134+
}
135+
136+
struct PathIter<'a> {
137+
map: &'a Map,
138+
visited: HashSet<Position>,
139+
todo: Vec<Position>,
140+
}
141+
142+
impl<'a> PathIter<'a> {
143+
fn new(map: &'a Map, start: Position) -> PathIter<'a> {
144+
PathIter {
145+
map,
146+
visited: HashSet::new(),
147+
todo: vec![start],
148+
}
149+
}
150+
}
151+
152+
impl<'a> Iterator for PathIter<'a> {
153+
type Item = Position;
154+
155+
fn next(&mut self) -> Option<Self::Item> {
156+
while let Some(here) = self.todo.pop() {
157+
if self.visited.insert(here) {
158+
self.todo
159+
.extend_from_slice(&self.map.reachable_neighbors(here));
160+
return Some(here);
161+
}
162+
}
163+
None
164+
}
165+
}
166+
167+
struct AllPathIter<'a> {
168+
map: &'a Map,
169+
todo: Vec<Position>,
170+
}
171+
172+
impl<'a> AllPathIter<'a> {
173+
fn new(map: &'a Map, start: Position) -> AllPathIter<'a> {
174+
AllPathIter {
175+
map,
176+
todo: vec![start],
177+
}
178+
}
179+
}
180+
181+
impl<'a> Iterator for AllPathIter<'a> {
182+
type Item = Position;
183+
184+
fn next(&mut self) -> Option<Self::Item> {
185+
while let Some(here) = self.todo.pop() {
186+
self.todo
187+
.extend_from_slice(&self.map.reachable_neighbors(here));
188+
return Some(here);
189+
}
190+
None
191+
}
192+
}

src/main.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ mod day06;
1111
mod day07;
1212
mod day08;
1313
mod day09;
14+
mod day10;
1415

1516
#[derive(Parser)]
1617
struct Args {
@@ -32,6 +33,7 @@ fn main() {
3233
6 => day06::day06(args.input_path),
3334
7 => day07::day07(args.input_path),
3435
8 => day08::day08(args.input_path),
35-
_ => day09::day09(args.input_path),
36+
9 => day09::day09(args.input_path),
37+
_ => day10::day10(args.input_path),
3638
}
3739
}

0 commit comments

Comments
 (0)