Day19
This commit is contained in:
262
day19/c/day19.c
Normal file
262
day19/c/day19.c
Normal file
@@ -0,0 +1,262 @@
|
||||
#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;
|
||||
}
|
||||
Reference in New Issue
Block a user