Files
adventofcode2024/day19/c/day19.c
dobiadi 7b0996cd95 Day19
2024-12-20 18:27:31 +01:00

263 lines
7.3 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <omp.h>
#define CHARS_MAX 4*1024
#define MAX_PATTERNS 1024
#define MAX_PATTERN_ELEMENTS 1024
#define MAX_DESIGNS 1024
#define MAX_DESIGN_ELEMENTS 1024
#define COLOR_COUNT 5
#define cti(a) ((a) == 'w' ? 0 : (((a) == 'u' ? 1 : ((a) == 'b' ? 2 : ((a) == 'r' ? 3 : 4)))))
typedef struct sequence {
char *colors;
int count;
} sequence_t;
typedef struct node {
struct node *children[COLOR_COUNT];
uint64_t variants;
char key;
uint8_t is_leaf;
} node_t;
node_t* create_node() {
node_t *node = calloc(1, sizeof(node[0]));
return node;
}
node_t* search(node_t* root, char* word, int len) {
node_t* node = root;
for (int i = 0; i < len; i++) {
if (node->children[cti(word[i])] == NULL) {
return NULL;
}
node = node->children[cti(word[i])];
}
return node;
}
void insert(node_t* root, char* word, int len, uint64_t variants) {
node_t* node = root;
for (int i = 0; i < len; i++) {
if (node->children[cti(word[i])] == NULL) {
node->children[cti(word[i])] = create_node();
}
node = node->children[cti(word[i])];
}
node->variants = variants;
node->is_leaf = 1;
}
void free_node(node_t* node) {
for (int i = 0; i < COLOR_COUNT; i++) {
if (node->children[i] != NULL) {
free_node(node->children[i]);
}
}
free(node);
}
int possible(sequence_t design, node_t *pattern_trie);
uint64_t possible_variants(sequence_t design, node_t* pattern_trie, node_t* variant_trie);
int main() {
char *p, *buf, c;
buf = calloc(CHARS_MAX, sizeof(char));
p = buf;
sequence_t *designs = calloc(MAX_DESIGNS, sizeof(designs[0]));
for (int i = 0; i < MAX_DESIGNS; i++) {
designs[i].colors = calloc(MAX_DESIGN_ELEMENTS, sizeof(designs[0].colors[0]));
}
int design_count = 0;
sequence_t *patterns = calloc(MAX_PATTERNS, sizeof(patterns[0]));
for (int i = 0; i < MAX_PATTERNS; i++) {
patterns[i].colors = calloc(MAX_PATTERN_ELEMENTS, sizeof(patterns[0].colors[0]));
}
int pattern_count = 0;
int reading_available_patterns = 1;
while ((c = getchar()) != EOF) {
if (reading_available_patterns) {
*p++ = c;
if (c != '\n') {
continue;
}
if (buf[0] == '\n') {
reading_available_patterns = 0;
continue;
}
char *q = p;
p = buf;
do {
while (*p != '\n' && *p != ',') {
patterns[pattern_count].colors[patterns[pattern_count].count++] = *p;
p++;
}
pattern_count++;
p += 2;
} while (p < q);
memset(buf, 0, CHARS_MAX);
p = buf;
} else {
if (c == '\n') {
design_count++;
continue;
}
designs[design_count].colors[designs[design_count].count++] = c;
}
}
uint32_t shortest_pattern = UINT32_MAX, longest_pattern = 0;
for (int i = 0; i < pattern_count; i++) {
if (patterns[i].count < shortest_pattern) {
shortest_pattern = patterns[i].count;
}
if (patterns[i].count > longest_pattern) {
longest_pattern = patterns[i].count;
}
}
node_t *pattern_trie = calloc(1, sizeof(pattern_trie[0]));
for (int i = 0; i < pattern_count; i++) {
sequence_t current_sequence = { 0 };
current_sequence.colors = calloc(MAX_DESIGN_ELEMENTS, sizeof(current_sequence.colors[0]));
insert(pattern_trie, patterns[i].colors, patterns[i].count, 0);
free(current_sequence.colors);
}
int part1 = 0;
uint64_t part2 = 0;
// Try to build each design out of the available patterns
#pragma omp parallel for
for (int i = 0; i < design_count; i++) {
sequence_t current_sequence = { 0 };
current_sequence.colors = calloc(MAX_DESIGN_ELEMENTS, sizeof(current_sequence.colors[0]));
if (possible(designs[i], pattern_trie))
#pragma omp critical
{
part1++;
}
free(current_sequence.colors);
}
node_t *variant_trie = calloc(1, sizeof(variant_trie[0]));
for (int i = 0; i < design_count; i++) {
sequence_t current_sequence = { 0 };
current_sequence.colors = calloc(MAX_DESIGN_ELEMENTS, sizeof(current_sequence.colors[0]));
part2 += possible_variants(designs[i], pattern_trie, variant_trie);
free(current_sequence.colors);
}
free(buf);
for (int i = 0; i < MAX_DESIGNS; i++) {
free(designs[i].colors);
}
free(designs);
for (int i = 0; i < MAX_PATTERNS; i++) {
free(patterns[i].colors);
}
free(patterns);
free_node(pattern_trie);
free_node(variant_trie);
printf("%i\n", part1);
printf("%lu\n", part2);
}
int possible(sequence_t design, node_t *pattern_trie) {
node_t *node = search(pattern_trie, design.colors, design.count);
if (node != NULL) {
return 1;
}
for (int i = 1; i <= design.count; i++) {
char *pattern = calloc(i, sizeof(pattern[0]));
memcpy(pattern, design.colors, i*sizeof(pattern[0]));
node_t *node = search(pattern_trie, pattern, i);
free(pattern);
if (node == NULL || node->is_leaf == 0) {
continue;
}
sequence_t subdesign = { 0 };
subdesign.count = design.count - i;
subdesign.colors = calloc(subdesign.count, sizeof(subdesign.colors[0]));
memcpy(subdesign.colors, design.colors + i, subdesign.count*sizeof(subdesign.colors[0]));
int good = possible(subdesign, pattern_trie);
free(subdesign.colors);
if (good) {
return 1;
}
}
return 0;
}
uint64_t possible_variants(sequence_t design, node_t* pattern_trie, node_t* variant_trie) {
if (design.count == 0) {
return 1;
}
char *pattern = calloc(design.count+1, sizeof(pattern[0]));
memcpy(pattern, design.colors, (design.count+1)*sizeof(pattern[0]));
pattern[design.count] = '\0';
node_t *node = search(variant_trie, design.colors, design.count);
// We already know the answer
if (node != NULL && node->is_leaf) {
char *pattern = calloc(design.count+1, sizeof(pattern[0]));
memcpy(pattern, design.colors, (design.count+1)*sizeof(pattern[0]));
pattern[design.count] = '\0';
return node->variants;
}
uint64_t count = 0;
// Try all possible patterns
for (int i = 1; i <= design.count; i++) {
char *pattern = calloc(i+1, sizeof(pattern[0]));
memcpy(pattern, design.colors, (i+1)*sizeof(pattern[0]));
node_t *node = search(pattern_trie, pattern, i);
pattern[i] = '\0';
if (node == NULL || node->is_leaf == 0) {
continue;
}
free(pattern);
sequence_t subdesign = { 0 };
subdesign.count = design.count - i;
subdesign.colors = calloc(subdesign.count, sizeof(subdesign.colors[0]));
memcpy(subdesign.colors, design.colors + i, subdesign.count*sizeof(subdesign.colors[0]));
count += possible_variants(subdesign, pattern_trie, variant_trie);
free(subdesign.colors);
}
insert(variant_trie, design.colors, design.count, count);
return count;
}