Skip to content

Commit 3342276

Browse files
committed
Day 6 (unoptimized)
1 parent cea0792 commit 3342276

File tree

3 files changed

+161
-9
lines changed

3 files changed

+161
-9
lines changed

README.md

+10-9
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,16 @@ Solutions for [Advent of Code](https://adventofcode.com/) in [Rust](https://www.
1919
<!--- benchmarking table --->
2020
## Benchmarks
2121

22-
| Day | Part 1 | Part 2 |
23-
| :---: | :---: | :---: |
24-
| [Day 1](./src/bin/01.rs) | `61.4µs` | `106.8µs` |
25-
| [Day 2](./src/bin/02.rs) | `220.6µs` | `404.8µs` |
26-
| [Day 3](./src/bin/03.rs) | `561.0µs` | `565.5µs` |
27-
| [Day 4](./src/bin/04.rs) | `560.8µs` | `161.9µs` |
28-
| [Day 5](./src/bin/05.rs) | `340.4µs` | `328.0µs` |
29-
30-
**Total: 3.31ms**
22+
| Day | Part 1 | Part 2 |
23+
|:---------------------------------------:| :---: | :---: |
24+
| [Day 1](./src/bin/01.rs) | `61.4µs` | `106.8µs` |
25+
| [Day 2](./src/bin/02.rs) | `220.6µs` | `404.8µs` |
26+
| [Day 3](./src/bin/03.rs) | `561.0µs` | `565.5µs` |
27+
| [Day 4](./src/bin/04.rs) | `560.8µs` | `161.9µs` |
28+
| [Day 5](./src/bin/05.rs) | `344.6µs` | `323.6µs` |
29+
| [Day 6](./src/bin/06.rs) (unoptimized) | `494.4µs` | `956.4ms` |
30+
31+
**Total: 960.21ms**
3132
<!--- benchmarking table --->
3233

3334
---

data/examples/06.txt

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
....#.....
2+
.........#
3+
..........
4+
..#.......
5+
.......#..
6+
..........
7+
.#..^.....
8+
........#.
9+
#.........
10+
......#...

src/bin/06.rs

+141
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
use std::collections::HashSet;
2+
use itertools::Itertools;
3+
4+
advent_of_code::solution!(6);
5+
6+
struct Map {
7+
dimensions: (isize, isize),
8+
obstacles: HashSet<(isize, isize)>,
9+
visited_pos: HashSet<(isize, isize)>,
10+
starting_pos: (isize, isize),
11+
}
12+
13+
impl Map {
14+
15+
fn parse(input: &str) -> Map {
16+
let (mut columns, mut rows) = (0, 0);
17+
let mut starting_pos = (0, 0);
18+
let mut obstacles = HashSet::new();
19+
let visited_pos = HashSet::new();
20+
input.lines()
21+
.enumerate()
22+
.map(|(y, line)| {
23+
rows = y;
24+
line.chars()
25+
.enumerate()
26+
.map(|(x, char)| {
27+
columns = x;
28+
match char {
29+
'^' => starting_pos = (x as isize, y as isize),
30+
'#' => {
31+
obstacles.insert((x as isize, y as isize));
32+
}
33+
_ => {}
34+
}
35+
char
36+
})
37+
.collect_vec()
38+
})
39+
.collect_vec();
40+
Map {
41+
dimensions: (columns as isize + 1, rows as isize + 1),
42+
obstacles,
43+
visited_pos,
44+
starting_pos,
45+
}
46+
}
47+
48+
fn is_obstacle(&self, pos: &(isize, isize)) -> bool {
49+
self.obstacles.contains(pos)
50+
}
51+
52+
fn farthest_point(&mut self, starting_pos: &(isize, isize), direction: &(isize, isize)) -> Option<(isize, isize)> {
53+
let mut pos = *starting_pos;
54+
while self.is_in_map(&pos) {
55+
self.visited_pos.insert(pos);
56+
let next_pos = (pos.0 + direction.0, pos.1 + direction.1);
57+
if self.is_obstacle(&next_pos) {
58+
return Some(pos);
59+
}
60+
pos = next_pos;
61+
}
62+
None
63+
}
64+
65+
fn is_in_map(&self, pos: &(isize, isize)) -> bool {
66+
(0..self.dimensions.0).contains(&pos.0) && (0..self.dimensions.1).contains(&pos.1)
67+
}
68+
69+
fn predict_path(&mut self) -> bool {
70+
let mut current_pos = self.starting_pos;
71+
let mut direction = 0;
72+
while let Some(next_pos) = self.farthest_point(&current_pos, &DIRECTIONS[direction]) {
73+
direction = (direction + 1) % 4;
74+
current_pos = next_pos;
75+
}
76+
false
77+
}
78+
79+
fn has_loop(&mut self) -> bool {
80+
let mut current_pos = self.starting_pos;
81+
let mut direction = 0;
82+
let mut turns = HashSet::new();
83+
while let Some(next_pos) = self.farthest_point(&current_pos, &DIRECTIONS[direction]) {
84+
if turns.contains(&(current_pos, direction)) {
85+
return true;
86+
}
87+
turns.insert((current_pos, direction));
88+
direction = (direction + 1) % 4;
89+
current_pos = next_pos;
90+
}
91+
false
92+
}
93+
94+
}
95+
96+
const DIRECTIONS: [(isize, isize); 4] = [
97+
(0, -1),
98+
(1, 0),
99+
(0, 1),
100+
(-1, 0),
101+
];
102+
103+
pub fn part_one(input: &str) -> Option<u32> {
104+
let mut map = Map::parse(input);
105+
map.predict_path();
106+
Some(map.visited_pos.len() as u32)
107+
}
108+
109+
pub fn part_two(input: &str) -> Option<u32> {
110+
let mut obstructions = 0;
111+
let mut map = Map::parse(input);
112+
map.predict_path();
113+
let mut original_path = map.visited_pos;
114+
original_path.remove(&map.starting_pos);
115+
for pos in original_path {
116+
map.obstacles.insert(pos);
117+
map.visited_pos = HashSet::new();
118+
if map.has_loop() {
119+
obstructions += 1;
120+
}
121+
map.obstacles.remove(&pos);
122+
}
123+
Some(obstructions)
124+
}
125+
126+
#[cfg(test)]
127+
mod tests {
128+
use super::*;
129+
130+
#[test]
131+
fn test_part_one() {
132+
let result = part_one(&advent_of_code::template::read_file("examples", DAY));
133+
assert_eq!(result, Some(41));
134+
}
135+
136+
#[test]
137+
fn test_part_two() {
138+
let result = part_two(&advent_of_code::template::read_file("examples", DAY));
139+
assert_eq!(result, Some(6));
140+
}
141+
}

0 commit comments

Comments
 (0)