advent-of-code-2021/9/9-1and2.c
2021-12-09 17:01:43 +08:00

161 lines
3.8 KiB
C

#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include "../check_alloc.h"
// BASIN_STATS DATATYPE
#define TOP_AREAS 3
typedef struct
{
unsigned int risk;
unsigned int top_areas;
} BASIN_STATS;
// GRID DATASTRUCTURE
typedef struct
{
unsigned int height;
bool scanned;
} CELL;
typedef struct
{
CELL **grid;
unsigned int height; // GRID DIMENSIONS
unsigned int width;
} GRID;
GRID *new_grid(unsigned int height, unsigned int width)
{
GRID *grid = calloc(1, sizeof(GRID));
grid->grid = calloc(height, sizeof(CELL));
grid->height = height;
grid->width = width;
return grid;
}
void print_grid(GRID *grid)
{
for (size_t i = 0; i < grid->height; i++)
{
for (size_t j = 0; j < grid->width; j++)
{
printf("%d(%d)", grid->grid[i][j].height, grid->grid[i][j].scanned);
}
putchar('\n');
}
putchar('\n');
}
unsigned int get_value(GRID *grid, size_t y, size_t x)
{
return (x < 0 || y < 0 || x >= grid->width || y >= grid->height || grid->grid[y][x].scanned)
? 10
: grid->grid[y][x].height;
}
//
unsigned int get_basin_area(GRID *grid, size_t i, size_t j)
{
unsigned int height = get_value(grid, i, j);
unsigned int area = 1;
grid->grid[i][j].scanned = true;
#define CHECK_ADJACENT(x, y, grid, area) \
if (get_value((grid), (x), (y)) < 9) \
{ \
(area) += get_basin_area((grid), (x), (y)); \
}
CHECK_ADJACENT(i + 1, j, grid, area);
CHECK_ADJACENT(i - 1, j, grid, area);
CHECK_ADJACENT(i, j + 1, grid, area);
CHECK_ADJACENT(i, j - 1, grid, area);
#undef CHECK_ADJACENT
return area;
}
int sort_list(const void *x, const void *y)
{
return *(int *)x - *(int *)y;
}
// PART 1
BASIN_STATS *get_risk(GRID *grid)
{
BASIN_STATS *basin = calloc(1, sizeof(BASIN_STATS));
unsigned int areas[TOP_AREAS + 1] = {0}; // TRACK 3 LARGEST AREAS
unsigned int risk = 0;
for (size_t i = 0; i < grid->height; i++)
{
for (size_t j = 0; j < grid->width; j++)
{
unsigned int height = get_value(grid, i, j);
// MINIMUM
if (get_value(grid, i + 1, j) > height && get_value(grid, i - 1, j) > height && get_value(grid, i, j + 1) > height && get_value(grid, i, j - 1) > height)
{
basin->risk += height + 1;
areas[0] = get_basin_area(grid, i, j);
qsort(areas, TOP_AREAS + 1, sizeof(areas[0]), sort_list);
}
}
}
basin->top_areas = 1;
for (size_t i = 1; i < TOP_AREAS + 1; i++)
{
basin->top_areas *= areas[i];
}
return basin;
}
//
unsigned int get_lines(char *file)
{
FILE *p_file = fopen(file, "r");
unsigned int lines = 0;
char c;
while ((c = getc(p_file)) != EOF)
if (c == '\n')
lines++;
return lines;
}
CELL *str_to_line(char *str, size_t len)
{
CELL *line = calloc(len, sizeof(CELL));
for (size_t i = 0; i < len; i++)
{
line[i].height = (str[i] - '0');
line[i].scanned = false;
}
return line;
}
GRID *read_file(char *file)
{
FILE *p_file = fopen(file, "r");
unsigned int n_lines = get_lines(file);
char buf[BUFSIZ];
fgets(buf, sizeof buf, p_file);
unsigned int width = strlen(buf) - 1;
GRID *p_grid = new_grid(n_lines, width);
size_t i = 0;
do
{
p_grid->grid[i] = str_to_line(buf, width);
i++;
} while (fgets(buf, sizeof buf, p_file) != NULL);
return p_grid;
}
int main(int argc, char const *argv[])
{
GRID *p_grid = read_file("input");
BASIN_STATS *p_basin = get_risk(p_grid);
printf("RISK %d AREA %d\n", p_basin->risk, p_basin->top_areas);
return 0;
}