From 98c579c96f9ec7304159f7780e0c547b98b2ddc6 Mon Sep 17 00:00:00 2001 From: Rokas Puzonas Date: Sat, 8 Jul 2023 19:29:38 +0300 Subject: [PATCH] solve day 22 part 1 --- Makefile | 2 +- README.md | 3 + day22.c | 599 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ main.c | 1 + 4 files changed, 604 insertions(+), 1 deletion(-) create mode 100644 day22.c diff --git a/Makefile b/Makefile index 8179a24..d564f0d 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ main: main.c day*.c vec.h aoc.h vec2.h types.h - gcc -o main main.c -lcurl -O3 + gcc -o main main.c -lcurl -lm -O3 run: main ./main $(day) diff --git a/README.md b/README.md index 11d40b4..a2d2f1a 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,6 @@ # Advent Of Code 2022 (C edition) This was a mistake + +## TODO +* Day 22, part 2 diff --git a/day22.c b/day22.c new file mode 100644 index 0000000..362d772 --- /dev/null +++ b/day22.c @@ -0,0 +1,599 @@ +#include +#include +#include +#include +#include + +#include "vec2.h" +#include "types.h" +#include "aoc.h" + +typedef enum { + TILE_VOID, + TILE_EMPTY, + TILE_WALL, +} day22_tile; +char g_day22_tiles[] = { + [TILE_VOID ] = ' ', + [TILE_EMPTY] = '.', + [TILE_WALL ] = '#' +}; + +typedef enum { + FACING_RIGHT, + FACING_DOWN, + FACING_LEFT, + FACING_UP, +} day22_facing; +char *g_day22_facing_str[] = { + [FACING_RIGHT] = "right", + [FACING_DOWN ] = "down", + [FACING_LEFT ] = "left", + [FACING_UP ] = "up", +}; +vec2 g_day22_dirs[] = { + [FACING_RIGHT] = { .x = 1, .y = 0}, + [FACING_DOWN ] = { .x = 0, .y = 1}, + [FACING_LEFT ] = { .x = -1, .y = 0}, + [FACING_UP ] = { .x = 0, .y = -1}, +}; + +typedef enum { + INST_WALK, + INST_LEFT, + INST_RIGHT, +} day22_instruction_op; + +typedef struct { + day22_tile *tiles; + u32 width; + u32 height; +} day22_map; + +// N T +// W E +// S B +// +// Reference image: https://media.printables.com/media/prints/209926/images/1928241_bf5690f2-3397-4519-aa4a-43afc07c0eaa/thumbs/inside/1920x1440/jpg/dice.webp +// Reference model: https://sketchfab.com/3d-models/6-sided-dice-7564358b73614881a1e838a0827f10f8 +// Unwrapped faces, based on 6-sided die: +// N 3 +// T 1 +// WSE 542 +// B 6 +// +typedef enum { + FACE_TOP, // 0 + FACE_EAST, // 1 + FACE_NORTH, // 2 + FACE_SOUTH, // 3 + FACE_WEST, // 4 + FACE_BOTTOM, // 5 +} day22_face; +char *g_day22_face_str[] = { + [FACE_TOP ] = "top", + [FACE_EAST ] = "east", + [FACE_NORTH ] = "north", + [FACE_SOUTH ] = "south", + [FACE_WEST ] = "west", + [FACE_BOTTOM] = "bottom", +}; +day22_face g_day22_relface[6][4] = { + [FACE_TOP] = { + [FACING_RIGHT] = FACE_EAST, + [FACING_DOWN ] = FACE_SOUTH, + [FACING_LEFT ] = FACE_WEST, + [FACING_UP ] = FACE_NORTH, + }, + [FACE_EAST] = { + [FACING_RIGHT] = FACE_NORTH, + [FACING_DOWN ] = FACE_BOTTOM, + [FACING_LEFT ] = FACE_SOUTH, + [FACING_UP ] = FACE_TOP, + }, + [FACE_NORTH] = { + [FACING_RIGHT] = FACE_EAST, + [FACING_DOWN ] = FACE_TOP, + [FACING_LEFT ] = FACE_WEST, + [FACING_UP ] = FACE_BOTTOM, + }, + [FACE_SOUTH] = { + [FACING_RIGHT] = FACE_EAST, + [FACING_DOWN ] = FACE_BOTTOM, + [FACING_LEFT ] = FACE_WEST, + [FACING_UP ] = FACE_TOP, + }, + [FACE_WEST] = { + [FACING_RIGHT] = FACE_SOUTH, + [FACING_DOWN ] = FACE_BOTTOM, + [FACING_LEFT ] = FACE_NORTH, + [FACING_UP ] = FACE_TOP, + }, + [FACE_BOTTOM] = { + [FACING_RIGHT] = FACE_EAST, + [FACING_DOWN ] = FACE_NORTH, + [FACING_LEFT ] = FACE_WEST, + [FACING_UP ] = FACE_SOUTH, + }, +}; + +day22_facing g_day22_relfacing[6][4] = { + [FACE_TOP] = { + [FACING_RIGHT] = FACING_DOWN, + [FACING_DOWN ] = FACING_DOWN, + [FACING_LEFT ] = FACING_DOWN, + [FACING_UP ] = FACING_UP, + }, + [FACE_EAST] = { + [FACING_RIGHT] = FACING_LEFT, + [FACING_DOWN ] = FACING_LEFT, + [FACING_LEFT ] = FACING_LEFT, + [FACING_UP ] = FACING_LEFT, + }, + [FACE_NORTH] = { + [FACING_RIGHT] = FACING_LEFT, + [FACING_DOWN ] = FACING_DOWN, + [FACING_LEFT ] = FACING_RIGHT, + [FACING_UP ] = FACING_UP, + }, + [FACE_SOUTH] = { + [FACING_RIGHT] = FACING_RIGHT, + [FACING_DOWN ] = FACING_DOWN, + [FACING_LEFT ] = FACING_LEFT, + [FACING_UP ] = FACING_UP, + }, + [FACE_WEST] = { + [FACING_RIGHT] = FACING_RIGHT, + [FACING_DOWN ] = FACING_RIGHT, + [FACING_LEFT ] = FACING_RIGHT, + [FACING_UP ] = FACING_RIGHT, + }, + [FACE_BOTTOM] = { + [FACING_RIGHT] = FACING_UP, + [FACING_DOWN ] = FACING_DOWN, + [FACING_LEFT ] = FACING_UP, + [FACING_UP ] = FACING_UP, + }, +}; + + +typedef struct { + day22_map *map; + vec2 faces[6]; + u32 face_size; +} day22_cube_map; + +typedef struct { + day22_instruction_op op; + u32 amount; +} day22_instruction; + +typedef struct { + day22_instruction *list; + u32 count; +} day22_instructions; + +typedef struct { + day22_map map; + day22_instructions instructions; +} day22_data; + +typedef bool (*step_cb)(void*, vec2*, day22_facing*); + +static day22_tile day22_tile_from_char(char c) +{ + switch(c) { + case ' ': return TILE_VOID; + case '.': return TILE_EMPTY; + case '#': return TILE_WALL; + default: assert(false && "Unknonwn tile symbol"); + } +} + +static void* day22_parse(char** lines, int line_count) +{ + day22_data *data = malloc(sizeof(day22_data)); + data->map.height = line_count - 2; + data->map.width = strlen(lines[0]); + for (int i = 1; i < data->map.height; i++) { + data->map.width = MAX(data->map.width, strlen(lines[i])); + } + + u32 tiles_size = sizeof(day22_tile) * data->map.width * data->map.height; + data->map.tiles = malloc(tiles_size); + memset(data->map.tiles, TILE_VOID, tiles_size); + + for (int y = 0; y < data->map.height; y++) { + for (int x = 0; x < MIN(strlen(lines[y]), data->map.width); x++) { + int idx = y * data->map.width + x; + data->map.tiles[idx] = day22_tile_from_char(lines[y][x]); + } + } + + u32 capacity = 1024*4; + data->instructions.list = calloc(capacity, sizeof(day22_instruction)); + data->instructions.count = 0; + char *instructions = lines[line_count-1]; + while (instructions[0]) { + assert(data->instructions.count+1 < capacity); + + day22_instruction *inst = &data->instructions.list[data->instructions.count]; + if (instructions[0] == 'R') { + inst->op = INST_RIGHT; + instructions++; + } else if (instructions[0] == 'L') { + inst->op = INST_LEFT; + instructions++; + } else { + inst->op = INST_WALK; + inst->amount = strtol(instructions, &instructions, 10); + } + + data->instructions.count++; + } + + return data; +} + +static void day22_print_map(day22_map *map) +{ + for (int y = 0; y < map->height; y++) { + for (int x = 0; x < map->width; x++) { + u32 idx = y * map->width + x; + day22_tile tile = map->tiles[idx]; + printf("%c", g_day22_tiles[tile]); + } + printf("\n"); + } +} + +static void day22_print_instructions(day22_instructions *insts) +{ + for (int i = 0; i < insts->count; i++) { + day22_instruction *inst = &insts->list[i]; + switch (inst->op) { + case INST_WALK: + printf("%d", inst->amount); + break; + case INST_LEFT: + printf("L"); + break; + case INST_RIGHT: + printf("R"); + break; + } + } + printf("\n"); +} + +static vec2 day22_starting_pos(day22_map *map) +{ + for (int x = 0; x < map->width; x++) { + if (map->tiles[x] == TILE_EMPTY) { + vec2 pos = { .x = x, .y = 0 }; + return pos; + } + } + assert(false && "Starting pos not found"); +} + +static day22_facing day22_turn_left(day22_facing facing) +{ + return (facing - 1 + 4) % 4; +} + +static day22_facing day22_turn_right(day22_facing facing) +{ + return (facing + 1) % 4; +} + +static day22_facing day22_turn_180(day22_facing facing) +{ + return (facing + 2) % 4; +} + +static void day22_wrap_around(day22_map *map, vec2 *pos) +{ + if (pos->x >= (i32)map->width) { + pos->x -= map->width; + } else if (pos->x < 0) { + pos->x += map->width; + } else if (pos->y >= (i32)map->height) { + pos->y -= map->height; + } else if (pos->y < 0) { + pos->y += map->height; + } +} + +static bool day22_in_bounds(day22_map *map, i32 x, i32 y) +{ + return (0 <= x && x < map->width) && (0 <= y && y < map->height); +} + +static day22_tile day22_get_tile(day22_map *map, i32 x, i32 y) +{ + if (!day22_in_bounds(map, x, y)) { + return TILE_VOID; + } + u32 idx = y * map->width + x; + return map->tiles[idx]; +} + +static bool day22_step(day22_map *map, vec2 *pos, day22_facing *dir) +{ + vec2 next_pos = *pos; + vec2 *step = &g_day22_dirs[*dir]; + + next_pos.x += step->x; + next_pos.y += step->y; + day22_wrap_around(map, &next_pos); + + while (day22_get_tile(map, next_pos.x, next_pos.y) == TILE_VOID) { + next_pos.x += step->x; + next_pos.y += step->y; + day22_wrap_around(map, &next_pos); + } + + if (day22_get_tile(map, next_pos.x, next_pos.y) == TILE_EMPTY) { + pos->x = next_pos.x; + pos->y = next_pos.y; + return true; + } else { + return false; + } +} + +static void day22_walk(void *map, vec2 *pos, day22_facing *dir, u32 amount, step_cb do_step) +{ + for (int i = 0; i < amount; i++) { + if (!do_step(map, pos, dir)) { + break; + } + } +} + +static void day22_follow_instructions(void *map, day22_instructions *insts, vec2 *pos, day22_facing *dir, step_cb do_step) +{ + for (int i = 0; i < insts->count; i++) { + day22_instruction *inst = &insts->list[i]; + switch(inst->op) { + case INST_WALK: + day22_walk(map, pos, dir, inst->amount, do_step); + break; + case INST_LEFT: + *dir = day22_turn_left(*dir); + break; + case INST_RIGHT: + *dir = day22_turn_right(*dir); + break; + } + } +} + +static void day22_part1(void *p) +{ + day22_data *data = (day22_data*)p; + + day22_map *map = &data->map; + day22_instructions *insts = &data->instructions; + + vec2 pos = day22_starting_pos(map); + day22_facing dir = FACING_RIGHT; + day22_follow_instructions(map, insts, &pos, &dir, (step_cb)day22_step); + + u32 answer = (pos.y+1) * 1000 + (pos.x+1) * 4 + dir; + printf("%d\n", answer); +} + +static day22_face day22_cube_map_face(day22_cube_map *cube_map, i32 x, i32 y) +{ + x = x / cube_map->face_size * cube_map->face_size; + y = y / cube_map->face_size * cube_map->face_size; + for (int i = 0; i < ARRAY_LEN(cube_map->faces); i++) { + vec2 *face = &cube_map->faces[i]; + if (face->x == x && face->y == y) { + return i; + } + } + return 9; +} + +static void day22_print_cube_map_faces(day22_cube_map *cube_map) +{ + day22_map *map = cube_map->map; + for (int y = 0; y < map->height; y++) { + for (int x = 0; x < map->width; x++) { + u32 idx = y * map->width + x; + if (map->tiles[idx] != TILE_VOID) { + printf("%d", day22_cube_map_face(cube_map, x, y)); + } else { + printf(" "); + } + } + printf("\n"); + } +} + +static void day22_cube_map_init(day22_cube_map *cube_map, day22_map *map, vec2 *top_face) +{ + cube_map->map = map; + + u32 surface_area = 0; + for (int y = 0; y < map->height; y++) { + for (int x = 0; x < map->width; x++) { + u32 idx = y * map->width + x; + surface_area += (map->tiles[idx] != TILE_VOID); + } + } + + u32 face_size = sqrt((float)surface_area/6); + assert(face_size != 0); + + cube_map->face_size = face_size; + + + if (face_size == 4) { // Example case + cube_map->faces[FACE_TOP] = *top_face; + + cube_map->faces[FACE_SOUTH] = cube_map->faces[FACE_TOP]; + cube_map->faces[FACE_SOUTH].y += 4; + + cube_map->faces[FACE_WEST] = cube_map->faces[FACE_SOUTH]; + cube_map->faces[FACE_WEST].x -= face_size; + + cube_map->faces[FACE_NORTH] = cube_map->faces[FACE_WEST]; + cube_map->faces[FACE_NORTH].x -= face_size; + + cube_map->faces[FACE_BOTTOM] = cube_map->faces[FACE_SOUTH]; + cube_map->faces[FACE_BOTTOM].y += face_size; + + cube_map->faces[FACE_EAST] = cube_map->faces[FACE_BOTTOM]; + cube_map->faces[FACE_EAST].x += face_size; + } else { // User case + cube_map->faces[FACE_TOP] = *top_face; + + cube_map->faces[FACE_EAST] = cube_map->faces[FACE_TOP]; + cube_map->faces[FACE_EAST].x += face_size; + + cube_map->faces[FACE_SOUTH] = cube_map->faces[FACE_TOP]; + cube_map->faces[FACE_SOUTH].y += face_size; + + cube_map->faces[FACE_BOTTOM] = cube_map->faces[FACE_SOUTH]; + cube_map->faces[FACE_BOTTOM].y += face_size; + + cube_map->faces[FACE_WEST] = cube_map->faces[FACE_BOTTOM]; + cube_map->faces[FACE_WEST].x -= face_size; + + cube_map->faces[FACE_NORTH] = cube_map->faces[FACE_WEST]; + cube_map->faces[FACE_NORTH].y += face_size; + } + + // TODO: To hell with this, too complicated for now. Stitching cube faces + // https://www.youtube.com/watch?v=qWgLdNFYDDo + /* + bool found_faces[6] = { 0 }; + day22_face stack_faces[6]; + day22_facing stack_incoming_facing[6]; + vec2 stack_positions[6]; + int stack_size; + static_assert(ARRAY_LEN(stack_faces) == ARRAY_LEN(stack_positions), "stack size is inconsistent"); + + stack_positions[0] = *top_face; + stack_faces[0] = FACE_TOP; + stack_incoming_facing[0] = FACING_DOWN; + found_faces[FACE_TOP] = true; + stack_size = 1; + + while (stack_size > 0) { + vec2 pos = stack_positions[stack_size-1]; + day22_face face = stack_faces[stack_size-1]; + day22_facing initial_facing = stack_incoming_facing[stack_size-1]; + stack_size--; + + cube_map->faces[face] = pos; + + day22_facing new_facings[] = { + initial_facing, + day22_turn_left(initial_facing), + day22_turn_right(initial_facing) + }; + for (int i = 0; i < ARRAY_LEN(new_facings); i++) { + day22_facing new_facing = new_facings[i]; + vec2 *dir = &g_day22_dirs[new_facing]; + // if (face == FACE_NORTH) { + // dir = &g_day22_dirs[day22_turn_180(new_facing)]; + // } + + i32 x = pos.x + face_size * dir->x; + i32 y = pos.y + face_size * dir->y; + if (day22_in_bounds(map, x, y) && day22_get_tile(map, x, y) != TILE_VOID) { + // day22_facing rel_new_facing = (4 + initial_facing - new_facing) % 4; + day22_face new_face = g_day22_relface[face][new_facing]; + + printf("found face %s(%d) from %s(%d) by going %s(%d)\n", g_day22_face_str[new_face], new_face, g_day22_face_str[face], face, g_day22_facing_str[new_facing], new_facing); + if (found_faces[new_face]) { + printf("already found\n"); + continue; + } + stack_positions[stack_size].x = x; + stack_positions[stack_size].y = y; + stack_faces[stack_size] = new_face; + stack_incoming_facing[stack_size] = new_facing; + found_faces[new_face] = true; + + stack_size++; + assert(stack_size < ARRAY_LEN(stack_positions)); + } + } + } + */ +} + +static void day22_map_edge(day22_cube_map *cube_map, day22_face from_face, day22_facing from_facing, day22_face to_face, day22_facing to_facing, vec2 *pos) +{ + // TODO: +} + +static bool day22_cube_step(day22_cube_map *cube_map, vec2 *pos, day22_facing *dir) +{ + day22_facing next_dir = *dir; + vec2 next_pos = *pos; + + next_pos.x += g_day22_dirs[next_dir].x; + next_pos.y += g_day22_dirs[next_dir].y; + + if (day22_get_tile(cube_map->map, next_pos.x, next_pos.y) == TILE_VOID) { + day22_face face = day22_cube_map_face(cube_map, pos->x, pos->y); + day22_face new_face = g_day22_relface[face][*dir]; + next_dir = g_day22_relfacing[face][*dir]; + day22_map_edge(cube_map, face, *dir, new_face, next_dir, &next_pos); + } + + if (day22_get_tile(cube_map->map, next_pos.x, next_pos.y) == TILE_EMPTY) { + pos->x = next_pos.x; + pos->y = next_pos.y; + *dir = next_dir; + return true; + } else { + return false; + } +} + +static void assert_face_table_is_correct() +{ + for (int face = 0; face < ARRAY_LEN(g_day22_relface); face++) { + for (int facing = 0; facing < ARRAY_LEN(g_day22_relface[face]); facing++) { + day22_face new_face = g_day22_relface[face][facing]; + day22_facing new_facing = g_day22_relfacing[face][facing]; + + int new_facing_180 = day22_turn_180(new_facing); + assert(face == g_day22_relface[new_face][new_facing_180]); + } + } +} + +static void day22_part2(void *p) +{ + assert_face_table_is_correct(); + + day22_data *data = (day22_data*)p; + + day22_map *map = &data->map; + day22_instructions *insts = &data->instructions; + + vec2 start = day22_starting_pos(map); + + day22_cube_map cube_map = { 0 }; + day22_cube_map_init(&cube_map, map, &start); + + day22_print_cube_map_faces(&cube_map); + + vec2 pos = start; + day22_facing dir = FACING_RIGHT; + // day22_follow_instructions(&cube_map, insts, &pos, &dir, (step_cb)day22_cube_step); + + // u32 answer = (pos.y+1) * 1000 + (pos.x+1) * 4 + dir; + // printf("%d\n", answer); +} + +ADD_SOLUTION(22, day22_parse, day22_part1, day22_part2); diff --git a/main.c b/main.c index a3da82f..ca677f1 100644 --- a/main.c +++ b/main.c @@ -30,6 +30,7 @@ #include "day19.c" #include "day20.c" #include "day21.c" +#include "day22.c" Solution *find_solution(int day) {