246 lines
6.0 KiB
C
246 lines
6.0 KiB
C
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#define BUFFER_SIZE 256
|
|
#define MAX_MEMBERS 64
|
|
#define MAX_PACKETS 512
|
|
|
|
enum NodeType {
|
|
NUMBER,
|
|
LIST
|
|
};
|
|
|
|
enum orderType {
|
|
INORDER,
|
|
OUTOFORDER,
|
|
INDECISIVE
|
|
};
|
|
|
|
typedef struct node {
|
|
enum NodeType type;
|
|
struct node *members[MAX_MEMBERS];
|
|
int member_count;
|
|
long value;
|
|
int marker;
|
|
} NODE;
|
|
|
|
void destructNode(NODE*);
|
|
long yeetList(NODE*, char*);
|
|
enum orderType inOrder(NODE*, NODE*);
|
|
void quicksort(NODE *[], int, int);
|
|
void swap(NODE *[], int, int);
|
|
|
|
int main() {
|
|
char buf[BUFFER_SIZE], *p, c;
|
|
memset(buf, 0, BUFFER_SIZE);
|
|
p = buf;
|
|
|
|
int isLeft = 1, iter = 0, sum = 0;
|
|
NODE *left, *right, *curr;
|
|
NODE *packets[MAX_PACKETS];
|
|
int packet_count = 0;
|
|
|
|
while ((c = getchar()) != EOF) {
|
|
*p++ = c;
|
|
if (c == '\n') {
|
|
if (buf[0] == '\n') {
|
|
// Empty lines don't matter
|
|
memset(buf, 0, BUFFER_SIZE);
|
|
p = buf;
|
|
continue;
|
|
}
|
|
|
|
// The root Node is always a list
|
|
if (isLeft) {
|
|
left = (NODE*)malloc(sizeof(NODE));
|
|
memset(left, 0, sizeof(NODE));
|
|
left->type = LIST;
|
|
left->marker = 0;
|
|
curr = left;
|
|
isLeft = 0;
|
|
} else {
|
|
right = (NODE*)malloc(sizeof(NODE));
|
|
memset(right, 0, sizeof(NODE));
|
|
right->type = LIST;
|
|
right->marker = 0;
|
|
curr = right;
|
|
isLeft = 1;
|
|
}
|
|
|
|
|
|
// Parse node
|
|
yeetList(curr, buf+1);
|
|
packets[packet_count] = curr;
|
|
packet_count++;
|
|
|
|
if (isLeft == 1) {
|
|
iter++;
|
|
// Compare
|
|
|
|
if (inOrder(left, right) == INORDER) {
|
|
sum += iter;
|
|
}
|
|
}
|
|
|
|
memset(buf, 0, BUFFER_SIZE);
|
|
p = buf;
|
|
}
|
|
}
|
|
printf("%i\n", sum);
|
|
|
|
// Add the two extra packets
|
|
curr = (NODE*)malloc(sizeof(NODE));
|
|
memset(curr, 0, sizeof(NODE));
|
|
curr->type = LIST;
|
|
curr->marker = 1;
|
|
yeetList(curr, "[2]]");
|
|
packets[packet_count] = curr;
|
|
packet_count++;
|
|
curr = (NODE*)malloc(sizeof(NODE));
|
|
memset(curr, 0, sizeof(NODE));
|
|
curr->type = LIST;
|
|
curr->marker = 1;
|
|
yeetList(curr, "[6]]");
|
|
packets[packet_count] = curr;
|
|
packet_count++;
|
|
|
|
// Quicksort packets
|
|
quicksort(packets, 0, packet_count - 1);
|
|
int product = 1;
|
|
|
|
for (int i = 0; i < packet_count; i++) {
|
|
if (packets[i]->marker) {
|
|
product *= i + 1;
|
|
}
|
|
// Cleanup
|
|
destructNode(packets[i]);
|
|
free(packets[i]);
|
|
}
|
|
|
|
printf("%i\n", product);
|
|
}
|
|
|
|
void destructNode(NODE* node) {
|
|
if (node->type == LIST) {
|
|
for (int i = 0; i < node->member_count; i++) {
|
|
destructNode(node->members[i]);
|
|
free(node->members[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
long yeetList(NODE* parent, char* p) {
|
|
long tmp;
|
|
char *q = p;
|
|
while(*q != ']') {
|
|
// New list
|
|
if (*q == '[') {
|
|
NODE *newNode = (NODE*)malloc(sizeof(NODE));
|
|
memset(newNode, 0, sizeof(NODE));
|
|
newNode->type = LIST;
|
|
parent->members[parent->member_count] = newNode;
|
|
parent->member_count++;
|
|
tmp = yeetList(newNode, q+1);
|
|
// Jump to the end
|
|
q += tmp + 2;
|
|
// Move one up if it is ','
|
|
if (*q == ',') {
|
|
q++;
|
|
}
|
|
} else {
|
|
// Read next int
|
|
sscanf(q, "%li", &tmp);
|
|
NODE *newNode = (NODE*)malloc(sizeof(NODE));
|
|
memset(newNode, 0, sizeof(NODE));
|
|
newNode->type = NUMBER;
|
|
newNode->value = tmp;
|
|
parent->members[parent->member_count] = newNode;
|
|
parent->member_count++;
|
|
|
|
// Move pointer to the next ',' or ']'
|
|
while (*q != ',' && *q != ']') { q++; }
|
|
// Move one up if it is ','
|
|
if (*q == ',') {
|
|
q++;
|
|
}
|
|
}
|
|
}
|
|
return q-p;
|
|
}
|
|
|
|
enum orderType inOrder(NODE* left, NODE* right) {
|
|
// If both are numbers
|
|
if (left->type == NUMBER && right->type == NUMBER) {
|
|
if (left->value < right->value) {
|
|
return INORDER;
|
|
} else if (left->value == right->value) {
|
|
return INDECISIVE;
|
|
} else {
|
|
return OUTOFORDER;
|
|
}
|
|
}
|
|
|
|
// If both are lists
|
|
if (left->type == LIST && right->type == LIST) {
|
|
for (int i = 0; i < left->member_count; i++) {
|
|
// Right ran out first
|
|
if (i == right->member_count) {
|
|
return OUTOFORDER;
|
|
}
|
|
enum orderType result = inOrder(left->members[i], right->members[i]);
|
|
if (result == INORDER || result == OUTOFORDER) return result;
|
|
}
|
|
// Left ran out first
|
|
if (right->member_count > left->member_count) return INORDER;
|
|
|
|
return INDECISIVE;
|
|
}
|
|
|
|
NODE tmp;
|
|
// If left is a number, right is a list
|
|
if (left->type == NUMBER && right->type == LIST) {
|
|
tmp.type = LIST;
|
|
tmp.members[0] = left;
|
|
tmp.member_count = 1;
|
|
|
|
return inOrder(&tmp, right);
|
|
}
|
|
|
|
// Left is a list, right is a number
|
|
tmp.type = LIST;
|
|
tmp.members[0] = right;
|
|
tmp.member_count = 1;
|
|
|
|
return inOrder(left, &tmp);
|
|
}
|
|
|
|
void quicksort(NODE *packets[], int left, int right) {
|
|
int last;
|
|
|
|
if (left >= right) {
|
|
return;
|
|
}
|
|
|
|
swap(packets, left, (left+right)/2);
|
|
last = left;
|
|
|
|
for (int i = left+1; i <= right; i++) {
|
|
if (inOrder(packets[left], packets[i]) == OUTOFORDER) {
|
|
swap(packets, ++last, i);
|
|
}
|
|
}
|
|
|
|
swap(packets, left, last);
|
|
quicksort(packets, left, last - 1);
|
|
quicksort(packets, last + 1, right);
|
|
}
|
|
|
|
void swap(NODE *packets[], int i, int j) {
|
|
NODE *tmp;
|
|
|
|
tmp = packets[i];
|
|
packets[i] = packets[j];
|
|
packets[j] = tmp;
|
|
}
|