#include #include #include #include #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; }