Files
dobiadi 55ae7103b8 Day8 C
2023-12-09 18:29:01 +01:00

229 lines
6.1 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#define LINE_MAX_LENGTH 512
#define MAX_INSTRUCTIONS 512
#define MAX_NODES 2048
#define MAX_HISTORY 32*1024
enum direction {
LEFT,
RIGHT
};
typedef struct node {
char name[3];
char left_name[3];
char right_name[3];
struct node *left;
struct node *right;
} node_t;
typedef struct h {
node_t *node;
unsigned long idx;
} history_t;
typedef struct period {
unsigned long offset;
unsigned long period;
unsigned long z[10];
int z_num;
} period_t;
void connect_nodes(node_t nodes[], int nodes_num);
int all_ending_with(char endchar, node_t *nodes[], int nodes_num);
int main() {
char *p, *buf, c;
int first = 1, instructions_num = 0;
enum direction instructions[MAX_INSTRUCTIONS];
int nodes_num = 0;
node_t nodes[MAX_NODES];
buf = (char *)malloc(LINE_MAX_LENGTH);
memset(buf, 0, LINE_MAX_LENGTH);
p = buf;
while ((c = getchar()) != EOF) {
*p++ = c;
if (c == '\n') {
if (first && buf[0] == '\n') {
first = 0;
} else if (first) {
p = buf;
while (*p != '\n') {
instructions[instructions_num] = *p == 'L' ? LEFT : RIGHT;
instructions_num++;
p++;
}
} else {
sscanf(buf, "%c%c%c = (%c%c%c, %c%c%c)", &nodes[nodes_num].name[0], &nodes[nodes_num].name[1], &nodes[nodes_num].name[2], &nodes[nodes_num].left_name[0], &nodes[nodes_num].left_name[1], &nodes[nodes_num].left_name[2], &nodes[nodes_num].right_name[0], &nodes[nodes_num].right_name[1], &nodes[nodes_num].right_name[2]);
nodes_num++;
}
memset(buf, 0, LINE_MAX_LENGTH);
p = buf;
}
}
connect_nodes(nodes, nodes_num);
unsigned long step_counter = 0;
node_t *curr;
#ifndef ONLY_PART2
// Find start node
for (int i = 0; i < nodes_num; i++) {
if (nodes[i].name[0] == 'A' && nodes[i].name[1] == 'A' && nodes[i].name[2] == 'A') {
curr = &nodes[i];
break;
}
}
while (curr->name[0] != 'Z' || curr->name[1] != 'Z' || curr->name[2] != 'Z') {
switch (instructions[step_counter % instructions_num]) {
case LEFT:
curr = curr->left;
break;
case RIGHT:
curr = curr->right;
break;
}
step_counter++;
}
printf("%lu\n", step_counter);
#endif
// Part2
node_t *current_nodes[MAX_NODES];
int current_nodes_num = 0;
// Search all nodes ending with 'A'
for (int i = 0; i < nodes_num; i++) {
if (nodes[i].name[2] == 'A') {
current_nodes[current_nodes_num] = &nodes[i];
current_nodes_num++;
}
}
period_t periods[MAX_NODES];
for (int i = 0; i < current_nodes_num; i++) {
history_t history[MAX_HISTORY];
int history_num = 0;
step_counter = 0;
int found = 0;
curr = current_nodes[i];
while (!found) {
history[history_num].node = curr;
history[history_num].idx = step_counter % instructions_num;
history_num++;
switch (instructions[step_counter % instructions_num]) {
case LEFT:
curr = curr->left;
break;
case RIGHT:
curr = curr->right;
break;
}
step_counter++;
for (int j = 0; j < history_num; j++) {
if (history[j].node == curr && step_counter % instructions_num == history[j].idx) {
found = 1;
periods[i].offset = j;
periods[i].period = history_num - j;
periods[i].z_num = 0;
for (int k = periods[i].offset; k < history_num; k++) {
if (history[k].node->name[2] == 'Z') {
periods[i].z[periods[i].z_num] = k - periods[i].offset;
periods[i].z_num++;
}
}
break;
}
}
}
}
unsigned long ref;
int found = 0;
step_counter = periods[0].offset;
while (!found) {
for (int i = 0; i < periods[0].z_num; i++) {
found = 1;
ref = step_counter + periods[0].z[i];
for (int j = 0; j < current_nodes_num; j++) {
int found2 = 0;
for (int k = 0; k < periods[j].z_num; k++) {
if ((ref - periods[j].offset) % periods[j].period == periods[j].z[k]) {
found2 = 1;
}
}
if (!found2) {
found = 0;
break;
}
}
}
step_counter += periods[0].period;
}
printf("%lu\n", ref);
free(buf);
}
void connect_nodes(node_t nodes[], int nodes_num) {
for (int i = 0; i < nodes_num; i++) {
// Left
for (int j = 0; j < nodes_num; j++) {
int found = 1;
for (int k = 0; k < 3; k++) {
if (nodes[i].left_name[k] != nodes[j].name[k]) {
found = 0;
break;
}
}
if (found) {
nodes[i].left = &nodes[j];
break;
}
}
// Right
for (int j = 0; j < nodes_num; j++) {
int found = 1;
for (int k = 0; k < 3; k++) {
if (nodes[i].right_name[k] != nodes[j].name[k]) {
found = 0;
break;
}
}
if (found) {
nodes[i].right = &nodes[j];
break;
}
}
}
}
int all_ending_with(char endchar, node_t *nodes[], int nodes_num) {
for (int i = 0; i < nodes_num; i++) {
if (nodes[i]->name[2] != endchar) {
return 0;
}
}
return 1;
}