From 8d3a064c734f9cddc752e73625fe667703a6136b Mon Sep 17 00:00:00 2001 From: Bruno Raoult Date: Fri, 7 Jan 2022 20:33:01 +0100 Subject: [PATCH] day 18 part 1 (with tons of debug) --- 2021/day18/EXAMPLE1.txt | 2 + 2021/day18/Makefile | 5 +- 2021/day18/README.txt | 28 +++ 2021/day18/aoc-c.c | 432 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 465 insertions(+), 2 deletions(-) create mode 100644 2021/day18/EXAMPLE1.txt create mode 100644 2021/day18/aoc-c.c diff --git a/2021/day18/EXAMPLE1.txt b/2021/day18/EXAMPLE1.txt new file mode 100644 index 0000000..61b0df6 --- /dev/null +++ b/2021/day18/EXAMPLE1.txt @@ -0,0 +1,2 @@ +[[[[4,3],4],4],[7,[[8,4],9]]] +[1,1] diff --git a/2021/day18/Makefile b/2021/day18/Makefile index 2a7ec46..9015b96 100644 --- a/2021/day18/Makefile +++ b/2021/day18/Makefile @@ -19,12 +19,13 @@ LIB := aoc_$(shell uname -m) INCDIR := ../include LIBDIR := ../lib LDFLAGS := -L$(LIBDIR) -LDLIB := -l$(LIB) -lm +#LDLIB := -l$(LIB) -lm +LDLIB := -l$(LIB) export LD_LIBRARY_PATH = $(LIBDIR) CFLAGS += -std=gnu99 -CFLAGS += -O2 +#CFLAGS += -O2 CFLAGS += -g #CFLAGS += -pg CFLAGS += -Wall diff --git a/2021/day18/README.txt b/2021/day18/README.txt index a156ed7..9d9a95c 100644 --- a/2021/day18/README.txt +++ b/2021/day18/README.txt @@ -160,3 +160,31 @@ The final sum is: The magnitude of this final sum is 4140. Add up all of the snailfish numbers from the homework assignment in the order they appear. What is the magnitude of the final sum? + +Your puzzle answer was 3987. + +The first half of this puzzle is complete! It provides one gold star: * +--- Part Two --- + +You notice a second question on the back of the homework assignment: + +What is the largest magnitude you can get from adding only two of the snailfish numbers? + +Note that snailfish addition is not commutative - that is, x + y and y + x can produce different results. + +Again considering the last example homework assignment above: + +[[[0,[5,8]],[[1,7],[9,6]]],[[4,[1,2]],[[1,4],2]]] +[[[5,[2,8]],4],[5,[[9,9],0]]] +[6,[[[6,2],[5,6]],[[7,6],[4,7]]]] +[[[6,[0,7]],[0,9]],[4,[9,[9,0]]]] +[[[7,[6,4]],[3,[1,3]]],[[[5,5],1],9]] +[[6,[[7,3],[3,2]]],[[[3,8],[5,7]],4]] +[[[[5,4],[7,7]],8],[[8,3],8]] +[[9,3],[[9,9],[6,[4,9]]]] +[[2,[[7,7],7]],[[5,8],[[9,3],[0,2]]]] +[[[[5,2],5],[8,[3,7]]],[[5,[7,5]],[4,4]]] + +The largest magnitude of the sum of any two snailfish numbers in this list is 3993. This is the magnitude of [[2,[[7,7],7]],[[5,8],[[9,3],[0,2]]]] + [[[0,[5,8]],[[1,7],[9,6]]],[[4,[1,2]],[[1,4],2]]], which reduces to [[[[7,8],[6,6]],[[6,0],[7,7]]],[[[7,8],[8,8]],[[7,9],[0,6]]]]. + +What is the largest magnitude of any sum of two different snailfish numbers from the homework assignment? diff --git a/2021/day18/aoc-c.c b/2021/day18/aoc-c.c new file mode 100644 index 0000000..1483f37 --- /dev/null +++ b/2021/day18/aoc-c.c @@ -0,0 +1,432 @@ +/* aoc-c.c: Advent of Code 2021, day 18 parts 1 & 2 + * + * Copyright (C) 2021 Bruno Raoult ("br") + * Licensed under the GNU General Public License v3.0 or later. + * Some rights reserved. See COPYING. + * + * You should have received a copy of the GNU General Public License along with this + * program. If not, see . + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#include +#include +#include + +#include "pool.h" +#include "debug.h" +#include "bits.h" +#include "list.h" + +#define POISON_VALUE -232323 +#define POISON_DEPTH 121212; + +#define PARENT 0 +#define LEFT 1 +#define RIGHT 2 + +static pool_t *pool_nodes; + +#define MAX_LINES 128 +static char *lines[MAX_LINES]; +static int nlines; + +typedef struct node { + s64 val; + struct node *tree[3]; /* parent, left, right */ + struct list_head leaf_list; /* head is tree root */ + u32 depth; +} node_t; + + +/* print leaves list + */ +static void leaves_print(node_t *root) +{ + node_t *list_cur; + log_i(2, "leaves:"); + list_for_each_entry(list_cur, &root->leaf_list, leaf_list) { + log_i(2, " %d", list_cur->val); + } + log_i(2, "\n"); +} + +/* print node tree + */ +static void node_print(node_t *node) +{ + if (!node->depth) + log_f(1, ""); + if (!node->tree[LEFT]) { /* leaf */ + log(1, "%ld", node->val); + } else { + log(1, "["); + node_print(node->tree[LEFT]); + log(1, ","); + node_print(node->tree[RIGHT]); + log(1, "]"); + } + if (!node->depth) { + log(1, "\n"); + leaves_print(node); + } +} + +static inline node_t *node_get() +{ + node_t *node = pool_get(pool_nodes); + + node->depth = POISON_DEPTH; + node->val = POISON_VALUE; + node->tree[LEFT] = NULL; + node->tree[RIGHT] = NULL; + node->tree[PARENT] = NULL; + INIT_LIST_HEAD(&node->leaf_list); + return node; +} + +/* split_node - split first node with value >= 10 + * return: 1: finished + */ +static int node_split(node_t *node) +{ + int depth = node->depth; + static node_t *root; + + if (depth == 0) + root = node; + //if (node->depth == 0) + log_f(2, "entering node %p: val=%d left=%p right=%p\n", node, node->val, + node->tree[LEFT], node->tree[RIGHT]); + + if (node->tree[LEFT]) { + if (node_split(node->tree[LEFT]) || node_split(node->tree[RIGHT])) + return 1; + } else { + if (node->val >= 10) { /* eligible leaf */ + //node_t *leaf_left = list_prev_entry(node, leaf_list); + node_t *left, *right; + + log_i(2, "splitting [%ld,%ld]\n", node->val); + + /* create and populate new nodes */ + left = node_get(); + left->depth = node->depth + 1; + left->val = node->val / 2; + + right = node_get(); + right->depth = node->depth + 1; + right->val = (node->val + 1) / 2; + + node->tree[LEFT] = left; + node->tree[RIGHT] = right; + node->val = POISON_VALUE; + + /* add new nodes in leaves list, remove current one */ + list_add(&node->tree[RIGHT]->leaf_list, &node->leaf_list); + list_add(&node->tree[LEFT]->leaf_list, &node->leaf_list); + list_del(&node->leaf_list); + log_i(2, "after split: \n\t"); + node_print(root); + return 1; + } + } + if (node->depth == 0) { + log_f(2, "return:\n\t"); + node_print(node); + } + return 0; +} + +/* explode node - explode first node with level == 4 + * return: 1: finished + */ +static int node_explode(node_t *node) +{ + int depth = node->depth; + static node_t *root; + + if (depth == 0) { + root = node; + + log_f(2, "entering node %p: val=%d left=%p right=%p\n", node, node->val, + node->tree[LEFT], node->tree[RIGHT]); + } + if (depth == 4) { + node_t *left = node->tree[LEFT], *right = node->tree[RIGHT]; + node_t *tmp; + //struct list_head *tmp; + + /* skip leaves */ + if (!left) + return 0; + + log_i(2, "exploding [%ld,%ld]\n", left->val, right->val); + //log_i(2, "zobu: "); + //node_print(root); + + /* increment left leaf */ + if (!list_is_first(&left->leaf_list, &root->leaf_list)) { + node_t *tmpnode = list_prev_entry(left, leaf_list); + tmpnode->val += left->val; + } + /* increment right leaf */ + if (!list_is_last(&right->leaf_list, &root->leaf_list)) { + node_t *tmpnode = list_next_entry(right, leaf_list); + tmpnode->val += right->val; + } + + //log_i(2, "zobi: "); + //node_print(root); + /* remove leaves from list, and add current one */ + //tmp = list_entry(left, node_t, leaf_list); + node->val = 0; + + list_add(&node->leaf_list, &left->leaf_list); + //log_i(2, "zoba: n=%p l=%p) ", &node->leaf_list, &left->leaf_list); + //node_print(root); + + //list_del(&left->leaf_list); + //list_del(left->leaf_list.prev); + + //list_del(&node->leaf_list->prev); + //tmp = list_prev_entry(node, leaf_list); + //log_i(2, "zoby: n=%p l=%p) ", &node->leaf_list, &left->leaf_list); + list_del(&left->leaf_list); + //node->leaf_list.prev; + //log_i(2, "zobe: "); + //node_print(root); + pool_add(pool_nodes, left); + + list_del(&right->leaf_list); + //log_i(2, "zobo: "); + //node_print(root); + pool_add(pool_nodes, right); + + /* remove childs links */ + node->tree[LEFT] = NULL; + node->tree[RIGHT] = NULL; + + //log_i(2, "after reduce: "); + //node_print(root); + return 1; + } else { + if (node->tree[LEFT]) { + if (node_explode(node->tree[LEFT]) || node_explode(node->tree[RIGHT])) + return 1; + } + } + return 0; +} + +static node_t *node_reduce(node_t *node) +{ + //log_f(2, ""); + //node_explode(node); + //node_explode(node); + //return node; + while (1) { + log_f(2, "\t"); + node_print(node); + if (node_explode(node)) + continue; + if (node_split(node)) + continue; + break; + } + return node; +} + +/* promote/demode node + */ +static node_t *node_promote(node_t *node, int promote) +{ + node->depth += promote; + if (node->tree[LEFT]) { + node_promote(node->tree[LEFT], promote); + node_promote(node->tree[RIGHT], promote); + } + return node; +} + +/* add 2 nodes + */ +static node_t *node_add(node_t *n1, node_t *n2) +{ + node_t *head = pool_get(pool_nodes); + + log_f(2, "\n"); + node_print(n1); + node_print(n2); + head->depth = 0; + INIT_LIST_HEAD(&head->leaf_list); + + /* create new tree from the two + */ + head->tree[LEFT] = node_promote(n1, 1); + head->tree[RIGHT] = node_promote(n2, 1); + n1->tree[PARENT] = head; + n2->tree[PARENT] = head; + + /* link leaves + */ + //head->leaf_list = n1->leaf_list; + list_splice_tail(&n1->leaf_list, &head->leaf_list); + list_splice_tail(&n2->leaf_list, &head->leaf_list); + //node_print(head); + return head; +} + +/* read node, from '[' to corresponding ']' + */ +static node_t *node_read(char **p, int depth)//, node_t *parent) +{ + static node_t *root; + node_t *node = node_get(); + + node->depth = depth; + + if (!depth) /* root node */ + root = node; + + //log_f(2, "str=%s depth=%d\n", *p, depth); + switch (**p) { + case '[': + (*p)++; + node->tree[LEFT] = node_read(p, depth+1); + node->tree[LEFT]->tree[PARENT] = node; + //log_i(2, "comma = %c\n", **p); + (*p)++; + node->tree[RIGHT] = node_read(p, depth+1); + node->tree[RIGHT]->tree[PARENT] = node; + //log_i(2, "closing = %c\n", **p); + break; + default: /* number */ + //log_i(2, "number = %c\n", **p); + node->val = **p - '0'; + list_add_tail(&node->leaf_list, &root->leaf_list); + } + (*p)++; + return node; +} + +/* read line, create a tree + */ +static node_t *read_line() +{ + node_t *head = NULL; + size_t alloc = 0; + char *buf, *p; + ssize_t buflen; + + if ((buflen = getline(&buf, &alloc, stdin)) > 0) { + p = buf; + buf[--buflen] = 0; + head = node_read(&p, 0); + } + free(buf); + //node_print(head); + return head; +} + +/* read input + */ +static int read_lines() +{ + size_t alloc = 0; + ssize_t buflen; + + while ((buflen = getline(&lines[nlines], &alloc, stdin)) > 0) { + lines[nlines][--buflen] = 0; + nlines++; + } + return nlines; +} + +/* free lines memory + */ +static void free_lines() +{ + for (int i = 0; i < nlines; ++i) + free(lines[i]); +} + +static s64 node_magnitude(node_t *node) +{ + if (!node->tree[LEFT]) + return node->val; + return 3 * node_magnitude(node->tree[LEFT]) + + 2 * node_magnitude(node->tree[RIGHT]); +} + +static s64 part1() +{ + node_t *head = NULL, *next = NULL; + s64 res = 1; + + head = node_read(lines + 0, 0); + for (int i = 1; i < nlines; ++i) { + next = node_read(lines + i, 0); + head = node_reduce(node_add(head, next)); + } + node_print(head); + return node_magnitude(head); +} + +static s64 part2() +{ + s64 res = 2; + return res; +} + +static int usage(char *prg) +{ + fprintf(stderr, "Usage: %s [-d debug_level] [-p part]\n", prg); + return 1; +} + +int main(int ac, char **av) +{ + int opt, part = 1; + + while ((opt = getopt(ac, av, "d:p:")) != -1) { + switch (opt) { + case 'd': + debug_level_set(atoi(optarg)); + break; + case 'p': /* 1 or 2 */ + part = atoi(optarg); + if (part < 1 || part > 2) + return usage(*av); + break; + default: + return usage(*av); + } + } + if (optind < ac) + return usage(*av); + + if (!(pool_nodes = pool_create("nodes", 1024, sizeof(node_t)))) + exit(1); + read_lines(); + printf("%s : res=%ld\n", *av, part == 1? part1(): part2()); + exit(0); + node_t *n1, *n2, *n3, *n4; + n1 = read_line(); + n2 = read_line(); + //node_print(n1); + //node_print(n2); + n3 = node_add(n1, n2); + //node_print(n3); + n4 = node_reduce(n3); + node_print(n4); + free_lines(); + exit(0); + //node_print(n1); + //node_print(n2); + n3 = node_add(n1, n2); + node_print(n3); + printf("%s : res=%ld\n", *av, part == 1? part1(): part2()); + exit (0); +}