1
0

solve day 14

This commit is contained in:
Rokas Puzonas 2023-06-11 19:47:08 +03:00
parent aff6457ce0
commit 0cd460461f
3 changed files with 359 additions and 0 deletions

356
day14.c Normal file
View File

@ -0,0 +1,356 @@
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/param.h>
#include "types.h"
#include "vec2.h"
#include "aoc.h"
typedef struct {
vec2_u32 *points;
size_t count;
} day14_line;
typedef struct {
day14_line *lines;
size_t count;
} day14_input;
typedef enum {
TILE_AIR,
TILE_SOLID,
TILE_SAND,
} map_tile;
typedef struct {
map_tile *tiles;
size_t width;
size_t height;
vec2_u32 offset;
} day14_map;
static void day14_parse_point(vec2_u32 *result, char *str)
{
char *x = strtok(str, ",");
result->x = strtoul(x, NULL, 10);
char *y = strtok(NULL, ",");
result->y = strtoul(y, NULL, 10);
}
static void day14_parse_line(day14_line *result, char *line)
{
result->count = 1;
for (int i = 0; i < strlen(line); i++) {
if (line[i] == '>') {
result->count++;
}
}
result->points = malloc(sizeof(vec2_u32)*result->count);
int i = 0;
char *save;
char *token = strtok_r(line, " -> ", &save);
while(token) {
day14_parse_point(&result->points[i], token);
token = strtok_r(NULL, " -> ", &save);
i++;
}
}
static void *day14_parse(char **lines, int line_count)
{
day14_input *result = malloc(sizeof(day14_input));
result->lines = malloc(sizeof(day14_line)*line_count);
result->count = line_count;
for (int i = 0; i < line_count; i++) {
day14_parse_line(&result->lines[i], lines[i]);
}
return result;
}
static void printf_day14_line(day14_line *line)
{
if (line->count > 0) {
for (int i = 0; i < line->count-1; i++) {
vec2_u32 point = line->points[i];
printf("%d,%d -> ", point.x, point.y);
}
vec2_u32 last = line->points[line->count-1];
printf("%d,%d", last.x, last.y);
}
}
static void printf_day14_map(day14_map *map)
{
char map_tile_chars[] = {
[TILE_AIR] = '.',
[TILE_SOLID] = '#',
[TILE_SAND] = 'O'
};
for (int y = 0; y < map->height; y++) {
for (int x = 0; x < map->width; x++) {
int idx = y * map->width + x;
char tile = map_tile_chars[map->tiles[idx]];
printf("%c", tile);
}
printf("\n");
}
}
static void printf_day14_segment(vec2_u32 *A, vec2_u32 *B)
{
printf("%d,%d -> %d,%d\n", A->x, A->y, B->x, B->y);
}
static void day14_place_vertical(day14_map *map, u32 x, u32 y, i32 size)
{
i32 from = size > 0 ? 0 : size+1;
i32 to = size > 0 ? size : 1;
for (i32 i = from; i < to; i++) {
size_t idx = (y - map->offset.y + i) * map->width + (x - map->offset.x);
map->tiles[idx] = TILE_SOLID;
}
}
static void day14_place_horizontal(day14_map *map, u32 x, u32 y, i32 size)
{
i32 from = size > 0 ? 0 : size+1;
i32 to = size > 0 ? size : 1;
for (i32 i = from; i < to; i++) {
size_t idx = (y - map->offset.y) * map->width + (x - map->offset.x + i);
map->tiles[idx] = TILE_SOLID;
}
}
static day14_map *day14_create_map(day14_line *lines, size_t count, vec2_u32 *sand_spawner)
{
day14_map *map = malloc(sizeof(day14_map));
vec2_u32 min_point = *sand_spawner;
vec2_u32 max_point = *sand_spawner;
for (int i = 0; i < count; i++) {
day14_line *line = &lines[i];
for (int j = 0; j < line->count; j++) {
vec2_u32 *point = &line->points[j];
min_point.x = MIN(min_point.x, point->x);
min_point.y = MIN(min_point.y, point->y);
max_point.x = MAX(max_point.x, point->x);
max_point.y = MAX(max_point.y, point->y);
}
}
map->offset = min_point;
map->width = max_point.x - min_point.x + 1;
map->height = max_point.y - min_point.y + 1;
map->tiles = calloc(map->width*map->height, sizeof(map_tile));
for (int i = 0; i < count; i++) {
day14_line *line = &lines[i];
for (int j = 1; j < line->count; j++) {
vec2_u32 *from = &line->points[j-1];
vec2_u32 *to = &line->points[j];
if (from->x == to->x) {
i32 size = to->y - from->y;
size += SIGN(size);
day14_place_vertical(map, from->x, from->y, size);
} else if (from->y == to->y) {
i32 size = to->x - from->x;
size += SIGN(size);
day14_place_horizontal(map, from->x, from->y, size);
} else {
abort();
}
}
}
return map;
}
static bool day14_is_air(day14_map *map, u32 x, u32 y)
{
if (x < map->offset.x || y < map->offset.y) return true;
size_t oy = y - map->offset.y;
if (oy >= map->height) return true;
size_t ox = x - map->offset.x;
if (ox >= map->width) return true;
size_t idx = oy * map->width + ox;
return map->tiles[idx] == TILE_AIR;
}
static bool day14_is_abyss(day14_map *map, u32 y)
{
return y >= (map->offset.y + map->height);
}
static bool day14_part1_spawn_sand(day14_map *map, u32 x, u32 y)
{
while (true) {
if (day14_is_abyss(map, y)) {
return false;
}
if (day14_is_air(map, x, y+1)) {
y++;
continue;
}
if (day14_is_air(map, x-1, y+1)) {
x--;
y++;
continue;
}
if (day14_is_air(map, x+1, y+1)) {
x++;
y++;
continue;
}
size_t idx = (y - map->offset.y) * map->width + (x - map->offset.x);
map->tiles[idx] = TILE_SAND;
return true;
}
}
static bool day14_is_in_bounds(day14_map *map, u32 x, u32 y)
{
if (x < map->offset.x || y < map->offset.y) return false;
u32 ox = x - map->offset.x;
u32 oy = y - map->offset.y;
return ox < map->width && oy < map->height;
}
static void day14_copy_tiles(
map_tile *from_map, u32 from_x, u32 from_y, size_t from_width, size_t from_height,
map_tile *to_map , u32 to_x , u32 to_y , size_t to_width , size_t to_height)
{
for (u32 oy = 0; oy < from_height; oy++) {
for (u32 ox = 0; ox < from_width; ox++) {
u32 x = from_x + ox;
u32 y = from_y + oy;
u32 from_idx = oy * from_width + ox;
u32 to_idx = (y - to_y) * to_width + (x - to_x);
to_map[to_idx] = from_map[from_idx];
}
}
}
static void day14_ensure_includes(day14_map *map, u32 x, u32 y, bool floor)
{
if (day14_is_in_bounds(map, x, y)) return;
u32 new_offset_x = MIN(map->offset.x, x);
u32 new_offset_y = MIN(map->offset.y, y);
size_t new_width = MAX(map->offset.x + map->width - 1, x) - new_offset_x + 1;
size_t new_height = MAX(map->offset.y + map->height - 1, y) - new_offset_y + 1;
map_tile *new_tiles = calloc(new_width*new_height, sizeof(map_tile));
day14_copy_tiles(
map->tiles, map->offset.x, map->offset.y, map->width, map->height,
new_tiles, new_offset_x, new_offset_y, new_width, new_height
);
free(map->tiles);
map->tiles = new_tiles;
map->offset.x = new_offset_x;
map->offset.y = new_offset_y;
map->width = new_width;
map->height = new_height;
if (floor) {
for (int ox = 0; ox < map->width; ox++) {
size_t idx = (map->height-1) * map->width + ox;
map->tiles[idx] = TILE_SOLID;
}
}
}
static void day14_map_place_at(day14_map *map, u32 x, u32 y, map_tile tile)
{
day14_ensure_includes(map, x, y, true);
size_t idx = (y - map->offset.y) * map->width + (x - map->offset.x);
map->tiles[idx] = TILE_SAND;
}
static bool day14_part2_spawn_sand(day14_map *map, u32 x, u32 y)
{
if (!day14_is_air(map, x, y)) return false;
while (true) {
if (y < map->offset.y + map->height-2) {
if (day14_is_air(map, x, y+1)) {
y++;
continue;
}
if (day14_is_air(map, x-1, y+1)) {
x--;
y++;
continue;
}
if (day14_is_air(map, x+1, y+1)) {
x++;
y++;
continue;
}
}
day14_map_place_at(map, x, y, TILE_SAND);
return true;
}
}
static void day14_add_floor(day14_map *map)
{
size_t height = map->height;
map->height += 2;
map->tiles = realloc(map->tiles, map->width*map->height * sizeof(map_tile));
for (size_t ox = 0; ox < map->width; ox++) {
size_t idx = height * map->width + ox;
map->tiles[idx] = TILE_AIR;
}
for (size_t ox = 0; ox < map->width; ox++) {
size_t idx = (height+1) * map->width + ox;
map->tiles[idx] = TILE_SOLID;
}
}
static void day14_part1(void *p)
{
day14_input *input = (day14_input*)p;
vec2_u32 sand_spawner = { .x = 500, .y = 0 };
day14_map *map = day14_create_map(input->lines, input->count, &sand_spawner);
size_t count = 0;
while (day14_part1_spawn_sand(map, sand_spawner.x, sand_spawner.y)) {
count++;
}
// printf_day14_map(map);
printf("Answer: %ld\n", count);
}
static void day14_part2(void *p)
{
day14_input *input = (day14_input*)p;
vec2_u32 sand_spawner = { .x = 500, .y = 0 };
day14_map *map = day14_create_map(input->lines, input->count, &sand_spawner);
day14_add_floor(map);
size_t count = 0;
while (day14_part2_spawn_sand(map, sand_spawner.x, sand_spawner.y)) {
count++;
}
// printf_day14_map(map);
printf("Answer: %ld\n", count);
}
ADD_SOLUTION(14, day14_parse, day14_part1, day14_part2);

1
main.c
View File

@ -22,6 +22,7 @@
#include "day11.c" #include "day11.c"
#include "day12.c" #include "day12.c"
#include "day13.c" #include "day13.c"
#include "day14.c"
Solution *find_solution(int day) Solution *find_solution(int day)
{ {

View File

@ -3,6 +3,8 @@
#include <stdint.h> #include <stdint.h>
#define SIGN(x) (x == 0 ? 0 : (x > 0 ? 1 : -1))
typedef uint8_t u8; typedef uint8_t u8;
typedef uint16_t u16; typedef uint16_t u16;
typedef uint32_t u32; typedef uint32_t u32;