Files
adventofcode2024/day22/c/day22.c

190 lines
4.7 KiB
C
Raw Normal View History

2024-12-23 11:25:55 +01:00
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <omp.h>
#define CHARS_MAX 64
#define MAX_BUYERS 8*1024
#define GENERATION 2000
typedef struct node {
struct node *children[19];
uint64_t value;
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, int8_t* word, int len) {
node_t* node = root;
for (int i = 0; i < len; i++) {
if (node->children[word[i] + 9] == NULL) {
return NULL;
}
node = node->children[word[i] + 9];
}
return node;
}
void insert(node_t* root, int8_t* word, int len, uint64_t value) {
node_t* node = root;
for (int i = 0; i < len; i++) {
if (node->children[word[i] + 9] == NULL) {
node->children[word[i] + 9] = create_node();
}
node = node->children[word[i] + 9];
}
node->value = value;
node->is_leaf = 1;
}
void free_node(node_t* node) {
for (int i = 0; i < 19; i++) {
if (node->children[i] != NULL) {
free_node(node->children[i]);
}
}
free(node);
}
uint64_t generate_new_secret(uint64_t);
uint64_t mix(uint64_t, uint64_t);
uint64_t prune(uint64_t);
int main() {
char *p, *buf, c;
buf = calloc(CHARS_MAX, sizeof(char));
p = buf;
uint64_t *secrets = calloc(MAX_BUYERS, sizeof(secrets[0]));
int secret_count = 0;
while ((c = getchar()) != EOF) {
*p++ = c;
if (c != '\n') {
continue;
}
sscanf(buf, "%lu", &secrets[secret_count++]);
memset(buf, 0, CHARS_MAX);
p = buf;
}
free(buf);
uint64_t sum = 0;
uint64_t **prices = calloc(secret_count, sizeof(prices[0]));
for (int i = 0; i < secret_count; i++) {
prices[i] = calloc(GENERATION + 1, sizeof(prices[0][0]));
prices[i][0] = secrets[i] % 10;
for (int j = 0; j < GENERATION; j++) {
secrets[i] = generate_new_secret(secrets[i]);
prices[i][j+1] = secrets[i] % 10;
}
sum += secrets[i];
}
printf("%lu\n", sum);
free(secrets);
// Calculate diffs
int8_t **diffs = calloc(secret_count, sizeof(diffs[0]));
for (int i = 0; i < secret_count; i++) {
diffs[i] = calloc(GENERATION, sizeof(diffs[0][0]));
for (int j = 0; j < GENERATION; j++) {
diffs[i][j] = (int8_t)prices[i][j+1] - (int8_t)prices[i][j];
}
}
int8_t (**sequences)[4] = calloc(secret_count, sizeof(int8_t(*)[4]));
for (int i = 0; i < secret_count; i++) {
sequences[i] = calloc(GENERATION - 4, sizeof(int8_t[4]));
for (int j = 0; j < GENERATION-4; j++) {
sequences[i][j][0] = diffs[i][j];
sequences[i][j][1] = diffs[i][j+1];
sequences[i][j][2] = diffs[i][j+2];
sequences[i][j][3] = diffs[i][j+3];
}
free(diffs[i]);
}
free(diffs);
node_t *root = calloc(1, sizeof(node_t));
uint64_t max_bananas = 0;
for (int i = 0; i < secret_count; i++) {
for (int j = 0; j < GENERATION - 4; j++) {
int8_t pattern[4];
memcpy(pattern, sequences[i][j], sizeof(sequences[0][0]));
node_t *node = search(root, pattern, 4);
if (node != NULL && node->is_leaf) {
continue;
}
// Count bananas
uint64_t bananas = 0;
#pragma omp parallel for
for (int k = 0; k < secret_count; k++) {
for (int l = 0; l < GENERATION - 4; l++) {
if (memcmp(pattern, sequences[k][l], sizeof(sequences[0][0]))) {
continue;
}
#pragma omp critical
{
bananas += prices[k][l+4];
}
break;
}
}
insert(root, pattern, 4, bananas);
if (bananas > max_bananas) {
max_bananas = bananas;
}
}
}
printf("%lu\n", max_bananas);
for (int i = 0; i < secret_count; i++) {
free(prices[i]);
free(sequences[i]);
}
free_node(root);
free(prices);
free(sequences);
}
uint64_t generate_new_secret(uint64_t secret) {
uint64_t new_secret = secret;
// 1
new_secret = prune(mix(new_secret, new_secret * 64));
// 2
new_secret = prune(mix(new_secret, new_secret / 32));
// 3
new_secret = prune(mix(new_secret, new_secret * 2048));
return new_secret;
}
uint64_t mix(uint64_t secret, uint64_t value) {
return secret ^ value;
}
uint64_t prune(uint64_t secret) {
return secret % 16777216;
}