176 lines
4.3 KiB
C
176 lines
4.3 KiB
C
#include <limits.h>
|
|
#include <stdlib.h>
|
|
#define RT_CORE_IMPLEMENTATION
|
|
#include "rtcore.h"
|
|
|
|
#include "aoc.h"
|
|
|
|
enum
|
|
{
|
|
F_EMPTY = '.',
|
|
F_PAPER = '@',
|
|
};
|
|
|
|
typedef struct
|
|
{
|
|
char *fields;
|
|
int *weights;
|
|
int rows;
|
|
int cols;
|
|
} grid;
|
|
|
|
typedef struct
|
|
{
|
|
int x;
|
|
int y;
|
|
} cell_coord;
|
|
|
|
force_inline char GetField(const grid *g, int x, int y)
|
|
{
|
|
if (x < 0 || x >= g->cols || y < 0 || y >= g->rows)
|
|
return F_EMPTY;
|
|
return g->fields[y * g->cols + x];
|
|
}
|
|
|
|
force_inline int *GetWeight(const grid *g, int x, int y)
|
|
{
|
|
if (x < 0 || x >= g->cols || y < 0 || y >= g->rows)
|
|
return 0;
|
|
return &g->weights[y * g->cols + x];
|
|
}
|
|
|
|
internal void CountInputRes(s8 input, int *x, int *y)
|
|
{
|
|
split_result split = S8Split(input, '\n');
|
|
int rows = 0;
|
|
int cols = 0;
|
|
while (split.second.data)
|
|
{
|
|
if (cols == 0)
|
|
cols = (int)split.first.length;
|
|
++rows;
|
|
split = S8Split(split.second, '\n');
|
|
}
|
|
*x = cols;
|
|
*y = rows;
|
|
}
|
|
|
|
internal grid FillGrid(s8 input, arena *a)
|
|
{
|
|
grid grid = {0};
|
|
CountInputRes(input, &grid.cols, &grid.rows);
|
|
grid.fields = alloc(a, char, grid.cols * grid.rows);
|
|
grid.weights = alloc(a, int, grid.cols * grid.rows);
|
|
split_result split = S8Split(input, '\n');
|
|
int y = 0;
|
|
while (split.second.data)
|
|
{
|
|
memcpy(&grid.fields[y * grid.cols], split.first.data, grid.cols);
|
|
++y;
|
|
split = S8Split(split.second, '\n');
|
|
}
|
|
for (int y = 0; y < grid.rows; ++y)
|
|
{
|
|
for (int x = 0; x < grid.cols; ++x)
|
|
{
|
|
if (GetField(&grid, x, y) == F_PAPER)
|
|
{
|
|
int p = (GetField(&grid, x - 1, y - 1) == F_PAPER) +
|
|
(GetField(&grid, x, y - 1) == F_PAPER) +
|
|
(GetField(&grid, x + 1, y - 1) == F_PAPER) +
|
|
(GetField(&grid, x - 1, y) == F_PAPER) +
|
|
(GetField(&grid, x + 1, y) == F_PAPER) +
|
|
(GetField(&grid, x - 1, y + 1) == F_PAPER) +
|
|
(GetField(&grid, x, y + 1) == F_PAPER) +
|
|
(GetField(&grid, x + 1, y + 1) == F_PAPER);
|
|
*GetWeight(&grid, x, y) = p;
|
|
}
|
|
else
|
|
{
|
|
*GetWeight(&grid, x, y) = INT_MAX;
|
|
}
|
|
}
|
|
}
|
|
return grid;
|
|
}
|
|
|
|
global_variable grid _g;
|
|
internal int compare_cells(const void *_a, const void *_b)
|
|
{
|
|
// We subtract b - a, so that the lower elements get moved to the back
|
|
// (Ret < 0 -> _a gets placed before _b)
|
|
const cell_coord *a = _a, *b = _b;
|
|
return *GetWeight(&_g, b->x, b->y) - *GetWeight(&_g, a->x, a->y);
|
|
}
|
|
|
|
int
|
|
main(int argc, char **argv)
|
|
{
|
|
arena arena = CreateArena();
|
|
dataset ds = ParseDatasetOption(argc, argv);
|
|
s8 input = {0};
|
|
if (ds == DS_FULL)
|
|
input = ReadEntireFileS8(S8("inputs/day04_full"), &arena);
|
|
else if (ds == DS_DEMO)
|
|
input = ReadEntireFileS8(S8("inputs/day04_demo"), &arena);
|
|
if (!input.data)
|
|
return 1;
|
|
|
|
grid g = FillGrid(input, &arena);
|
|
_g = g;
|
|
cell_coord *paper_coords = alloc(&arena, cell_coord, g.rows * g.cols);
|
|
int num_papers = 0;
|
|
for (int y = 0; y < g.rows; ++y)
|
|
{
|
|
for (int x = 0; x < g.cols; ++x)
|
|
{
|
|
if (GetField(&g, x, y) == F_PAPER)
|
|
{
|
|
paper_coords[num_papers++] = (cell_coord){x, y};
|
|
}
|
|
}
|
|
}
|
|
|
|
int count = 0;
|
|
while (num_papers > 0)
|
|
{
|
|
qsort(paper_coords, num_papers, sizeof(cell_coord), compare_cells);
|
|
cell_coord lowest = paper_coords[--num_papers];
|
|
|
|
int neighbors =
|
|
(GetField(&g, lowest.x - 1, lowest.y - 1) == F_PAPER) +
|
|
(GetField(&g, lowest.x, lowest.y - 1) == F_PAPER) +
|
|
(GetField(&g, lowest.x + 1, lowest.y - 1) == F_PAPER) +
|
|
(GetField(&g, lowest.x - 1, lowest.y) == F_PAPER) +
|
|
(GetField(&g, lowest.x + 1, lowest.y) == F_PAPER) +
|
|
(GetField(&g, lowest.x - 1, lowest.y + 1) == F_PAPER) +
|
|
(GetField(&g, lowest.x, lowest.y + 1) == F_PAPER) +
|
|
(GetField(&g, lowest.x + 1, lowest.y + 1) == F_PAPER);
|
|
// Terminate condition: No paper can be removed
|
|
if (neighbors >= 4)
|
|
break;
|
|
|
|
g.fields[lowest.y * g.cols + lowest.x] = F_EMPTY;
|
|
++count;
|
|
|
|
for (int dy = -1; dy <= 1; ++dy)
|
|
{
|
|
int y = lowest.y + dy;
|
|
if (y >= 0 && y < g.rows)
|
|
{
|
|
for (int dx = -1; dx <= 1; ++dx)
|
|
{
|
|
int x = lowest.x + dx;
|
|
if (x >= 0 && x < g.cols)
|
|
{
|
|
*GetWeight(&g, x, y) -= 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
printf("Answer: %d\n", count);
|
|
|
|
return 0;
|
|
}
|