1
+ #include <stdbool.h>
2
+ #include <stdio.h>
3
+ #include <stdlib.h>
4
+ #include <string.h>
5
+
6
+ #define OBJECT '#'
7
+ #define MAX_GRID_SIZE 1000
8
+ #define MAX_SET_SIZE 10000
9
+
10
+ typedef enum { UP , DOWN , LEFT , RIGHT } Direction ;
11
+
12
+ typedef struct {
13
+ size_t x ;
14
+ size_t y ;
15
+ } Position ;
16
+
17
+ typedef struct {
18
+ Position pos1 ;
19
+ Position pos2 ;
20
+ } PositionPair ;
21
+
22
+ typedef struct {
23
+ Position pos_init ;
24
+ char grid [MAX_GRID_SIZE ][MAX_GRID_SIZE ];
25
+ size_t rows ;
26
+ size_t cols ;
27
+ } Lab ;
28
+
29
+ typedef struct {
30
+ bool is_out ;
31
+ bool has_pos ;
32
+ bool has_block ;
33
+ Position pos ;
34
+ Position block ;
35
+ } MoveResult ;
36
+
37
+ typedef struct {
38
+ Position positions [MAX_SET_SIZE ];
39
+ size_t size ;
40
+ } PositionSet ;
41
+
42
+ typedef struct {
43
+ PositionPair pairs [MAX_SET_SIZE ];
44
+ size_t size ;
45
+ } PositionPairSet ;
46
+
47
+ void init_position_set (PositionSet * set ) { set -> size = 0 ; }
48
+
49
+ void init_position_pair_set (PositionPairSet * set ) { set -> size = 0 ; }
50
+
51
+ bool position_in_set (PositionSet * set , Position pos ) {
52
+ for (size_t i = 0 ; i < set -> size ; i ++ ) {
53
+ if (set -> positions [i ].x == pos .x && set -> positions [i ].y == pos .y ) {
54
+ return true;
55
+ }
56
+ }
57
+ return false;
58
+ }
59
+
60
+ bool position_pair_in_set (PositionPairSet * set , PositionPair pair ) {
61
+ for (size_t i = 0 ; i < set -> size ; i ++ ) {
62
+ if (set -> pairs [i ].pos1 .x == pair .pos1 .x &&
63
+ set -> pairs [i ].pos1 .y == pair .pos1 .y &&
64
+ set -> pairs [i ].pos2 .x == pair .pos2 .x &&
65
+ set -> pairs [i ].pos2 .y == pair .pos2 .y ) {
66
+ return true;
67
+ }
68
+ }
69
+ return false;
70
+ }
71
+
72
+ void add_position_to_set (PositionSet * set , Position pos ) {
73
+ if (!position_in_set (set , pos )) {
74
+ set -> positions [set -> size ++ ] = pos ;
75
+ }
76
+ }
77
+
78
+ void add_position_pair_to_set (PositionPairSet * set , PositionPair pair ) {
79
+ if (!position_pair_in_set (set , pair )) {
80
+ set -> pairs [set -> size ++ ] = pair ;
81
+ }
82
+ }
83
+
84
+ Direction change_direction (Direction direction ) {
85
+ switch (direction ) {
86
+ case UP :
87
+ return RIGHT ;
88
+ case RIGHT :
89
+ return DOWN ;
90
+ case DOWN :
91
+ return LEFT ;
92
+ case LEFT :
93
+ return UP ;
94
+ default :
95
+ return UP ;
96
+ }
97
+ }
98
+
99
+ MoveResult change_position (Lab * lab , Direction direction , Position position ) {
100
+ MoveResult result = {false, false, false, {0 , 0 }, {0 , 0 }};
101
+
102
+ switch (direction ) {
103
+ case UP :
104
+ if (position .y == 0 ) {
105
+ result .is_out = true;
106
+ return result ;
107
+ }
108
+ if (lab -> grid [position .y - 1 ][position .x ] != OBJECT ) {
109
+ result .has_pos = true;
110
+ result .pos = (Position ){position .x , position .y - 1 };
111
+ } else {
112
+ result .has_block = true;
113
+ result .block = (Position ){position .x , position .y - 1 };
114
+ }
115
+ break ;
116
+
117
+ case LEFT :
118
+ if (position .x == 0 ) {
119
+ result .is_out = true;
120
+ return result ;
121
+ }
122
+ if (lab -> grid [position .y ][position .x - 1 ] != OBJECT ) {
123
+ result .has_pos = true;
124
+ result .pos = (Position ){position .x - 1 , position .y };
125
+ } else {
126
+ result .has_block = true;
127
+ result .block = (Position ){position .x - 1 , position .y };
128
+ }
129
+ break ;
130
+
131
+ case DOWN :
132
+ if (position .y + 1 >= lab -> rows ) {
133
+ result .is_out = true;
134
+ return result ;
135
+ }
136
+ if (lab -> grid [position .y + 1 ][position .x ] != OBJECT ) {
137
+ result .has_pos = true;
138
+ result .pos = (Position ){position .x , position .y + 1 };
139
+ } else {
140
+ result .has_block = true;
141
+ result .block = (Position ){position .x , position .y + 1 };
142
+ }
143
+ break ;
144
+
145
+ case RIGHT :
146
+ if (position .x + 1 >= lab -> cols ) {
147
+ result .is_out = true;
148
+ return result ;
149
+ }
150
+ if (lab -> grid [position .y ][position .x + 1 ] != OBJECT ) {
151
+ result .has_pos = true;
152
+ result .pos = (Position ){position .x + 1 , position .y };
153
+ } else {
154
+ result .has_block = true;
155
+ result .block = (Position ){position .x + 1 , position .y };
156
+ }
157
+ break ;
158
+ }
159
+ return result ;
160
+ }
161
+
162
+ Lab * parse_file (const char * filename ) {
163
+ FILE * file = fopen (filename , "r" );
164
+ if (!file ) {
165
+ perror ("Failed to open file" );
166
+ exit (EXIT_FAILURE );
167
+ }
168
+
169
+ Lab * lab = malloc (sizeof (Lab ));
170
+ char line [MAX_GRID_SIZE ];
171
+ size_t row = 0 ;
172
+ size_t col_max = 0 ;
173
+
174
+ while (fgets (line , sizeof (line ), file )) {
175
+ size_t len = strlen (line );
176
+ if (len > 0 && line [len - 1 ] == '\n' )
177
+ line [len -- ] = '\0' ;
178
+
179
+ if (len > col_max )
180
+ col_max = len ;
181
+
182
+ for (size_t i = 0 ; i < len ; i ++ ) {
183
+ if (line [i ] == '^' ) {
184
+ lab -> pos_init = (Position ){i , row };
185
+ lab -> grid [row ][i ] = '.' ;
186
+ } else {
187
+ lab -> grid [row ][i ] = line [i ];
188
+ }
189
+ }
190
+ row ++ ;
191
+ }
192
+
193
+ lab -> rows = row ;
194
+ lab -> cols = col_max ;
195
+ fclose (file );
196
+ return lab ;
197
+ }
198
+
199
+ size_t find_path (Lab * lab ) {
200
+ Direction direction = UP ;
201
+ Position current_position = lab -> pos_init ;
202
+ PositionSet explored ;
203
+ init_position_set (& explored );
204
+ add_position_to_set (& explored , current_position );
205
+
206
+ if (current_position .y == 0 ||
207
+ (current_position .y > 0 &&
208
+ lab -> grid [current_position .y ][current_position .x ] == OBJECT )) {
209
+ direction = change_direction (direction );
210
+ }
211
+
212
+ bool second_try = false;
213
+
214
+ while (true) {
215
+ MoveResult result = change_position (lab , direction , current_position );
216
+ if (result .is_out )
217
+ break ;
218
+
219
+ if (result .has_pos ) {
220
+ current_position = result .pos ;
221
+ add_position_to_set (& explored , current_position );
222
+ second_try = false;
223
+ } else {
224
+ direction = change_direction (direction );
225
+ if (second_try )
226
+ break ;
227
+ second_try = true;
228
+ }
229
+ }
230
+
231
+ return explored .size ;
232
+ }
233
+
234
+ size_t find_if_stuck (Lab * lab ) {
235
+ char original_grid [MAX_GRID_SIZE ][MAX_GRID_SIZE ];
236
+ memcpy (original_grid , lab -> grid , sizeof (original_grid ));
237
+ size_t count = 0 ;
238
+
239
+ for (size_t row = 0 ; row < lab -> rows ; row ++ ) {
240
+ for (size_t col = 0 ; col < lab -> cols ; col ++ ) {
241
+ if (OBJECT != lab -> grid [row ][col ]) {
242
+ lab -> grid [row ][col ] = OBJECT ;
243
+ Direction direction = UP ;
244
+ Position current_position = lab -> pos_init ;
245
+ PositionPairSet detect_loop ;
246
+ init_position_pair_set (& detect_loop );
247
+
248
+ if (current_position .y == 0 ||
249
+ (current_position .y > 0 &&
250
+ lab -> grid [current_position .y ][current_position .x ] == OBJECT )) {
251
+ direction = change_direction (direction );
252
+ }
253
+
254
+ bool second_try = false;
255
+
256
+ while (true) {
257
+ MoveResult result = change_position (lab , direction , current_position );
258
+ if (result .is_out )
259
+ break ;
260
+
261
+ if (result .has_pos ) {
262
+ current_position = result .pos ;
263
+ second_try = false;
264
+ } else if (result .has_block ) {
265
+ PositionPair blocking = {current_position , result .block };
266
+
267
+ if (position_pair_in_set (& detect_loop , blocking )) {
268
+ count ++ ;
269
+ break ;
270
+ }
271
+ direction = change_direction (direction );
272
+ add_position_pair_to_set (& detect_loop , blocking );
273
+ second_try = true;
274
+ }
275
+ }
276
+
277
+ lab -> grid [row ][col ] = original_grid [row ][col ];
278
+ }
279
+ }
280
+ }
281
+
282
+ return count ;
283
+ }
284
+
285
+ int main () {
286
+ Lab * lab = parse_file ("crates/day06/input.txt" );
287
+
288
+ // --- Part One ---
289
+ printf ("Part One solution: %zu\n" , find_path (lab ));
290
+ // --- Part Two ---
291
+ printf ("Part Two solution: %zu\n" , find_if_stuck (lab ));
292
+
293
+ free (lab );
294
+ return 0 ;
295
+ }
0 commit comments