advent-of-code-2024/day-15/main.c

222 lines
6.3 KiB
C

#include "aoc.h"
static bool
can_push(Grid *grid, i32 x, i32 y, i32 dx, i32 dy) {
i32 index = y * grid->width + x;
i32 next_index = (y + dy) * grid->width + (x + dx);
u8 cell = grid->grid[index];
u8 next_cell = grid->grid[index];
switch (next_cell) {
case '.': return true;
case '#': return false;
case '@':
case 'O': return can_push(grid, x + dx, y + dy, dx, dy);
case '[':
if (dy == 0) return can_push(grid, x + dx, y, dx, dy);
else return can_push(grid, x, y + dy, dx, dy) && can_push(grid, x + 1, y + dy, dx, dy);
case ']':
if (dy == 0) return can_push(grid, x + dx, y, dx, dy);
else return can_push(grid, x, y + dy, dx, dy) && can_push(grid, x - 1, y + dy, dx, dy);
default: NOT_REACHABLE();
}
}
static bool
push_block(Grid *grid, i32 x, i32 y, i32 dx, i32 dy) {
if (!can_push(grid, x, y, dx, dy)) return false;
u8 cell = grid_at(grid, x, y);
if (cell == '.') {
return true;
}
else if (cell == '#') {
return false;
}
else if (cell == 'O' || cell == '@') {
i32 nx = x + dx;
i32 ny = y + dy;
if (push_block(grid, nx, ny, dx, dy)) {
ASSERT(can_push(grid, x, y, dx, dy));
grid->grid[ny * grid->width + nx] = grid->grid[y * grid->width + x];
grid->grid[y * grid->width + x] = '.';
return true;
}
else {
return false;
}
}
else if (cell == '[' || cell == ']') {
i32 nx = x + dx;
i32 ny = y + dy;
if (dy == 0) {
if (push_block(grid, nx, ny, dx, dy)) {
ASSERT(can_push(grid, x, y, dx, dy));
grid->grid[ny * grid->width + nx] = grid->grid[y * grid->width + x];
grid->grid[y * grid->width + x] = '.';
return true;
}
else {
return false;
}
}
else {
ASSERT(dy != 0);
i32 partner_x = (cell == '[') ? nx + 1 : nx - 1;
if (push_block(grid, nx, ny, dx, dy)
&& push_block(grid, partner_x, ny, dx, dy))
{
ASSERT(can_push(grid, x, y, dx, dy));
grid->grid[ny * grid->width + nx] = grid->grid[y * grid->width + x];
grid->grid[ny * grid->width + partner_x] = grid->grid[y * grid->width + partner_x];
grid->grid[y * grid->width + x] = '.';
grid->grid[y * grid->width + partner_x] = '.';
return true;
}
else {
return false;
}
}
}
else NOT_REACHABLE();
}
static void
print_grid(Grid *grid) {
for (i32 y = 0; y < grid->height; y++) {
for (i32 x = 0; x < grid->width; x++) {
putchar(grid_at(grid, x, y));
}
putchar('\n');
}
}
static Grid
widen(Arena *arena, Grid *grid) {
Grid result = {
.width = 2 * grid->width,
.height = grid->height,
.grid = ARENA_ALLOC_ARRAY(arena, u8, 2 * grid->width * grid->height)
};
u8 *ptr = result.grid;
for (i32 y = 0; y < grid->height; y++) {
for (i32 x = 0; x < grid->width; x++) {
u8 cell = grid_at(grid, x, y);
if (cell == '.') {
*ptr++ = '.';
*ptr++ = '.';
}
else if (cell == '#') {
*ptr++ = '#';
*ptr++ = '#';
}
else if (cell == 'O') {
*ptr++ = '[';
*ptr++ = ']';
}
else if (cell == '@') {
*ptr++ = '@';
*ptr++ = '.';
}
else {
NOT_REACHABLE();
}
}
}
ASSERT(ptr == result.grid + result.width * result.height);
return result;
}
static i32
compute_total(Grid *grid) {
i32 result = 0;
for (i32 y = 0; y < grid->height; y++) {
for (i32 x = 0; x < grid->width; x++) {
u8 cell = grid_at(grid, x, y);
if (cell == 'O' || cell == '[') {
result += 100 * y + x;
}
}
}
return result;
}
static void
find_robot(Grid *grid, i32 *x, i32 *y) {
i32 robot_x = -1, robot_y = -1;
for (i32 y = 0; y < grid->height; y++) {
for (i32 x = 0; x < grid->width; x++) {
if (grid_at(grid, x, y) == '@') {
robot_x = x;
robot_y = y;
}
}
}
ASSERT(robot_x != -1 && robot_y != -1);
*x = robot_x;
*y = robot_y;
}
int main(int argc, char **argv) {
Arena *arena = make_arena(Megabytes(1));
str input = read_file(arena, argv[1]);
str grid_input, instructions_str;
str_split(input, STR("\n\n"), &grid_input, &instructions_str);
Grid original = parse_grid(grid_input, arena);
Grid grid = parse_grid(grid_input, arena);
i32 robot_x, robot_y;
find_robot(&grid, &robot_x, &robot_y);
u8 *instructions = ARENA_ALLOC_ARRAY(arena, u8, instructions_str.len);
isize instruction_count = 0;
for (isize i = 0; i < instructions_str.len; i++) {
u8 ch = instructions_str.data[i];
if (ch != '\n') {
instructions[instruction_count++] = ch;
}
}
// Part 1
for (isize i = 0; i < instruction_count; i++) {
u8 ch = instructions[i];
i32 dx = 0, dy = 0;
if (ch == '<') dx = -1;
else if (ch == '>') dx = 1;
else if (ch == '^') dy = -1;
else if (ch == 'v') dy = 1;
else NOT_REACHABLE();
if (push_block(&grid, robot_x, robot_y, dx, dy)) {
robot_x += dx;
robot_y += dy;
}
}
i32 part_1 = compute_total(&grid);
printf("%d\n", part_1);
// Part 2
Grid wide_grid = widen(arena, &original);
find_robot(&wide_grid, &robot_x, &robot_y);
for (isize i = 0; i < instruction_count; i++) {
u8 ch = instructions[i];
i32 dx = 0, dy = 0;
if (ch == '<') dx = -1;
else if (ch == '>') dx = 1;
else if (ch == '^') dy = -1;
else if (ch == 'v') dy = 1;
else NOT_REACHABLE();
if (push_block(&wide_grid, robot_x, robot_y, dx, dy)) {
robot_x += dx;
robot_y += dy;
}
}
i32 part_2 = compute_total(&wide_grid);
printf("%d\n", part_2);
}