diff --git a/12/12-1and2.c b/12/12-1and2.c new file mode 100644 index 0000000..89ff953 --- /dev/null +++ b/12/12-1and2.c @@ -0,0 +1,250 @@ +#include +#include +#include +#include +#include + +#define PART_2 + +#define ADJACENT_NODE_SIZE 8 // MAX NUMBER OF CONNECTED NODES +#define MAX_CAVES 20 +#define NAME_BUF 5 + +#ifdef PART_2 +#define MAX_VISITS 2 +#else +#define MAX_VISITS 1 +#endif +// ASSUME STRING IS EITHER ALL UPPERCASE OR ALL LOWERCASE +size_t max_visits(char *name) +{ + if (strcmp(name, "start") == 0 || strcmp(name, "end") == 0) + return 1; + else if (isupper(name[0]) != 0) + return 0; + return MAX_VISITS; // LOWERCASE +} + +typedef struct __node +{ + char *name; + size_t max_visits; // 0 => INFINITE VISITS + size_t visit_count; + struct __node **linked; + size_t id; + int n_linked; +} NODE; + +NODE *new_node(char *name, size_t id) +{ + NODE *p_node = calloc(1, sizeof(NODE)); + p_node->name = name; + p_node->max_visits = max_visits(name); + p_node->visit_count = 0; + p_node->id = id; + p_node->linked = calloc(ADJACENT_NODE_SIZE, sizeof(NODE *)); + p_node->n_linked = 0; + return p_node; +} + +void link_nodes(NODE *node1, NODE *node2) +{ + node2->linked[node2->n_linked] = node1; + node1->linked[node1->n_linked] = node2; + node1->n_linked++; + node2->n_linked++; +} + +// NOTE - A HASHTABLE WOULD WORK GREAT FOR VERY LARGE SYSTEMS, BUT SINCE +// THE CHALLENGE IS SMALL WE WILL USE A SIMPLE LIST. +typedef struct +{ + NODE **nodes; + int n_nodes; + NODE *start_node; + NODE *end_node; +} CAVE_SYSTEM; + +CAVE_SYSTEM *new_cave_system() +{ + CAVE_SYSTEM *p_cave_system = calloc(1, sizeof(CAVE_SYSTEM)); + p_cave_system->nodes = calloc(MAX_CAVES, sizeof(NODE *)); +} + +int add_new_cave(CAVE_SYSTEM *caves, char *name) +{ + if (caves->n_nodes > MAX_CAVES) + exit(EXIT_FAILURE); + for (int i = 0; i < caves->n_nodes; i++) + if (strcmp(name, caves->nodes[i]->name) == 0) + return i; + caves->nodes[caves->n_nodes] = new_node(name, caves->n_nodes); + if (caves->start_node == NULL && strcmp(name, "start") == 0) + caves->start_node = caves->nodes[caves->n_nodes]; + else if (caves->end_node == NULL && strcmp(name, "end") == 0) + caves->end_node = caves->nodes[caves->n_nodes]; + caves->n_nodes++; + return caves->n_nodes - 1; +} + +void print_links(CAVE_SYSTEM *caves) +{ + for (size_t i = 0; i < caves->n_nodes; i++) + { + printf("%s:\t", caves->nodes[i]->name); + for (size_t j = 0; caves->nodes[i]->linked[j] != NULL; j++) + { + printf("%s ", caves->nodes[i]->linked[j]->name); + } + putchar('\n'); + } +} + +// READ INPUT CAVES +void read_link(CAVE_SYSTEM *system, char *link_description) +{ + char buf1[NAME_BUF]; + int cave1_idx, cave2_idx; + char buf2[NAME_BUF]; + sscanf(link_description, "%[^-]-%[^\n]\n", buf1, buf2); + cave1_idx = add_new_cave(system, strdup(buf1)); + cave2_idx = add_new_cave(system, strdup(buf2)); + link_nodes(system->nodes[cave1_idx], system->nodes[cave2_idx]); +} + +CAVE_SYSTEM *read_file(char *input) +{ + CAVE_SYSTEM *p_caves = new_cave_system(); + FILE *p_file = fopen(input, "r"); + char buf[BUFSIZ]; + while (fgets(buf, sizeof buf, p_file) != NULL) + read_link(p_caves, buf); + return p_caves; +} + +// +// CAVE TRAVERSAL LOGIC +// + +typedef struct +{ + NODE **excluded_nodes; + NODE **path; + int path_len; + int n_paths; +#ifdef PART_2 + int n_double_visits; +#endif +} TRAVERSAL_CONTEXT; + +TRAVERSAL_CONTEXT *new_traversal_context(void) +{ + TRAVERSAL_CONTEXT *p_context = calloc(1, sizeof(TRAVERSAL_CONTEXT)); + p_context->excluded_nodes = calloc(MAX_CAVES, sizeof(NODE *)); + p_context->path = calloc(MAX_VISITS * MAX_CAVES, sizeof(NODE *)); + p_context->path_len = 0; + p_context->n_paths = 0; +#ifdef PART_2 + p_context->n_double_visits = 0; +#endif + return p_context; +} + +void print_path_stack(TRAVERSAL_CONTEXT *context) +{ + for (size_t i = 0; i < context->path_len; i++) + printf("%s -> ", context->path[i]->name); + putchar('\n'); +} + +bool excluded(TRAVERSAL_CONTEXT *context, NODE *node) +{ + for (size_t i = 0; i < MAX_CAVES; i++) + { + if (context->excluded_nodes != NULL && context->excluded_nodes[i] == node) + return true; + } + return false; +} + +void remove_excluded(TRAVERSAL_CONTEXT *context, NODE *node) +{ + for (size_t i = 0; i < MAX_CAVES; i++) + if (context->excluded_nodes != NULL && context->excluded_nodes[i] == node) + { + context->excluded_nodes[i] = NULL; +#ifdef PART_2 + context->n_double_visits--; +#endif + } +} +void add_excluded(TRAVERSAL_CONTEXT *context, NODE *node) +{ + for (size_t i = 0; i < MAX_CAVES; i++) + if (context->excluded_nodes[i] != NULL) + { + if (context->excluded_nodes[i] == node) + return; + } + else + { + context->excluded_nodes[i] = node; +#ifdef PART_2 + if (node->max_visits == MAX_VISITS) + context->n_double_visits++; +#endif + return; + } +} + +void finish_node(NODE *node, TRAVERSAL_CONTEXT *context) +{ + + if (node->max_visits > 0) + { + node->visit_count--; + if (node->visit_count < node->max_visits) + remove_excluded(context, node); + } + context->path_len--; +} + +void traverse(NODE *start, TRAVERSAL_CONTEXT *context) +{ + context->path[context->path_len] = start; + context->path_len++; + start->visit_count++; +#ifdef PART_2 + if (context->n_double_visits > 1 || excluded(context, start)) +#else + if (excluded(context, start)) +#endif + { + finish_node(start, context); + return; + } + if (strcmp(start->name, "end") == 0) + { + // printf("%s : ", start->name); + // print_path_stack(context); + context->n_paths++; + finish_node(start, context); + return; + } + + if (start->max_visits > 0 && start->visit_count >= start->max_visits) + add_excluded(context, start); + for (size_t i = 0; start->linked[i] != NULL; i++) + traverse(start->linked[i], context); + finish_node(start, context); +} + +int main(int argc, char const *argv[]) +{ + CAVE_SYSTEM *p_caves = read_file("input"); + print_links(p_caves); + TRAVERSAL_CONTEXT *p_context = new_traversal_context(); + traverse(p_caves->start_node, p_context); + printf("n_paths : %d\n", p_context->n_paths); + return 0; +}