mirror of
https://github.com/peter-tanner/advent-of-code-2021.git
synced 2024-11-30 19:20:19 +08:00
161 lines
3.8 KiB
C
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;
|
|
}
|