304 lines
11 KiB
C
304 lines
11 KiB
C
#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';
|
|
}
|