Files
adventofcode2023/day19/c/day19.c
2023-12-23 00:18:03 +01:00

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