#include #include #include #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'; }