Day19 C
This commit is contained in:
BIN
day19/c/day19
Executable file
BIN
day19/c/day19
Executable file
Binary file not shown.
303
day19/c/day19.c
Normal file
303
day19/c/day19.c
Normal file
@@ -0,0 +1,303 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define LINE_MAX_LENGTH 256
|
||||
#define MAX_INSTRUCTIONS 16
|
||||
#define MAX_WORKFLOWS 1024
|
||||
#define MAX_PARTS 2048
|
||||
#define NUM_0_CHARCODE 48
|
||||
#define NUM_9_CHARCODE NUM_0_CHARCODE + 9
|
||||
#define MAX_BREAKPOINTS 1024
|
||||
|
||||
typedef struct instruction {
|
||||
char category;
|
||||
char operator;
|
||||
int value;
|
||||
char destination[16];
|
||||
int destination_length;
|
||||
} instruction_t;
|
||||
|
||||
typedef struct workflow {
|
||||
char name[16];
|
||||
int name_length;
|
||||
instruction_t instructions[MAX_INSTRUCTIONS];
|
||||
int instructions_num;
|
||||
char default_action[16];
|
||||
int default_action_length;
|
||||
} workflow_t;
|
||||
|
||||
typedef struct part {
|
||||
int x;
|
||||
int m;
|
||||
int a;
|
||||
int s;
|
||||
} part_t;
|
||||
|
||||
typedef struct breakpoints {
|
||||
int x[MAX_BREAKPOINTS];
|
||||
int x_num;
|
||||
int m[MAX_BREAKPOINTS];
|
||||
int m_num;
|
||||
int a[MAX_BREAKPOINTS];
|
||||
int a_num;
|
||||
int s[MAX_BREAKPOINTS];
|
||||
int s_num;
|
||||
} breakpoints_t;
|
||||
|
||||
int cmp(const void *a, const void *b);
|
||||
char get_workflow_result(workflow_t workflows[], int workflows_num, part_t part, workflow_t in);
|
||||
|
||||
int main() {
|
||||
char *p, *q, *buf, c;
|
||||
|
||||
buf = (char *)malloc(LINE_MAX_LENGTH);
|
||||
memset(buf, 0, LINE_MAX_LENGTH);
|
||||
p = buf;
|
||||
|
||||
int first = 1;
|
||||
workflow_t *workflows = (workflow_t*)malloc(MAX_WORKFLOWS * sizeof(workflow_t));
|
||||
memset(workflows, 0, MAX_WORKFLOWS * sizeof(workflow_t));
|
||||
int workflows_num = 0;
|
||||
|
||||
part_t *parts = (part_t*)malloc(MAX_PARTS * sizeof(part_t));
|
||||
memset(parts, 0, MAX_PARTS * sizeof(part_t));
|
||||
int parts_num = 0;
|
||||
|
||||
while ((c = getchar()) != EOF) {
|
||||
*p++ = c;
|
||||
if (c == '\n') {
|
||||
if (buf[0] == '\n') {
|
||||
first = 0;
|
||||
} else {
|
||||
p = buf;
|
||||
if (first) {
|
||||
while (*p != '{') p++;
|
||||
strncpy(workflows[workflows_num].name, buf, p - buf);
|
||||
workflows[workflows_num].name_length = p - buf;
|
||||
p++;
|
||||
while(*p != '\n') {
|
||||
q = p;
|
||||
while(*p != '<' && *p != '>' && *p != '}') p++;
|
||||
// Default action
|
||||
if (*p == '}') {
|
||||
strncpy(workflows[workflows_num].default_action, q, p - q);
|
||||
workflows[workflows_num].default_action_length = p - q;
|
||||
} else {
|
||||
workflows[workflows_num].instructions[workflows[workflows_num].instructions_num].category = *q;
|
||||
workflows[workflows_num].instructions[workflows[workflows_num].instructions_num].operator = *p;
|
||||
p++;
|
||||
sscanf(p, "%i", &workflows[workflows_num].instructions[workflows[workflows_num].instructions_num].value);
|
||||
while (*p != ':') p++;
|
||||
p++;
|
||||
q = p;
|
||||
while (*p != ',') p++;
|
||||
strncpy(workflows[workflows_num].instructions[workflows[workflows_num].instructions_num].destination, q, p - q);
|
||||
workflows[workflows_num].instructions[workflows[workflows_num].instructions_num].destination_length = p - q;
|
||||
workflows[workflows_num].instructions_num++;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
workflows_num++;
|
||||
} else {
|
||||
while (*p < NUM_0_CHARCODE || *p > NUM_9_CHARCODE) p++;
|
||||
sscanf(p, "%i", &parts[parts_num].x);
|
||||
while (*p != ',') p++;
|
||||
while (*p < NUM_0_CHARCODE || *p > NUM_9_CHARCODE) p++;
|
||||
sscanf(p, "%i", &parts[parts_num].m);
|
||||
while (*p != ',') p++;
|
||||
while (*p < NUM_0_CHARCODE || *p > NUM_9_CHARCODE) p++;
|
||||
sscanf(p, "%i", &parts[parts_num].a);
|
||||
while (*p != ',') p++;
|
||||
while (*p < NUM_0_CHARCODE || *p > NUM_9_CHARCODE) p++;
|
||||
sscanf(p, "%i", &parts[parts_num].s);
|
||||
parts_num++;
|
||||
}
|
||||
}
|
||||
memset(buf, 0, LINE_MAX_LENGTH);
|
||||
p = buf;
|
||||
}
|
||||
}
|
||||
|
||||
// Find start
|
||||
workflow_t *start;
|
||||
for (int i = 0; i < workflows_num; i++) {
|
||||
if (!strcmp(workflows[i].name, "in")) {
|
||||
start = &workflows[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int part1 = 0;
|
||||
for (int i = 0; i < parts_num; i++) {
|
||||
char result = get_workflow_result(workflows, workflows_num, parts[i], *start);
|
||||
if (result == 'A') {
|
||||
part1 += parts[i].x + parts[i].m + parts[i].a + parts[i].s;
|
||||
}
|
||||
}
|
||||
|
||||
printf("%i\n", part1);
|
||||
|
||||
breakpoints_t breakpoints;
|
||||
memset(&breakpoints, 0, sizeof(breakpoints_t));
|
||||
|
||||
for (int i = 0; i < workflows_num; i++) {
|
||||
for (int j = 0; j < workflows[i].instructions_num; j++) {
|
||||
if (workflows[i].instructions[j].category == 'x') {
|
||||
int value = workflows[i].instructions[j].operator == '<' ? workflows[i].instructions[j].value : workflows[i].instructions[j].value + 1;
|
||||
int found = 0;
|
||||
for (int k = 0; k < breakpoints.x_num; k++) {
|
||||
if (breakpoints.x[k] == value) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
breakpoints.x[breakpoints.x_num] = value;
|
||||
breakpoints.x_num++;
|
||||
}
|
||||
}
|
||||
if (workflows[i].instructions[j].category == 'm') {
|
||||
int value = workflows[i].instructions[j].operator == '<' ? workflows[i].instructions[j].value : workflows[i].instructions[j].value + 1;
|
||||
int found = 0;
|
||||
for (int k = 0; k < breakpoints.m_num; k++) {
|
||||
if (breakpoints.m[k] == value) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
breakpoints.m[breakpoints.m_num] = value;
|
||||
breakpoints.m_num++;
|
||||
}
|
||||
}
|
||||
if (workflows[i].instructions[j].category == 'a') {
|
||||
int value = workflows[i].instructions[j].operator == '<' ? workflows[i].instructions[j].value : workflows[i].instructions[j].value + 1;
|
||||
int found = 0;
|
||||
for (int k = 0; k < breakpoints.a_num; k++) {
|
||||
if (breakpoints.a[k] == value) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
breakpoints.a[breakpoints.a_num] = value;
|
||||
breakpoints.a_num++;
|
||||
}
|
||||
}
|
||||
if (workflows[i].instructions[j].category == 's') {
|
||||
int value = workflows[i].instructions[j].operator == '<' ? workflows[i].instructions[j].value : workflows[i].instructions[j].value + 1;
|
||||
int found = 0;
|
||||
for (int k = 0; k < breakpoints.s_num; k++) {
|
||||
if (breakpoints.s[k] == value) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
breakpoints.s[breakpoints.s_num] = value;
|
||||
breakpoints.s_num++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
qsort(breakpoints.x, breakpoints.x_num, sizeof(breakpoints.x[0]), &cmp);
|
||||
qsort(breakpoints.m, breakpoints.m_num, sizeof(breakpoints.m[0]), &cmp);
|
||||
qsort(breakpoints.a, breakpoints.a_num, sizeof(breakpoints.a[0]), &cmp);
|
||||
qsort(breakpoints.s, breakpoints.s_num, sizeof(breakpoints.s[0]), &cmp);
|
||||
|
||||
double part2 = 0;
|
||||
#pragma omp parallel for schedule(dynamic)
|
||||
for (int i = 0; i < breakpoints.x_num + 1; i++) {
|
||||
for (int j = 0; j < breakpoints.m_num + 1; j++) {
|
||||
for (int k = 0; k < breakpoints.a_num + 1; k++) {
|
||||
for (int l = 0; l < breakpoints.s_num + 1; l++) {
|
||||
unsigned long x0 = i == 0 ? 1 : breakpoints.x[i - 1];
|
||||
unsigned long x1 = i == breakpoints.x_num ? 4001 : breakpoints.x[i];
|
||||
unsigned long m0 = j == 0 ? 1 : breakpoints.m[j - 1];
|
||||
unsigned long m1 = j == breakpoints.m_num ? 4001 : breakpoints.m[j];
|
||||
unsigned long a0 = k == 0 ? 1 : breakpoints.a[k - 1];
|
||||
unsigned long a1 = k == breakpoints.a_num ? 4001 : breakpoints.a[k];
|
||||
unsigned long s0 = l == 0 ? 1 : breakpoints.s[l - 1];
|
||||
unsigned long s1 = l == breakpoints.s_num ? 4001 : breakpoints.s[l];
|
||||
part_t metapart = {
|
||||
.x = x0,
|
||||
.m = m0,
|
||||
.a = a0,
|
||||
.s = s0,
|
||||
};
|
||||
char result = get_workflow_result(workflows, workflows_num, metapart, *start);
|
||||
#pragma omp critical
|
||||
if (result == 'A') {
|
||||
part2 += (double)(x1 - x0) * (double)(m1 - m0) * (double)(a1 - a0) * (double)(s1 - s0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
printf("%f\n", part2);
|
||||
|
||||
free(buf);
|
||||
free(workflows);
|
||||
}
|
||||
|
||||
int cmp(const void *a, const void *b) {
|
||||
return *(int*)a - *(int*)b;
|
||||
}
|
||||
|
||||
char get_workflow_result(workflow_t workflows[], int workflows_num, part_t part, workflow_t in) {
|
||||
for (int i = 0; i < in.instructions_num; i++) {
|
||||
int value;
|
||||
switch (in.instructions[i].category) {
|
||||
case 'x':
|
||||
value = part.x;
|
||||
break;
|
||||
case 'm':
|
||||
value = part.m;
|
||||
break;
|
||||
case 'a':
|
||||
value = part.a;
|
||||
break;
|
||||
case 's':
|
||||
value = part.s;
|
||||
break;
|
||||
}
|
||||
int matches;
|
||||
switch (in.instructions[i].operator) {
|
||||
case '<':
|
||||
matches = value < in.instructions[i].value;
|
||||
break;
|
||||
case '>':
|
||||
matches = value > in.instructions[i].value;
|
||||
break;
|
||||
}
|
||||
if (matches) {
|
||||
if (!strcmp(in.instructions[i].destination, "A")) {
|
||||
return 'A';
|
||||
}
|
||||
if (!strcmp(in.instructions[i].destination, "R")) {
|
||||
return 'R';
|
||||
}
|
||||
for (int j = 0; j < workflows_num; j++) {
|
||||
if (!strcmp(workflows[j].name, in.instructions[i].destination)) {
|
||||
return get_workflow_result(workflows, workflows_num, part, workflows[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!strcmp(in.default_action, "A")) {
|
||||
return 'A';
|
||||
}
|
||||
if (!strcmp(in.default_action, "R")) {
|
||||
return 'R';
|
||||
}
|
||||
for (int i = 0; i < workflows_num; i++) {
|
||||
if (!strcmp(workflows[i].name, in.default_action)) {
|
||||
return get_workflow_result(workflows, workflows_num, part, workflows[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return 'F';
|
||||
}
|
||||
Reference in New Issue
Block a user