AoC2024/12/main.c
2024-12-12 15:41:01 +01:00

176 lines
4 KiB
C

#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include<stdbool.h>
struct list {
char type;
struct square *tiles;
unsigned int area;
unsigned int perimeter;
struct list *next;
};
struct square {
int x;
int y;
struct square *next;
};
bool tile_in_list(int x, int y, struct list *plot)
{
if (!plot)
return 0;
struct square *current = plot->tiles;
while (current) {
if (current->x == x && current->y == y) {
return 1;
}
current = current->next;
}
return 0;
}
bool plot_exists (int x, int y, struct list *plots)
{
struct list *current = plots;
while (current) {
if (tile_in_list(x, y, current))
return 1;
current = current->next;
}
return 0;
}
void add_tile(int x, int y, struct list *plot)
{
if (plot->tiles == NULL) {
plot->tiles = malloc(sizeof(struct square));
plot->tiles->x = x;
plot->tiles->y = y;
plot->tiles->next = NULL;
return;
}
struct square *tiles = plot->tiles;
while (tiles->next)
tiles = tiles->next;
tiles->next = malloc(sizeof(struct square));
tiles->next->x = x;
tiles->next->y = y;
tiles->next->next = NULL;
}
struct list *check_plot(int x, int y, int width, int height, char **map, struct list *plot, bool daddy)
{
int dir[4][2] = {{0, -1}, {1, 0}, {0, 1}, {-1, 0}};
int perimeter = 0;
// daddy simply states if this function was called from the outside,
// since the main loop will never send grids in the same plot
// should actually be solved by handling the list outside this func
struct list *prevPlot = plot;
while (plot && plot->type != map[x][y]) {
prevPlot = plot;
plot = plot->next;
}
// create list of every tile in this plot
// init list
if (plot == NULL || daddy) {
plot = malloc(sizeof(struct list));
plot->type = map[x][y];
plot->area = 0;
plot->perimeter = 0;
plot->tiles = NULL;
plot->next = NULL;
if (prevPlot)
prevPlot->next = plot;
}
// check if current tile is in this list
// if yes, return
if (tile_in_list(x, y, plot))
return NULL;
// else, add, then check all surrounding tiles with this function
add_tile(x, y, plot);
plot->area++;
// look in every direction for same type, recurse it
for (int i = 0; i < 4; i++) {
if (x + dir[i][0] >= 0 &&
x + dir[i][0] < width &&
y + dir[i][1] >= 0 &&
y + dir[i][1] < height) {
if (map[x + dir[i][0]][y + dir[i][1]] == map[x][y]) {
check_plot(x + dir[i][0], y + dir[i][1],
width, height, map, plot, false);
} else {
plot->perimeter++;
}
} else
plot->perimeter++;
}
return plot;
}
int main ()
{
// figure out data dimensions
FILE *input = fopen("./input", "r");
int width = 0;
int height = 1;
while (fgetc(input) != '\n') width++;
for (char c = fgetc(input); c != EOF; c = fgetc(input)) {
if (c == '\n')
height++;
}
rewind(input);
printf("Dimensions: %d x %d\n", width, height);
// make 2d array
char **map = malloc(width * sizeof(char*));
map[0] = malloc(width * height);
for (int i = 1; i < width; i++) {
map[i] = map[0] + i * height;
}
// put the data in the array
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
map[j][i] = fgetc(input);
}
fgetc(input);
}
fclose(input);
int scoreSum = 0;
// find plots not in list, check their score
struct list *plots = NULL;
struct list *current = NULL;
char prevType = 0;
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
// nasty if. prev type, skip. first, init head.
// else, if tile is already in plot-list, skip
// else, add a new plot to the list from current tile
if (map[j][i] == prevType)
continue;
if (i == 0 && j == 0) {
plots = check_plot(j,i, width, height, map, plots, true);
current = plots;
}
else if (plot_exists(j, i, plots))
continue;
else
current = check_plot(j,i, width, height, map, current, true);
}
}
current = plots;
int sum = 0;
while (current) {
printf("plot %c is area %d and perimeter %d\n", current->type, current->area, current->perimeter);
sum += current->area * current->perimeter;
current = current->next;
}
printf("total score: %d\n", sum);
}