advent2021

Advent of Code 2021 Solutions
git clone git://bsandro.tech/advent2021
Log | Files | Refs

commit 97089615314bbf37377e8a1bd02dd591fbdf8c4d
parent d836c1292cf2a87c207c2d40388826bbf81c6195
Author: bsandro <[email protected]>
Date:   Sun, 19 Dec 2021 17:32:52 +0200

Day 18, puzzles 1+2

Diffstat:
Mcommon/util.c | 20++++++++++++++++++++
Mcommon/util.h | 2++
Mday18/Makefile | 2+-
Mday18/puzzle.c | 276+++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------------
4 files changed, 223 insertions(+), 77 deletions(-)

diff --git a/common/util.c b/common/util.c @@ -12,6 +12,19 @@ void array_init(struct array_t *array, size_t elem_size, size_t cap) { assert(array->data != NULL); } +struct array_t array_copy(struct array_t *array) { + assert(array != NULL); + assert(array->data != NULL); + struct array_t ar_copy = { .data = NULL }; + array_init(&ar_copy, array->elem_size, array->count); + assert(ar_copy.data != NULL); + memcpy(ar_copy.data, array->data, array->count * array->elem_size); + ar_copy.count = array->count; + ar_copy.cap = ar_copy.count; + ar_copy.elem_size = ar_copy.elem_size; + return ar_copy; +} + void array_expand(struct array_t *array) { size_t new_cap = array->cap * 2; array->data = realloc(array->data, array->elem_size * new_cap); @@ -19,6 +32,13 @@ void array_expand(struct array_t *array) { array->cap = new_cap; } +void array_expand1(struct array_t *array, size_t incr) { + size_t new_cap = array->cap + incr; + array->data = realloc(array->data, array->elem_size * new_cap); + assert(array->data != NULL); + array->cap = new_cap; +} + /* ******************* parse plain numbers array *******************/ void parse_numbers_array(struct array_t *numbers, const char *str, const char *delim) { assert(numbers != NULL); diff --git a/common/util.h b/common/util.h @@ -32,6 +32,8 @@ struct array_t { void array_init(struct array_t *array, size_t elem_size, size_t cap); void array_expand(struct array_t *array); +void array_expand1(struct array_t *array, size_t incr); +struct array_t array_copy(struct array_t *array); /* ******************* parse plain numbers array *******************/ void parse_numbers_array(struct array_t *numbers, const char *str, const char *delim); diff --git a/day18/Makefile b/day18/Makefile @@ -3,7 +3,7 @@ SRC=$(wildcard *.c ../common/*.c) DEPS:=$(wildcard *.h ../common/*.h) OBJ:=$(SRC:.c=.o) CFLAGS=-O0 -g -std=c99 -Werror -Wall -Wextra -I. -I../common -LDFLAGS=-lc +LDFLAGS=-lc -lm all: $(NAME) diff --git a/day18/puzzle.c b/day18/puzzle.c @@ -8,23 +8,28 @@ #include <assert.h> #include <stdbool.h> #include <unistd.h> +#include <math.h> #include "util.h" #define STR_LEN 1024 -struct pair_t { - int *left; - int *right; - struct pair_t *pleft; - struct pair_t *pright; - int **leftmost; - int **rightmost; - struct pair_t *parent; +struct num_t { + int value; + int depth; }; -size_t make_pair(const char *str, struct pair_t *parent, struct pair_t **pair_ptr); -void print_pair(struct pair_t *pair); +void parse(const char *str, struct array_t *array); +void print_nums(struct array_t *array); +void array_remove(struct array_t *nums, size_t index); +void array_insert(struct array_t *nums, size_t index, struct num_t num); +void array_add(struct array_t *nums, struct num_t num); +bool explode(struct array_t *nums); +bool split(struct array_t *nums); +void add(struct array_t *to, struct array_t *from); +int magnitude(struct array_t *nums); +int max_magnitude(struct array_t *all_nums); +int compare(const void *l, const void *r); void puzzle(const char *filename, long long *result1, long long *result2) { FILE *infile = fopen(filename, "r"); @@ -39,93 +44,212 @@ void puzzle(const char *filename, long long *result1, long long *result2) { *result1 = 0; *result2 = 0; - struct array_t pairs = { .data = NULL }; - array_init(&pairs, sizeof(void *), 10); + struct array_t nums = { .data = NULL }; + array_init(&nums, sizeof(struct num_t), 10); + + struct array_t all_nums = { .data = NULL }; + array_init(&all_nums, sizeof(struct array_t), 10); while (fgets(buf, STR_LEN, infile) != NULL) { - size_t len = strlen(buf); - assert(len != 0); - struct pair_t *pair = NULL; - size_t processed = make_pair(buf, NULL, &pair); - printf("len:%zu, processed:%zu\n", len, processed); - if (pairs.count >= pairs.cap) array_expand(&pairs); - ((struct pair_t **)pairs.data)[pairs.count++] = pair; - - printf("str: %s", buf); - printf("pair: "); - print_pair(pair); - printf("\n"); - - break; + if (all_nums.count >= all_nums.cap) array_expand(&all_nums); + + struct array_t nums_add = { .data = NULL }; + array_init(&nums_add, sizeof(struct num_t), 10); + parse(buf, &nums_add); + + ((struct array_t *)all_nums.data)[all_nums.count++] = array_copy(&nums_add); + if (nums.count == 0) { // first line + nums = nums_add; + continue; + } + add(&nums, &nums_add); + while (explode(&nums) || split(&nums)) { + // + } ++line_num; bzero(buf, STR_LEN); } + *result1 = magnitude(&nums); + *result2 = max_magnitude(&all_nums); + + free(nums.data); // mutiny! ignoring feof/ferror. fclose(infile); } -size_t make_pair(const char *str, struct pair_t *parent, struct pair_t **pair_ptr) { - printf("pair start\n"); +int compare(const void *l, const void *r) { + return *(int *)r - *(int *)l; +} + +int max_magnitude(struct array_t *all_nums) { + struct array_t magnitudes = { .data = NULL }; + array_init(&magnitudes, sizeof(int), all_nums->count * all_nums->count); + int *magnitudes_data = magnitudes.data; + assert(magnitudes_data != NULL); + + struct array_t *all_nums_data = all_nums->data; + for (size_t i = 0; i < all_nums->count; ++i) { + for (size_t j = 0; j < all_nums->count; ++j) { + if (i == j) continue; + struct array_t nums_copy = array_copy(&all_nums_data[i]); + add(&nums_copy, &all_nums_data[j]); + while (explode(&nums_copy) || split(&nums_copy)) { + // + } + magnitudes_data[magnitudes.count++] = magnitude(&nums_copy); + free(nums_copy.data); + } + } - assert(str != NULL); - struct pair_t *pair = malloc(sizeof(struct pair_t)); - bzero(pair, sizeof(struct pair_t)); - printf("pair_ptr: %p, *pair_ptr: %p\n", pair_ptr, *pair_ptr); - *pair_ptr = pair; + qsort(magnitudes_data, magnitudes.count, magnitudes.elem_size, compare); + int max_mag = magnitudes_data[0]; + free(magnitudes.data); + return max_mag; +} - pair->parent = parent; - if (parent != NULL) { - pair->leftmost = parent->leftmost; - pair->rightmost = parent->rightmost; +int magnitude(struct array_t *nums) { + assert(nums != NULL); + while (nums->count > 1) { + struct num_t *data = nums->data; + for (size_t i = 0; i < nums->count-1; ++i) { + if (data[i].depth == data[i+1].depth) { + int mag = data[i].value*3 + data[i+1].value*2; + struct num_t mul = {.value=mag, .depth=data[i].depth-1}; + data[i] = mul; + array_remove(nums, i+1); + break; + } + } } + struct num_t *data = nums->data; + return data[0].value; +} - assert(str[0] == '['); - size_t processed = 1; - - if (str[processed] == '[') { - printf("making left pair...\n"); - processed += make_pair(str+processed, pair, &pair->pleft); - } else if (str[processed] >= '0' && str[processed] <= '9') { - pair->left = malloc(sizeof(int)); - *pair->left = str[processed] - '0'; - pair->leftmost = &pair->left; - printf("left num %d\n", *pair->left); +void add(struct array_t *to, struct array_t *from) { + assert(to != NULL); + assert(from != NULL); + assert(to->elem_size == from->elem_size); + array_expand1(to, to->cap + from->cap); + assert(to->data != NULL); + struct num_t *to_data = to->data; + struct num_t *from_data = from->data; + for (size_t i = 0; i < to->count; ++i) { + to_data[i].depth++; + } + for (size_t i = 0; i < from->count; ++i) { + struct num_t num = from_data[i]; + num.depth++; + to_data[to->count++] = num; } +} - processed++; - assert(str[processed] == ','); - processed++; - - if (str[processed] == '[') { - printf("making right pair...\n"); - processed += make_pair(str+processed, pair, &pair->pright); - } else if (str[processed] >= '0' && str[processed] <= '9') { - pair->right = malloc(sizeof(int)); - *pair->right = str[processed] - '0'; - pair->rightmost = &pair->right; - printf("right num %d\n", *pair->right); +bool explode(struct array_t *nums) { + assert(nums->count > 1); + struct num_t *array = nums->data; + for (size_t i = 0; i < nums->count-1; ++i) { + if (array[i].depth > 4 && array[i].depth == array[i+1].depth) { + if (i > 0) { + array[i-1].value += array[i].value; + } + if (i < nums->count-2) { + array[i+2].value += array[i+1].value; + } + array[i].depth--; + array[i].value = 0; + array_remove(nums, i+1); + return true; + } } + return false; +} - processed++; - assert(str[processed] == ']'); - printf("pair end\n"); +bool split(struct array_t *nums) { + assert(nums->count > 1); + struct num_t *array = nums->data; + for (size_t i = 0; i < nums->count; ++i) { + if (array[i].value > 9) { + double l = floor((double)array[i].value / 2.0); + double r = ceil((double)array[i].value / 2.0); + int depth = array[i].depth; + array_remove(nums, i); + array = nums->data; + if (i >= nums->count) { + array_add(nums, (struct num_t){.value=l, .depth=depth+1}); + array_add(nums, (struct num_t){.value=r, .depth=depth+1}); + } else { + array_insert(nums, i, (struct num_t){.value=r, .depth=depth+1}); + array_insert(nums, i, (struct num_t){.value=l, .depth=depth+1}); + } + return true; + } + } + return false; +} - return processed; +void parse(const char *str, struct array_t *array) { + size_t len = strlen(str); + int depth = 0; + for (size_t i = 0; i < len-1; ++i) { + if (str[i] == '[') { + depth++; + } else if (str[i] == ']') { + depth--; + } else if (str[i] >= '0' && str[i] <= '9') { + if (array->count >= array->cap) array_expand(array); + ((struct num_t *)array->data)[array->count++] = (struct num_t){.value=str[i]-'0', .depth=depth}; + } + } +} + +void print_nums(struct array_t *array) { + struct num_t *nums = array->data; + for (size_t i = 0; i < array->count; ++i) { + printf("%2d,", nums[i].value); + } + printf("\n"); } -void print_pair(struct pair_t *pair) { - printf("["); - if (pair->pleft != NULL) { - print_pair(pair->pleft); - } else { - printf("%d", *pair->left); +void array_remove(struct array_t *nums, size_t index) { + assert(index < nums->count); + struct num_t *data = nums->data; + struct num_t *new_data = calloc(nums->count-1, nums->elem_size); + assert(new_data != NULL); + size_t new_count = 0; + for (size_t i = 0; i < nums->count; ++i) { + if (i != index) { + new_data[new_count++] = data[i]; + } } - printf(","); - if (pair->pright != NULL) { - print_pair(pair->pright); - } else { - printf("%d", *pair->right); + free(data); + nums->data = new_data; + nums->count = new_count; + nums->cap = new_count; +} + +void array_insert(struct array_t *nums, size_t index, struct num_t num) { + assert(index < nums->count); + struct num_t *data = nums->data; + struct num_t *new_data = calloc(nums->count + 1, nums->elem_size); + assert(new_data != NULL); + size_t new_count = 0; + for (size_t i = 0; i < nums->count; ++i) { + if (i == index) { + new_data[new_count++] = num; + new_data[new_count++] = data[i]; + } else { + new_data[new_count++] = data[i]; + } } - printf("]"); + nums->data = new_data; + nums->count = new_count; + nums->cap = new_count; +} + + +void array_add(struct array_t *nums, struct num_t num) { + assert(nums != NULL); + if (nums->count >= nums->cap) array_expand(nums); + struct num_t *data = nums->data; + data[nums->count++] = num; }