Snailfish data structure diagram + cosmetic changes

This commit is contained in:
2022-01-12 11:02:51 +01:00
parent a88aa2312b
commit 457b3eb9b9

View File

@@ -18,19 +18,37 @@
#include "debug.h" #include "debug.h"
#include "list.h" #include "list.h"
/* Data structure : A snailfish number (SN) is represented as a binary tree and a
* (doubly) linked list LL for leaves (= decimal numbers).
* The latter will allow to easily find previous/next number.
*
* Example, [1,[4,2]] is represented as :
*
* ------> SN root <-------------- Depth: 0
* | / \ |
* LL| / \ |
* | / \ |LL
* --> 1 <--- SN node | Depth: 1
* | / \ |
* | / \ |
* LL---> 4 <-------> 2 <-- Depth: 2
* LL
*/
static pool_t *pool_nodes; static pool_t *pool_nodes;
#define MAX_LINES 128 /* I know, I know... */ #define MAX_LINES 128 /* I know, I know... */
static char *lines[MAX_LINES]; static char *lines[MAX_LINES];
static int nlines; static int nlines;
#define LEFT 0 #define LEFT 0
#define RIGHT 1 #define RIGHT 1
#define IS_LEAF(node) (!(node)->tree[LEFT])
#define IS_LEAF(node) (!(node)->left)
typedef struct node { typedef struct node {
int val; int val;
struct node *tree[2]; /* left & right subtrees */ struct node *left, *right;
struct list_head leaf_list; /* tree root is list head */ struct list_head leaf_list; /* tree root is list head */
} node_t; } node_t;
@@ -40,8 +58,8 @@ static inline node_t *node_get()
{ {
node_t *node = pool_get(pool_nodes); node_t *node = pool_get(pool_nodes);
node->tree[LEFT] = NULL; node->left = NULL;
node->tree[RIGHT] = NULL; node->right = NULL;
return node; return node;
} }
@@ -50,8 +68,8 @@ static inline node_t *node_get()
static inline void node_free(node_t *node) static inline void node_free(node_t *node)
{ {
if (!IS_LEAF(node)) { if (!IS_LEAF(node)) {
node_free(node->tree[LEFT]); node_free(node->left);
node_free(node->tree[RIGHT]); node_free(node->right);
} }
pool_add(pool_nodes, node); pool_add(pool_nodes, node);
} }
@@ -72,17 +90,17 @@ static int node_split(node_t *node)
right = node_get(); right = node_get();
right->val = (node->val + 1) / 2; right->val = (node->val + 1) / 2;
node->tree[LEFT] = left; node->left = left;
node->tree[RIGHT] = right; node->right = right;
/* add new nodes in leaves list, remove current one */ /* add new nodes in leaves list, remove current one */
list_add(&node->tree[RIGHT]->leaf_list, &node->leaf_list); list_add(&node->right->leaf_list, &node->leaf_list);
list_add(&node->tree[LEFT]->leaf_list, &node->leaf_list); list_add(&node->left->leaf_list, &node->leaf_list);
list_del(&node->leaf_list); list_del(&node->leaf_list);
return 1; return 1;
} }
} else { } else {
return node_split(node->tree[LEFT]) || node_split(node->tree[RIGHT]); return node_split(node->left) || node_split(node->right);
} }
return 0; return 0;
} }
@@ -95,9 +113,9 @@ static int node_explode(node_t *node, int depth)
static node_t *root; static node_t *root;
node_t *left, *right; node_t *left, *right;
if (!(left = node->tree[LEFT])) if (!(left = node->left))
return 0; return 0;
right = node->tree[RIGHT]; right = node->right;
/* Need to keep leaves list head */ /* Need to keep leaves list head */
if (depth == 0) if (depth == 0)
@@ -110,10 +128,10 @@ static int node_explode(node_t *node, int depth)
if (!list_is_last(&right->leaf_list, &root->leaf_list)) if (!list_is_last(&right->leaf_list, &root->leaf_list))
list_next_entry(right, leaf_list)->val += right->val; list_next_entry(right, leaf_list)->val += right->val;
/* node becomes a leaf */ /* current node becomes a leaf */
node->val = 0; node->val = 0;
node->tree[LEFT] = NULL; node->left = NULL;
node->tree[RIGHT] = NULL; node->right = NULL;
list_add(&node->leaf_list, &left->leaf_list); list_add(&node->leaf_list, &left->leaf_list);
/* remove children from leaves list, and put back in mem pool */ /* remove children from leaves list, and put back in mem pool */
@@ -134,7 +152,7 @@ static int node_explode(node_t *node, int depth)
static node_t *node_reduce(node_t *node) static node_t *node_reduce(node_t *node)
{ {
while (1) { while (1) {
if (!node_explode(node, 0) && !node_split(node)) if (! (node_explode(node, 0) || node_split(node)))
return node; return node;
} }
} }
@@ -145,17 +163,16 @@ static node_t *node_add(node_t *n1, node_t *n2)
{ {
node_t *head = pool_get(pool_nodes); node_t *head = pool_get(pool_nodes);
/* create new tree from the two nodes
*/
INIT_LIST_HEAD(&head->leaf_list); INIT_LIST_HEAD(&head->leaf_list);
head->left = n1;
head->right = n2;
/* create new tree from the two /* link leaves lists
*/ */
head->tree[LEFT] = n1; list_splice(&n2->leaf_list, &head->leaf_list);
head->tree[RIGHT] = n2; list_splice(&n1->leaf_list, &head->leaf_list);
/* link corresponding leaves
*/
list_splice_tail(&n1->leaf_list, &head->leaf_list);
list_splice_tail(&n2->leaf_list, &head->leaf_list);
return head; return head;
} }
@@ -174,9 +191,9 @@ static inline node_t *_node_read(char **p, int depth)
switch (**p) { switch (**p) {
case '[': case '[':
(*p)++; /* skip left bracket */ (*p)++; /* skip left bracket */
node->tree[LEFT] = _node_read(p, depth + 1); node->left = _node_read(p, depth + 1);
(*p)++; /* skip comma */ (*p)++; /* skip comma */
node->tree[RIGHT] = _node_read(p, depth + 1); node->right = _node_read(p, depth + 1);
break; break;
default: /* number: add to tail list */ default: /* number: add to tail list */
node->val = **p - '0'; node->val = **p - '0';
@@ -218,10 +235,9 @@ static void free_lines()
static inline int node_magnitude(node_t *node) static inline int node_magnitude(node_t *node)
{ {
if (!node->tree[LEFT]) if (!node->left)
return node->val; return node->val;
return 3 * node_magnitude(node->tree[LEFT]) + return 3 * node_magnitude(node->left) + 2 * node_magnitude(node->right);
2 * node_magnitude(node->tree[RIGHT]);
} }
static int part1() static int part1()