aboutsummaryrefslogtreecommitdiff
path: root/2023/src/day10.cpp
diff options
context:
space:
mode:
Diffstat (limited to '2023/src/day10.cpp')
-rw-r--r--2023/src/day10.cpp216
1 files changed, 216 insertions, 0 deletions
diff --git a/2023/src/day10.cpp b/2023/src/day10.cpp
new file mode 100644
index 0000000..264e111
--- /dev/null
+++ b/2023/src/day10.cpp
@@ -0,0 +1,216 @@
1#include <algorithm>
2#include <fstream>
3#include <iostream>
4#include <sstream>
5#include <string>
6#include <vector>
7using namespace std;
8
9using pos_t = tuple<size_t, size_t>;
10using puzzle_t = vector<string>;
11
12puzzle_t
13read_file(string_view filename)
14{
15 fstream input{ filename };
16 puzzle_t data;
17
18 for ( string line; getline(input, line); ) {
19 data.emplace_back(line);
20 }
21
22 return data;
23}
24
25pos_t
26find_start_pos(const puzzle_t& puzzle)
27{
28 for ( size_t y = 0; y != puzzle.size(); ++y ) { // NOLINT
29 auto x = puzzle[y].find('S'); // NOLINT
30 if ( x != string::npos ) {
31 return { x, y };
32 }
33 }
34
35 return { 0, 0 };
36};
37
38bool
39predict_direction(const puzzle_t& puzzle, pos_t& current, char& direction)
40{
41 auto [x, y] = current;
42
43 if ( direction == 'S' ) {
44 ++y;
45 if ( y >= puzzle.size() ) {
46 return false;
47 }
48 const auto tile = puzzle[y][x];
49 if ( tile != 'J' && tile != '|' && tile != 'L' ) {
50 return false;
51 }
52 if ( tile == 'J' ) {
53 direction = 'W';
54 }
55 else if ( tile == 'L' ) {
56 direction = 'E';
57 }
58 }
59 else if ( direction == 'N' ) {
60 --y;
61 if ( y >= puzzle.size() ) {
62 return false;
63 }
64 const auto tile = puzzle[y][x];
65 if ( tile != '7' && tile != '|' && tile != 'F' ) {
66 return false;
67 }
68 if ( tile == '7' ) {
69 direction = 'W';
70 }
71 else if ( tile == 'F' ) {
72 direction = 'E';
73 }
74 }
75 else if ( direction == 'E' ) {
76 ++x;
77 if ( x >= puzzle[y].size() ) {
78 return false;
79 }
80 const auto tile = puzzle[y][x];
81 if ( tile != 'J' && tile != '-' && tile != '7' ) {
82 return false;
83 }
84 if ( tile == 'J' ) {
85 direction = 'N';
86 }
87 else if ( tile == '7' ) {
88 direction = 'S';
89 }
90 }
91 else if ( direction == 'W' ) {
92 --x;
93 if ( x >= puzzle[y].size() ) {
94 return false;
95 }
96 const auto tile = puzzle[y][x];
97 if ( tile != 'L' && tile != '-' && tile != 'F' ) {
98 return false;
99 }
100 if ( tile == 'L' ) {
101 direction = 'N';
102 }
103 else if ( tile == 'F' ) {
104 direction = 'S';
105 }
106 }
107 else {
108 cerr << "invalid direction " << direction << ")!" << endl;
109 return false;
110 }
111
112 current = { x, y };
113 return true;
114};
115
116void
117part1(const puzzle_t& puzzle)
118{
119 const auto start_pos = find_start_pos(puzzle);
120
121 auto max_steps = 0;
122
123 for ( const auto direction: { 'N', 'S', 'E', 'W' } ) {
124 auto current_direction = direction;
125 auto current_pos = start_pos;
126
127 auto steps = 0;
128 for ( ;; ) {
129 ++steps;
130
131 if ( !predict_direction(puzzle, current_pos, current_direction) ) {
132 break;
133 }
134 }
135
136 max_steps = max(max_steps, steps);
137 }
138
139 cout << max_steps / 2 << endl;
140}
141
142bool
143flood_fill(puzzle_t& puzzle, size_t x, size_t y)
144{
145 if ( y >= puzzle.size() || x >= puzzle[0].size() ) {
146 return false;
147 }
148
149 if ( puzzle[y][x] == ' ' ) {
150 puzzle[y][x] = 'o';
151 if ( !flood_fill(puzzle, x, y + 1) ||
152 !flood_fill(puzzle, x, y - 1) ||
153 !flood_fill(puzzle, x + 1, y) ||
154 !flood_fill(puzzle, x - 1, y) ) {
155 return false;
156 }
157 }
158
159 return true;
160};
161
162void
163part2(const puzzle_t& puzzle_original)
164{
165 puzzle_t puzzle{ puzzle_original.size(), string(puzzle_original[0].size(), ' ') };
166
167 const auto start_pos = find_start_pos(puzzle_original);
168
169 for ( const auto direction: { 'N', 'S', 'E', 'W' } ) {
170 auto current_direction = direction;
171 auto current_pos = start_pos;
172
173 for ( ;; ) {
174 auto [x, y] = current_pos;
175
176 puzzle[y][x] = puzzle_original[y][x];
177
178 if ( !predict_direction(puzzle_original, current_pos, current_direction) ) {
179 break;
180 }
181 }
182 }
183
184 for ( size_t y = 0; y != puzzle.size(); ++y ) { // NOLINT
185 for ( size_t x = 0; x != puzzle[y].size(); ++x ) { // NOLINT
186 auto test_puzzle{ puzzle };
187
188 if ( flood_fill(test_puzzle, x, y) ) {
189 puzzle = test_puzzle;
190 }
191 }
192 }
193
194 auto sum = 0;
195 for ( auto& line: puzzle ) {
196 auto pipes = 0U;
197 for ( auto chr: line ) {
198 if ( chr == '|' || chr == 'L' || chr == 'J' ) {
199 ++pipes;
200 }
201 if ( chr == 'o' && (pipes & 1U) == 1U ) {
202 ++sum;
203 }
204 }
205 }
206
207 cout << sum << endl;
208}
209
210int
211main()
212{
213 const auto puzzle = read_file("data/day10.txt");
214 part1(puzzle);
215 part2(puzzle);
216}