Skip to content

Commit 9d437ae

Browse files
committed
feat: day06
1 parent c714b47 commit 9d437ae

File tree

8 files changed

+502
-0
lines changed

8 files changed

+502
-0
lines changed

Cargo.lock

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ members = [
66
"crates/day03",
77
"crates/day04",
88
"crates/day05",
9+
"crates/day06",
910
"crates/helpers",
1011
]
1112

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,4 @@ Ideally, the solution does not use external crates/dependencies.
1616
| 3 |||||||
1717
| 4 |||||||
1818
| 5 |||||||
19+
| 6 |||||||

cpp/day06.cc

Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
#include <fstream>
2+
#include <iostream>
3+
#include <optional>
4+
#include <set>
5+
#include <sstream>
6+
#include <string>
7+
#include <vector>
8+
9+
using namespace std;
10+
11+
const char OBJECT = '#';
12+
13+
enum class Direction { Up, Down, Left, Right };
14+
15+
class Lab {
16+
public:
17+
pair<size_t, size_t> pos_init;
18+
vector<vector<char>> grid;
19+
pair<size_t, size_t> right_bottom_position;
20+
21+
Lab(const string &content) {
22+
grid = parseGrid(content);
23+
pos_init = findInitialPosition(content);
24+
right_bottom_position = {grid.size() - 1, grid[0].size() - 1};
25+
}
26+
27+
size_t findPath() {
28+
Direction direction = Direction::Up;
29+
auto current_position = pos_init;
30+
set<pair<size_t, size_t>> already_explored_pos;
31+
already_explored_pos.insert(pos_init);
32+
33+
if (pos_init.second == 0 ||
34+
(pos_init.second > 0 &&
35+
grid[pos_init.second][pos_init.first] == OBJECT)) {
36+
direction = changeDirection(direction);
37+
}
38+
39+
bool second_try = false;
40+
41+
while (true) {
42+
auto [is_out, pos, _] = changePosition(direction, current_position);
43+
if (is_out) {
44+
break;
45+
}
46+
if (pos.has_value()) {
47+
current_position = pos.value();
48+
already_explored_pos.insert(current_position);
49+
if (second_try) {
50+
second_try = false;
51+
}
52+
} else {
53+
direction = changeDirection(direction);
54+
if (second_try) {
55+
break;
56+
}
57+
second_try = true;
58+
}
59+
}
60+
61+
return already_explored_pos.size();
62+
}
63+
64+
size_t findIfStuck() {
65+
vector<vector<char>> original_grid = grid;
66+
size_t count = 0;
67+
68+
for (size_t row = 0; row < grid.size(); ++row) {
69+
for (size_t col = 0; col < grid[row].size(); ++col) {
70+
if (OBJECT != grid[row][col]) {
71+
grid[row][col] = OBJECT;
72+
Direction direction = Direction::Up;
73+
auto current_position = pos_init;
74+
set<tuple<pair<size_t, size_t>, pair<size_t, size_t>, string>>
75+
detect_loop;
76+
77+
if (pos_init.second == 0 ||
78+
(pos_init.second > 0 &&
79+
grid[pos_init.second][pos_init.first] == OBJECT)) {
80+
direction = changeDirection(direction);
81+
}
82+
83+
bool second_try = false;
84+
85+
while (true) {
86+
auto [is_out, pos, block] =
87+
changePosition(direction, current_position);
88+
if (is_out) {
89+
break;
90+
}
91+
if (pos.has_value()) {
92+
current_position = pos.value();
93+
if (second_try) {
94+
second_try = false;
95+
}
96+
} else if (block.has_value()) {
97+
string str_direction = to_string(static_cast<int>(direction));
98+
auto blocking =
99+
make_tuple(current_position, block.value(), str_direction);
100+
direction = changeDirection(direction);
101+
if (detect_loop.count(blocking)) {
102+
count += 1;
103+
break;
104+
}
105+
detect_loop.insert(blocking);
106+
second_try = true;
107+
}
108+
}
109+
110+
grid[row][col] = original_grid[row][col];
111+
}
112+
}
113+
}
114+
115+
return count;
116+
}
117+
118+
private:
119+
static vector<vector<char>> parseGrid(const string &content) {
120+
vector<vector<char>> grid;
121+
stringstream ss(content);
122+
string line;
123+
124+
while (getline(ss, line)) {
125+
vector<char> row(line.begin(), line.end());
126+
for (char &c : row) {
127+
if (c == '^') {
128+
c = '.';
129+
}
130+
}
131+
grid.push_back(row);
132+
}
133+
return grid;
134+
}
135+
136+
static pair<size_t, size_t> findInitialPosition(const string &content) {
137+
stringstream ss(content);
138+
string line;
139+
size_t row_idx = 0;
140+
141+
while (getline(ss, line)) {
142+
size_t col_idx = line.find('^');
143+
if (col_idx != string::npos) {
144+
return {row_idx, col_idx};
145+
}
146+
row_idx++;
147+
}
148+
throw runtime_error("initial position not detected");
149+
}
150+
151+
tuple<bool, optional<pair<size_t, size_t>>, optional<pair<size_t, size_t>>>
152+
changePosition(Direction direction, pair<size_t, size_t> position) {
153+
auto [y, x] = position;
154+
155+
switch (direction) {
156+
case Direction::Up:
157+
if (y == 0) {
158+
return {true, nullopt, nullopt};
159+
}
160+
if (grid[y - 1][x] != OBJECT) {
161+
return {false, make_optional(make_pair(y - 1, x)), nullopt};
162+
}
163+
return {false, nullopt, make_optional(make_pair(y - 1, x))};
164+
165+
case Direction::Left:
166+
if (x == 0) {
167+
return {true, nullopt, nullopt};
168+
}
169+
if (grid[y][x - 1] != OBJECT) {
170+
return {false, make_optional(make_pair(y, x - 1)), nullopt};
171+
}
172+
return {false, nullopt, make_optional(make_pair(y, x - 1))};
173+
174+
case Direction::Down:
175+
if (y + 1 > right_bottom_position.first) {
176+
return {true, nullopt, nullopt};
177+
}
178+
if (grid[y + 1][x] != OBJECT) {
179+
return {false, make_optional(make_pair(y + 1, x)), nullopt};
180+
}
181+
return {false, nullopt, make_optional(make_pair(y + 1, x))};
182+
183+
case Direction::Right:
184+
if (x + 1 > right_bottom_position.second) {
185+
return {true, nullopt, nullopt};
186+
}
187+
if (grid[y][x + 1] != OBJECT) {
188+
return {false, make_optional(make_pair(y, x + 1)), nullopt};
189+
}
190+
return {false, nullopt, make_optional(make_pair(y, x + 1))};
191+
}
192+
193+
return {false, nullopt, nullopt};
194+
}
195+
196+
static Direction changeDirection(Direction direction) {
197+
switch (direction) {
198+
case Direction::Up:
199+
return Direction::Right;
200+
case Direction::Right:
201+
return Direction::Down;
202+
case Direction::Down:
203+
return Direction::Left;
204+
}
205+
return Direction::Up;
206+
}
207+
};
208+
209+
string readFile(const string &filename) {
210+
ifstream file(filename);
211+
if (!file.is_open()) {
212+
throw runtime_error("Could not open file");
213+
}
214+
stringstream buffer;
215+
buffer << file.rdbuf();
216+
return buffer.str();
217+
}
218+
219+
int main() {
220+
try {
221+
string message = readFile("crates/day06/input.txt");
222+
Lab grid(message);
223+
// --- Part One ---
224+
cout << "Part One solution: " << grid.findPath() << endl;
225+
// --- Part Two ---
226+
cout << "Part Two solution: " << grid.findIfStuck() << endl;
227+
} catch (const exception &e) {
228+
cerr << e.what() << endl;
229+
}
230+
return 0;
231+
}

crates/day06/Cargo.toml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
[package]
2+
name = "day06"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
[lints]
7+
workspace = true
8+
9+
[dependencies]
10+
helpers = { path = "../helpers"}

crates/day06/example_input.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+
......#...

crates/day06/input.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+
......#...

0 commit comments

Comments
 (0)