day 18 part 1 (with tons of debug)
This commit is contained in:
2
2021/day18/EXAMPLE1.txt
Normal file
2
2021/day18/EXAMPLE1.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
[[[[4,3],4],4],[7,[[8,4],9]]]
|
||||||
|
[1,1]
|
@@ -19,12 +19,13 @@ LIB := aoc_$(shell uname -m)
|
|||||||
INCDIR := ../include
|
INCDIR := ../include
|
||||||
LIBDIR := ../lib
|
LIBDIR := ../lib
|
||||||
LDFLAGS := -L$(LIBDIR)
|
LDFLAGS := -L$(LIBDIR)
|
||||||
LDLIB := -l$(LIB) -lm
|
#LDLIB := -l$(LIB) -lm
|
||||||
|
LDLIB := -l$(LIB)
|
||||||
|
|
||||||
export LD_LIBRARY_PATH = $(LIBDIR)
|
export LD_LIBRARY_PATH = $(LIBDIR)
|
||||||
|
|
||||||
CFLAGS += -std=gnu99
|
CFLAGS += -std=gnu99
|
||||||
CFLAGS += -O2
|
#CFLAGS += -O2
|
||||||
CFLAGS += -g
|
CFLAGS += -g
|
||||||
#CFLAGS += -pg
|
#CFLAGS += -pg
|
||||||
CFLAGS += -Wall
|
CFLAGS += -Wall
|
||||||
|
@@ -160,3 +160,31 @@ The final sum is:
|
|||||||
The magnitude of this final sum is 4140.
|
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?
|
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?
|
||||||
|
432
2021/day18/aoc-c.c
Normal file
432
2021/day18/aoc-c.c
Normal file
@@ -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 <https://www.gnu.org/licenses/gpl-3.0-standalone.html>.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#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);
|
||||||
|
}
|
Reference in New Issue
Block a user