adventofcode2024/day06/sol.c

215 lines
3.9 KiB
C
Raw Normal View History

2024-12-06 05:19:41 +00:00
#include <stdlib.h>
2024-12-06 05:49:05 +00:00
#include <stdint.h>
2024-12-06 05:19:41 +00:00
#include <stdio.h>
#include <string.h>
#include <limits.h>
#include <stdbool.h>
struct grid {
char** A;
int x, y;
};
void* xrealloc(void* ptr, size_t size) {
if (size == 0) {
size = 1;
}
ptr = realloc(ptr, size);
if (ptr == NULL) {
fprintf(stderr, "fatal: alloc(%zd) failed", size);
exit(1);
}
return ptr;
}
int readfile(const char* filename, struct grid* out) {
FILE *fp = fopen(filename, "r");
if (fp == NULL) {
perror("fopen");
exit(1);
}
int len = 0;
int cap = 100;
char* data = xrealloc(NULL, cap);
for (;;) {
if (len >= cap) {
cap *= 2;
data = xrealloc(data, cap);
}
int c = fgetc(fp);
if (c == -1) {
break;
}
data[len] = c;
len++;
}
int i, nl=0;
for (i = 0; i < len; i++) {
if (data[i] == '\n') {
nl++;
}
}
// split on newlines
char** lines = xrealloc(NULL, nl * sizeof(char*));
char* p = data;
int mincol = INT_MAX;
i = 0;
while (p != NULL && p < data+len) {
lines[i++] = p;
char* q = memchr(p, '\n', (data+len)-p);
if (!q) {
break; // TODO: final line?
}
int col = q - p;
if (mincol > col && col > 0) {
mincol = col;
}
p = q+1; // skip newline
}
out->A = lines;
out->x = mincol;
out->y = nl;
return 0;
}
inline bool inbounds(struct grid *g, int x, int y) {
return (0 <= x && x < g->x && 0 <= y && y < g->y);
}
struct step_r { int x, y, dx, dy; bool ok; };
struct step_r step(struct grid *g, int x, int y, int dx, int dy) {
struct step_r r = {0};
if (!inbounds(g, x, y)) {
return r;
}
// if there is nothing in front of you, step forward
if (!inbounds(g, x+dx, y+dy) || g->A[y+dy][x+dx] != '#') {
r.x = x+dx;
r.y = y+dy;
r.dx = dx;
r.dy = dy;
r.ok = true;
return r;
} else {
// if there is something in front of you, turn right
r.x = x;
r.y = y;
r.dx = -dy;
r.dy = dx;
r.ok = true;
return r;
}
}
2024-12-06 05:49:05 +00:00
struct point { int x, y; };
struct point startingPoint(struct grid *g) {
2024-12-06 05:19:41 +00:00
int x, y;
for (y = 0; y < g->y; y++)
for (x = 0; x < g->x; x++) {
if (g->A[y][x] == '^') {
2024-12-06 05:49:05 +00:00
struct point r = {x, y};
return r;
2024-12-06 05:19:41 +00:00
}
}
2024-12-06 05:49:05 +00:00
struct point r = {-1,-1};
return r;
}
int solve(struct grid *g) {
struct point start = startingPoint(g);
int x = start.x, y = start.y;
int count = 0;
2024-12-06 05:19:41 +00:00
int dx = 0, dy = -1; // up
2024-12-06 05:49:05 +00:00
while(inbounds(g, x, y)) {
if (g->A[y][x] != 'x') {
2024-12-06 05:19:41 +00:00
count++;
}
2024-12-06 05:49:05 +00:00
g->A[y][x] = 'x';
2024-12-06 05:19:41 +00:00
2024-12-06 05:49:05 +00:00
struct step_r r = step(g, x, y, dx, dy);
2024-12-06 05:19:41 +00:00
if (r.ok != true) {
break;
}
2024-12-06 05:49:05 +00:00
x = r.x;
y = r.y;
dx = r.dx;
dy = r.dy;
}
g->A[start.y][start.x] = '^';
printf("%d\n", count);
return 0;
}
// returns whether the chosen grid will cause the guard to get stuck in a loop
2024-12-06 05:51:15 +00:00
bool loops(struct grid *g, struct point start, uint8_t* state) {
2024-12-06 05:49:05 +00:00
int x = start.x;
int y = start.y;
int dx = 0, dy = -1; // up
int stride = g->x;
//printf("loops(%d,%d)\n", x,y);
while(inbounds(g, x, y)) {
2024-12-06 05:51:15 +00:00
uint8_t dir = 15;
2024-12-06 05:49:05 +00:00
if (dx == 1) { dir = 1; }
else if (dx == -1) { dir = 2; }
else if (dy == 1) { dir = 4; }
else if (dy == -1) { dir = 8; }
2024-12-06 05:51:15 +00:00
uint8_t *s = &state[y*stride + x];
2024-12-06 05:49:05 +00:00
if ((*s & dir) != 0) {
// revisited a state, loop!
return true;
}
*s |= dir;
struct step_r r = step(g, x, y, dx, dy);
if (r.ok != true) {
// step failed, no loop
return false;
}
x = r.x;
y = r.y;
2024-12-06 05:19:41 +00:00
dx = r.dx;
dy = r.dy;
}
2024-12-06 05:49:05 +00:00
// left the map, no loop
return false;
}
int solve2(struct grid *g) {
int count = 0;
int ox, oy; // obstacle coords
struct point p = startingPoint(g);
2024-12-06 05:51:15 +00:00
size_t state_size = g->x * g->y * sizeof(uint8_t);
uint8_t *state = xrealloc(NULL, state_size);
2024-12-06 05:49:05 +00:00
for (oy = 0; oy < g->y; oy++)
for (ox = 0; ox < g->x; ox++) {
int c = g->A[oy][ox];
if (c != '#' && c != '^') {
g->A[oy][ox] = '#';
memset(state, 0, state_size);
if (loops(g, p, state)) {
count++;
}
g->A[oy][ox] = c;
}
}
free(state);
2024-12-06 05:19:41 +00:00
printf("%d\n", count);
return 0;
}
2024-12-06 05:49:05 +00:00
2024-12-06 05:19:41 +00:00
int main() {
struct grid g;
2024-12-06 05:49:05 +00:00
//readfile("sample1.in", &g);
2024-12-06 05:19:41 +00:00
readfile("input", &g);
printf("%d %d\n", g.x, g.y);
solve(&g);
2024-12-06 05:49:05 +00:00
//printf("%s", g.A[0]);
solve2(&g);
2024-12-06 05:19:41 +00:00
}