Skip to content

Commit 158fb3b

Browse files
committed
Add day 6 part 1 and 2
1 parent c99a200 commit 158fb3b

File tree

3 files changed

+358
-0
lines changed

3 files changed

+358
-0
lines changed

input_examples/day06.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
....#.....
2+
.........#
3+
..........
4+
..#.......
5+
.......#..
6+
..........
7+
.#..^.....
8+
........#.
9+
#.........
10+
......#...

src/days.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ mod day02;
44
mod day03;
55
mod day04;
66
mod day05;
7+
mod day06;
78

89
use common::generic_day::GenericDay;
910

@@ -19,6 +20,7 @@ pub fn run_day(day: u8, input_folder: String) {
1920
3 => run_my_day(day03::Day03::new(input_folder)),
2021
4 => run_my_day(day04::Day04::new(input_folder)),
2122
5 => run_my_day(day05::Day05::new(input_folder)),
23+
6 => run_my_day(day06::Day06::new(input_folder)),
2224
_ => panic!("Day not found!"),
2325
}
2426
}

src/days/day06.rs

Lines changed: 346 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,346 @@
1+
use std::collections::HashSet;
2+
use std::fs::File;
3+
use std::io::BufRead;
4+
use std::io::BufReader;
5+
use std::ops::Range;
6+
7+
use super::common::generic_day;
8+
use super::common::position::Position;
9+
10+
#[derive(Clone)]
11+
pub struct Day06 {
12+
input_file: String,
13+
positions_with_obstacle: HashSet<Position>,
14+
guard_initial_position: Position,
15+
grid_size: i64,
16+
}
17+
18+
impl Day06 {
19+
pub fn new(input_folder: String) -> Day06 {
20+
let mut day06: Day06 = Day06 {
21+
input_file: format!("{}/day06.txt", input_folder),
22+
positions_with_obstacle: HashSet::new(),
23+
guard_initial_position: Position::new(),
24+
grid_size: 0,
25+
};
26+
day06.parse_input();
27+
day06
28+
}
29+
30+
fn parse_line(&mut self, i: usize, line: String) {
31+
self.grid_size = line.len() as i64;
32+
for (j, char) in line.chars().enumerate() {
33+
match char {
34+
'#' => {
35+
self.positions_with_obstacle.insert(Position {
36+
x: j as i64,
37+
y: i as i64,
38+
});
39+
}
40+
'^' => {
41+
let position = Position {
42+
x: j as i64,
43+
y: i as i64,
44+
};
45+
self.guard_initial_position = position.clone();
46+
}
47+
48+
_ => (),
49+
}
50+
}
51+
}
52+
53+
fn parse_input(&mut self) {
54+
let mut i = 0;
55+
let _ = BufReader::new(File::open(&self.input_file).unwrap())
56+
.lines()
57+
.map(|x| x.unwrap())
58+
.map(|line| {
59+
self.parse_line(i, line);
60+
i += 1
61+
})
62+
.collect::<Vec<_>>();
63+
}
64+
65+
fn is_an_obstacle_present_in_the_direction_faced_by_the_guard(
66+
&self,
67+
guard_patrol_path: &mut GuardPatrolPath,
68+
) -> bool {
69+
let mut result = false;
70+
let mut smallest_diff = self.grid_size * 2;
71+
for obstacle in self.positions_with_obstacle.iter() {
72+
let x_diff = obstacle.x - guard_patrol_path.position.x;
73+
let y_diff = obstacle.y - guard_patrol_path.position.y;
74+
if (x_diff.abs() == x_diff * guard_patrol_path.direction[0])
75+
&& (y_diff.abs() == y_diff * guard_patrol_path.direction[1])
76+
{
77+
if !result || x_diff.abs() + y_diff.abs() < smallest_diff {
78+
guard_patrol_path.next_obstacle_position = obstacle.clone();
79+
smallest_diff = x_diff.abs() + y_diff.abs();
80+
}
81+
result = true;
82+
}
83+
}
84+
if !result {
85+
let next_obstacle_position: Position = match guard_patrol_path.direction {
86+
[0, -1] => Position {
87+
x: guard_patrol_path.position.x,
88+
y: -1,
89+
},
90+
[1, 0] => Position {
91+
x: self.grid_size,
92+
y: guard_patrol_path.position.y,
93+
},
94+
[0, 1] => Position {
95+
x: guard_patrol_path.position.x,
96+
y: self.grid_size,
97+
},
98+
[-1, 0] => Position {
99+
x: -1,
100+
y: guard_patrol_path.position.y,
101+
},
102+
_ => panic!("This should not happen!"),
103+
};
104+
guard_patrol_path.next_obstacle_position = next_obstacle_position.clone();
105+
}
106+
result
107+
}
108+
}
109+
110+
#[derive(Debug)]
111+
struct GuardPatrolPath {
112+
visited_positions: HashSet<Position>,
113+
next_obstacle_position: Position,
114+
position: Position,
115+
past_positions: HashSet<Position>,
116+
direction: [i64; 2],
117+
}
118+
119+
impl GuardPatrolPath {
120+
fn turn_guard_90degrees(&mut self) {
121+
match self.direction {
122+
[0, -1] => self.direction = [1, 0],
123+
[1, 0] => self.direction = [0, 1],
124+
[0, 1] => self.direction = [-1, 0],
125+
[-1, 0] => self.direction = [0, -1],
126+
_ => panic!("This should not happen!"),
127+
}
128+
}
129+
130+
fn walk_until_next_obstacle(&mut self) {
131+
if self.position.x == self.next_obstacle_position.x {
132+
let mut end_position = Position {
133+
x: self.position.x,
134+
y: 0,
135+
};
136+
let y_range: Range<i64>;
137+
138+
if self.position.y > self.next_obstacle_position.y {
139+
y_range = Range {
140+
start: self.next_obstacle_position.y + 1,
141+
end: self.position.y,
142+
};
143+
end_position.y = self.next_obstacle_position.y + 1;
144+
} else {
145+
y_range = Range {
146+
start: self.position.y,
147+
end: self.next_obstacle_position.y,
148+
};
149+
end_position.y = self.next_obstacle_position.y - 1;
150+
}
151+
152+
for y in y_range {
153+
self.visited_positions.insert(Position {
154+
x: self.position.x,
155+
y,
156+
});
157+
}
158+
159+
self.position = end_position.clone();
160+
} else {
161+
let x_range: Range<i64>;
162+
let mut end_position = Position {
163+
x: 0,
164+
y: self.position.y,
165+
};
166+
if self.position.x > self.next_obstacle_position.x {
167+
x_range = Range {
168+
start: self.next_obstacle_position.x + 1,
169+
end: self.position.x,
170+
};
171+
end_position.x = self.next_obstacle_position.x + 1;
172+
} else {
173+
x_range = Range {
174+
start: self.position.x,
175+
end: self.next_obstacle_position.x,
176+
};
177+
end_position.x = self.next_obstacle_position.x - 1;
178+
}
179+
180+
for x in x_range {
181+
self.visited_positions.insert(Position {
182+
x,
183+
y: self.position.y,
184+
});
185+
}
186+
187+
self.position = end_position.clone();
188+
}
189+
self.turn_guard_90degrees();
190+
}
191+
192+
fn walk_until_next_obstacle_part2(&mut self) {
193+
let end_position: Position;
194+
if self.position.x == self.next_obstacle_position.x {
195+
if self.position.y > self.next_obstacle_position.y {
196+
end_position = Position {
197+
x: self.position.x,
198+
y: self.next_obstacle_position.y + 1,
199+
}
200+
} else {
201+
end_position = Position {
202+
x: self.position.x,
203+
y: self.next_obstacle_position.y - 1,
204+
}
205+
}
206+
} else if self.position.x > self.next_obstacle_position.x {
207+
end_position = Position {
208+
x: self.next_obstacle_position.x + 1,
209+
y: self.position.y,
210+
};
211+
} else {
212+
end_position = Position {
213+
x: self.next_obstacle_position.x - 1,
214+
y: self.position.y,
215+
};
216+
}
217+
self.position = end_position.clone();
218+
self.turn_guard_90degrees();
219+
}
220+
}
221+
222+
impl generic_day::GenericDay for Day06 {
223+
fn part1(&self) -> i64 {
224+
let mut guard_patrol_path = GuardPatrolPath {
225+
visited_positions: HashSet::new(),
226+
next_obstacle_position: Position::new(),
227+
position: self.guard_initial_position.clone(),
228+
past_positions: HashSet::new(),
229+
direction: [0, -1],
230+
};
231+
guard_patrol_path
232+
.visited_positions
233+
.insert(self.guard_initial_position.clone());
234+
guard_patrol_path
235+
.past_positions
236+
.insert(self.guard_initial_position.clone());
237+
238+
loop {
239+
if self
240+
.is_an_obstacle_present_in_the_direction_faced_by_the_guard(&mut guard_patrol_path)
241+
{
242+
guard_patrol_path.walk_until_next_obstacle();
243+
} else {
244+
guard_patrol_path.walk_until_next_obstacle();
245+
break;
246+
}
247+
}
248+
249+
guard_patrol_path.visited_positions.len() as i64
250+
}
251+
252+
fn part2(&self) -> i64 {
253+
let mut result = 0;
254+
let mut guard_patrol_path = GuardPatrolPath {
255+
visited_positions: HashSet::new(),
256+
next_obstacle_position: Position::new(),
257+
position: self.guard_initial_position.clone(),
258+
past_positions: HashSet::new(),
259+
direction: [0, -1],
260+
};
261+
guard_patrol_path
262+
.visited_positions
263+
.insert(self.guard_initial_position.clone());
264+
guard_patrol_path
265+
.past_positions
266+
.insert(self.guard_initial_position.clone());
267+
268+
loop {
269+
if self
270+
.is_an_obstacle_present_in_the_direction_faced_by_the_guard(&mut guard_patrol_path)
271+
{
272+
guard_patrol_path.walk_until_next_obstacle();
273+
} else {
274+
guard_patrol_path.walk_until_next_obstacle();
275+
break;
276+
}
277+
}
278+
279+
let mut test_day = self.clone();
280+
guard_patrol_path
281+
.visited_positions
282+
.remove(&self.guard_initial_position);
283+
284+
for position in guard_patrol_path.visited_positions {
285+
if test_day.positions_with_obstacle.insert(position.clone()) {
286+
let guard_stuck_in_loop: bool;
287+
let mut new_guard_patrol_path = GuardPatrolPath {
288+
visited_positions: HashSet::new(),
289+
next_obstacle_position: Position::new(),
290+
position: test_day.guard_initial_position.clone(),
291+
past_positions: HashSet::new(),
292+
direction: [0, -1],
293+
};
294+
new_guard_patrol_path
295+
.past_positions
296+
.insert(new_guard_patrol_path.position.clone());
297+
298+
loop {
299+
if test_day.is_an_obstacle_present_in_the_direction_faced_by_the_guard(
300+
&mut new_guard_patrol_path,
301+
) {
302+
let previous_guard_position = new_guard_patrol_path.position.clone();
303+
new_guard_patrol_path.walk_until_next_obstacle_part2();
304+
305+
if !new_guard_patrol_path
306+
.past_positions
307+
.insert(new_guard_patrol_path.position.clone())
308+
&& previous_guard_position != new_guard_patrol_path.position
309+
{
310+
guard_stuck_in_loop = true;
311+
break;
312+
}
313+
} else {
314+
guard_stuck_in_loop = false;
315+
break;
316+
}
317+
}
318+
319+
if guard_stuck_in_loop {
320+
result += 1;
321+
}
322+
323+
test_day.positions_with_obstacle.remove(&position);
324+
}
325+
}
326+
result
327+
}
328+
}
329+
330+
#[cfg(test)]
331+
mod tests {
332+
use super::*;
333+
use crate::days::GenericDay;
334+
335+
#[test]
336+
fn result_part1() {
337+
let day06: Day06 = Day06::new(String::from("input_examples"));
338+
assert_eq!(day06.part1(), 41);
339+
}
340+
341+
#[test]
342+
fn result_part2() {
343+
let day06: Day06 = Day06::new(String::from("input_examples"));
344+
assert_eq!(day06.part2(), 6);
345+
}
346+
}

0 commit comments

Comments
 (0)