tangled
alpha
login
or
join now
bwc9876.dev
/
advent
0
fork
atom
Advent of Code solutions
0
fork
atom
overview
issues
pulls
pipelines
Day 6
bwc9876.dev
1 year ago
aa0ed0d1
90981006
verified
This commit was signed with the committer's
known signature
.
bwc9876.dev
SSH Key Fingerprint:
SHA256:DanMEP/RNlSC7pAVbnXO6wzQV00rqyKj053tz4uH5gQ=
+210
-8
4 changed files
expand all
collapse all
unified
split
utils
src
grid.rs
years
2024
src
day_6.rs
examples
day_6
1.txt
2.txt
+57
-2
utils/src/grid.rs
···
1
1
+
use cursors::GridCursor;
2
2
+
1
3
use crate::{
2
4
dir::{Direction, Movement, CARDINALS},
3
5
pos::Position,
···
334
336
pub fn iter(&self) -> impl Iterator<Item = (Position, &T)> {
335
337
self.data.iter().enumerate().flat_map(|(y, row)| {
336
338
row.iter()
339
339
+
.enumerate()
340
340
+
.map(move |(x, col)| (Position::new(x as isize, y as isize), col))
341
341
+
})
342
342
+
}
343
343
+
344
344
+
/// Iterate over all elements of the grid.
345
345
+
///
346
346
+
/// This also yields the position of each element for easy access.
347
347
+
///
348
348
+
/// # Examples
349
349
+
///
350
350
+
/// ```
351
351
+
/// use utils::prelude::*;
352
352
+
///
353
353
+
/// let data = vec![
354
354
+
/// vec![1, 2, 3],
355
355
+
/// vec![4, 5, 6],
356
356
+
/// vec![7, 8, 9],
357
357
+
/// ];
358
358
+
///
359
359
+
/// let grid = Grid::new(data);
360
360
+
///
361
361
+
/// assert_eq!(grid.iter().map(|(_, v)| v).sum::<usize>(), 1+2+3+4+5+6+7+8+9);
362
362
+
/// ```
363
363
+
///
364
364
+
pub fn iter_mut(&mut self) -> impl Iterator<Item = (Position, &mut T)> {
365
365
+
self.data.iter_mut().enumerate().flat_map(|(y, row)| {
366
366
+
row.iter_mut()
337
367
.enumerate()
338
368
.map(move |(x, col)| (Position::new(x as isize, y as isize), col))
339
369
})
···
532
562
) -> impl Iterator<Item = ((Direction, usize), Position, &T)> {
533
563
self.relatives_expand_by_wrapped(pos, &CARDINALS, expand)
534
564
}
565
565
+
566
566
+
/// Create a new cursor for this grid facing in the specified direction at the specified
567
567
+
/// position
568
568
+
pub fn cursor<D: Movement>(&self, pos: Position, dir: D) -> GridCursor<T, D> {
569
569
+
GridCursor::new(self, pos, dir)
570
570
+
}
571
571
+
}
572
572
+
573
573
+
impl<T> Grid<T>
574
574
+
where
575
575
+
T: Eq,
576
576
+
{
577
577
+
pub fn find_tile(&self, tile: &T) -> Option<Position> {
578
578
+
self.iter()
579
579
+
.find_map(|(p, t)| if t == tile { Some(p) } else { None })
580
580
+
}
581
581
+
582
582
+
pub fn cursor_at<D: Movement>(&self, tile: &T, dir: D) -> Option<GridCursor<T, D>> {
583
583
+
self.find_tile(tile).map(|pos| self.cursor(pos, dir))
584
584
+
}
535
585
}
536
586
537
587
impl<T: std::fmt::Debug> std::fmt::Debug for Grid<T> {
···
742
792
///
743
793
pub struct GridCursor<'a, T, D: Movement> {
744
794
grid: &'a Grid<T>,
745
745
-
pos: Position,
746
746
-
dir: D,
795
795
+
pub pos: Position,
796
796
+
pub dir: D,
747
797
}
748
798
749
799
impl<'a, T> GridCursor<'a, T, Direction> {
···
789
839
/// Move the cursor forward one step in the direction it is facing.
790
840
pub fn move_forward(&mut self) {
791
841
self.pos = self.pos.move_dir(self.dir);
842
842
+
}
843
843
+
844
844
+
pub fn peek_forward(&self) -> Option<(Position, &T)> {
845
845
+
let next_pos = self.pos.move_dir(self.dir);
846
846
+
self.grid.get(next_pos).map(|value| (next_pos, value))
792
847
}
793
848
794
849
/// Get the value at the current position of the cursor.
+133
-6
years/2024/src/day_6.rs
···
1
1
+
use std::collections::HashSet;
1
2
2
2
-
use advent_core::{Day, day_stuff, ex_for_day};
3
3
+
use advent_core::{day_stuff, ex_for_day, Day};
4
4
+
use utils::{dir::Direction, pos::Position, prelude::GridCursor, tiles};
3
5
4
6
pub struct Day6;
5
7
8
8
+
tiles!(Tile, [
9
9
+
'.' => Floor,
10
10
+
'#' => Wall,
11
11
+
'^' => GuardStart
12
12
+
]);
13
13
+
14
14
+
impl Tile {
15
15
+
fn is_open(&self) -> bool {
16
16
+
matches!(self, Self::Floor | Self::GuardStart)
17
17
+
}
18
18
+
}
19
19
+
20
20
+
type Grid = utils::grid::Grid<Tile>;
21
21
+
22
22
+
/// Returns true if we get into a loop
23
23
+
fn crawl_grid_with_obs(mut curs: GridCursor<Tile, Direction>, obs_pos: Position) -> bool {
24
24
+
let mut visited = HashSet::new();
25
25
+
26
26
+
while let Some((pos, tile)) = curs.peek_forward() {
27
27
+
visited.insert((curs.pos, curs.dir));
28
28
+
if tile.is_open() && pos != obs_pos {
29
29
+
curs.move_forward();
30
30
+
} else {
31
31
+
curs.turn(true);
32
32
+
}
33
33
+
34
34
+
if visited.contains(&(curs.pos, curs.dir)) {
35
35
+
return true;
36
36
+
}
37
37
+
}
38
38
+
39
39
+
false
40
40
+
}
41
41
+
6
42
impl Day for Day6 {
43
43
+
day_stuff!(6, "41", "6", Grid);
44
44
+
45
45
+
fn part_1(input: Self::Input) -> Option<String> {
46
46
+
let mut curs = input
47
47
+
.cursor_at(&Tile::GuardStart, Direction::North)
48
48
+
.unwrap();
49
49
+
50
50
+
let mut visited = HashSet::with_capacity(input.width() * input.height());
51
51
+
52
52
+
while let Some((_next_pos, tile)) = curs.peek_forward() {
53
53
+
visited.insert(curs.pos);
54
54
+
if tile.is_open() {
55
55
+
curs.move_forward();
56
56
+
} else {
57
57
+
curs.turn(true);
58
58
+
}
59
59
+
}
60
60
+
61
61
+
// While let means we'll be missing one
62
62
+
visited.insert(curs.pos);
63
63
+
64
64
+
Some(visited.len().to_string())
65
65
+
}
66
66
+
67
67
+
fn part_2(input: Self::Input) -> Option<String> {
68
68
+
let mut curs = input
69
69
+
.cursor_at(&Tile::GuardStart, Direction::North)
70
70
+
.unwrap();
71
71
+
72
72
+
let start_curs = curs;
73
73
+
74
74
+
let mut obs = HashSet::with_capacity(input.width() * input.height());
7
75
8
8
-
day_stuff!(6, "", "");
76
76
+
while let Some((possible, tile)) = curs.peek_forward() {
77
77
+
if !obs.contains(&possible) {
78
78
+
let curs_2 = start_curs;
79
79
+
if crawl_grid_with_obs(curs_2, possible) {
80
80
+
obs.insert(possible);
81
81
+
}
82
82
+
}
9
83
10
10
-
fn part_1(_input: Self::Input) -> Option<String> {
11
11
-
None
84
84
+
if tile.is_open() {
85
85
+
curs.move_forward();
86
86
+
} else {
87
87
+
curs.turn(true);
88
88
+
}
89
89
+
}
90
90
+
91
91
+
Some(obs.len().to_string())
12
92
}
13
93
14
14
-
fn part_2(_input: Self::Input) -> Option<String> {
15
15
-
None
94
94
+
fn parse_input(input: &str) -> Self::Input {
95
95
+
Grid::parse(input)
16
96
}
17
97
}
98
98
+
99
99
+
// - ORIGINAL PART 2 : BRUTE FORCE APPROACH (Im so sad i had to do this) -
100
100
+
101
101
+
// let mut c = 0;
102
102
+
103
103
+
// let start_pos = input
104
104
+
// .iter()
105
105
+
// .find_map(|(pos, c)| {
106
106
+
// if matches!(c, Tile::GuardStart) {
107
107
+
// Some(pos)
108
108
+
// } else {
109
109
+
// None
110
110
+
// }
111
111
+
// })
112
112
+
// .unwrap();
113
113
+
114
114
+
// for x in 0..input.width() {
115
115
+
// for y in 0..input.height() {
116
116
+
// let pos = mpos!(x as isize, y as isize);
117
117
+
// if matches!(input.get(pos).unwrap(), Tile::Floor) {
118
118
+
// let mut i2 = input.clone();
119
119
+
// i2.iter_mut().for_each(|(pt, r)| if pt == pos { *r = Tile::Wall; });
120
120
+
// let mut curs = GridCursor::new(&i2, start_pos, Direction::North);
121
121
+
122
122
+
// let mut visited = HashSet::with_capacity(i2.width());
123
123
+
124
124
+
// loop {
125
125
+
// visited.insert((curs.pos, curs.dir));
126
126
+
// if let Some(val_ahead) = i2.get(curs.pos.move_dir(curs.dir)) {
127
127
+
// if val_ahead.is_open() {
128
128
+
// curs.move_forward();
129
129
+
// } else {
130
130
+
// curs.turn(true);
131
131
+
// }
132
132
+
// if visited.contains(&(curs.pos, curs.dir)) {
133
133
+
// c += 1;
134
134
+
// break;
135
135
+
// }
136
136
+
// } else {
137
137
+
// break;
138
138
+
// }
139
139
+
// }
140
140
+
// }
141
141
+
// }
142
142
+
// }
143
143
+
144
144
+
// Some(c.to_string())
+10
years/2024/src/examples/day_6/1.txt
···
1
1
+
....#.....
2
2
+
.........#
3
3
+
..........
4
4
+
..#.......
5
5
+
.......#..
6
6
+
..........
7
7
+
.#..^.....
8
8
+
........#.
9
9
+
#.........
10
10
+
......#...
+10
years/2024/src/examples/day_6/2.txt
···
1
1
+
....#.....
2
2
+
.........#
3
3
+
..........
4
4
+
..#.......
5
5
+
.......#..
6
6
+
..........
7
7
+
.#..^.....
8
8
+
........#.
9
9
+
#.........
10
10
+
......#...