229 lines
6.1 KiB
C
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;
|
|
}
|