191 lines
4.3 KiB
C
191 lines
4.3 KiB
C
#include <stdint.h>
|
|
|
|
#include "cartesian.h"
|
|
#include "memory.h"
|
|
#include "parse.h"
|
|
#include "printf.h"
|
|
|
|
static bool move(char * map,
|
|
int width, int height,
|
|
int x, int y,
|
|
enum cartesian_direction direction,
|
|
bool commit)
|
|
{
|
|
const struct cartesian_neighbor * dir = &cartesian_neighbor[direction];
|
|
|
|
int nx = x + dir->x;
|
|
int ny = y + dir->y;
|
|
char n = map[ny * width + nx];
|
|
switch (n) {
|
|
case '#':
|
|
return false;
|
|
case 'O':
|
|
if (!move(map, width, height, nx, ny, direction, false))
|
|
return false;
|
|
move(map, width, height, nx, ny, direction, commit);
|
|
break;
|
|
case '[': [[fallthrough]];
|
|
case ']':
|
|
{
|
|
int nxoff = (n == '[') ? 1 : -1;
|
|
|
|
bool move2 = true;
|
|
if (direction == CARTESIAN_UP || direction == CARTESIAN_DOWN)
|
|
move2 = move(map, width, height, nx + nxoff, ny, direction, false);
|
|
|
|
bool move1 = move(map, width, height, nx, ny, direction, false);
|
|
|
|
if (!move1 || !move2)
|
|
return false;
|
|
|
|
if (direction == CARTESIAN_UP || direction == CARTESIAN_DOWN)
|
|
move(map, width, height, nx + nxoff, ny, direction, commit);
|
|
|
|
move(map, width, height, nx, ny, direction, commit);
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (commit) {
|
|
char c = map[y * width + x];
|
|
map[y * width + x] = '.';
|
|
map[ny * width + nx] = c;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static enum cartesian_direction parse_direction(char c)
|
|
{
|
|
switch (c) {
|
|
case '<': return CARTESIAN_LEFT;
|
|
case '>': return CARTESIAN_RIGHT;
|
|
case '^': return CARTESIAN_UP;
|
|
case 'v': return CARTESIAN_DOWN;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
typedef int (* map_transform_func)(char * map, char c);
|
|
|
|
static int part1_map_transform(char * map, char c)
|
|
{
|
|
*map = c;
|
|
return 1;
|
|
}
|
|
|
|
static int part2_map_transform(char * map, char c)
|
|
{
|
|
switch (c) {
|
|
case '#': map[0] = '#'; map[1] = '#'; break;
|
|
case '.': map[0] = '.'; map[1] = '.'; break;
|
|
case 'O': map[0] = '['; map[1] = ']'; break;
|
|
case '@': map[0] = '@'; map[1] = '.'; break;
|
|
};
|
|
return 2;
|
|
}
|
|
|
|
static const char * parse_map(const char * input, const char * end,
|
|
int * width, int * height,
|
|
int * x, int * y,
|
|
char * map,
|
|
map_transform_func func)
|
|
{
|
|
*width = 0;
|
|
*height = 0;
|
|
|
|
while (input < end) {
|
|
if (input[0] == '\n' && input[1] == '\n') {
|
|
*height += 1;
|
|
input = parse_skip(input, '\n');
|
|
return input;
|
|
} else if (*input == '\n') {
|
|
*height += 1;
|
|
*width = 0;
|
|
input = parse_skip(input, '\n');
|
|
} else {
|
|
if (*input == '@') {
|
|
*x = *width;
|
|
*y = *height;
|
|
}
|
|
int char_width = func(map, *input++);
|
|
*width += char_width;
|
|
map += char_width;
|
|
}
|
|
}
|
|
|
|
return input;
|
|
}
|
|
|
|
static void print_map(const char * map,
|
|
int width, int height)
|
|
{
|
|
for (int y = 0; y < height; y++) {
|
|
for (int x = 0; x < width; x++) {
|
|
print_char(map[y * width + x]);
|
|
}
|
|
print_char('\n');
|
|
}
|
|
print_char('\n');
|
|
}
|
|
|
|
static int gps_coordinate(int x, int y)
|
|
{
|
|
return 100 * y + x;
|
|
}
|
|
|
|
static int sum_boxes(const char * map, int width, int height)
|
|
{
|
|
int sum = 0;
|
|
for (int y = 0; y < height; y++) {
|
|
for (int x = 0; x < width; x++) {
|
|
char c = map[y * width + x];
|
|
if (c == 'O' || c == '[') {
|
|
sum += gps_coordinate(x, y);
|
|
}
|
|
}
|
|
}
|
|
return sum;
|
|
}
|
|
|
|
static int solve(const char * input, int length,
|
|
map_transform_func func)
|
|
{
|
|
const char * end = input + length;
|
|
|
|
int width;
|
|
int height;
|
|
int x;
|
|
int y;
|
|
char map[100 * 100];
|
|
input = parse_map(input, end,
|
|
&width, &height,
|
|
&x, &y,
|
|
map,
|
|
func);
|
|
const char * movements = input;
|
|
while (movements < end) {
|
|
char c = *movements++;
|
|
enum cartesian_direction direction = parse_direction(c);
|
|
if (move(map, width, height, x, y, direction, true)) {
|
|
x += cartesian_neighbor[direction].x;
|
|
y += cartesian_neighbor[direction].y;
|
|
}
|
|
|
|
movements = parse_skip(movements, '\n');
|
|
}
|
|
|
|
return sum_boxes(map, width, height);
|
|
}
|
|
|
|
int64_t _2024_day15_part1(const char * input, int length)
|
|
{
|
|
return solve(input, length, part1_map_transform);
|
|
}
|
|
|
|
int64_t _2024_day15_part2(const char * input, int length)
|
|
{
|
|
return solve(input, length, part2_map_transform);
|
|
}
|