From b9e08c1ce5f089b500406576f833924c877bb6e9 Mon Sep 17 00:00:00 2001 From: Kyle Shores Date: Mon, 23 Dec 2024 12:32:28 -0600 Subject: [PATCH] I guess counting cycles may not be it? --- 2024/src/CMakeLists.txt | 1 + 2024/src/day21.cpp | 63 ++--------- 2024/src/day23.cpp | 227 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 239 insertions(+), 52 deletions(-) create mode 100644 2024/src/day23.cpp diff --git a/2024/src/CMakeLists.txt b/2024/src/CMakeLists.txt index 8a76a01..6e3e2f1 100644 --- a/2024/src/CMakeLists.txt +++ b/2024/src/CMakeLists.txt @@ -33,6 +33,7 @@ create_standard_test(NAME 2024_day19 SOURCES day19.cpp LIBRARIES aoc2024) create_standard_test(NAME 2024_day20 SOURCES day20.cpp LIBRARIES aoc2024) create_standard_test(NAME 2024_day21 SOURCES day21.cpp LIBRARIES aoc2024) create_standard_test(NAME 2024_day22 SOURCES day22.cpp LIBRARIES aoc2024) +create_standard_test(NAME 2024_day23 SOURCES day23.cpp LIBRARIES aoc2024) ################################################################################ # Copy input data diff --git a/2024/src/day21.cpp b/2024/src/day21.cpp index 3819548..fe305b3 100644 --- a/2024/src/day21.cpp +++ b/2024/src/day21.cpp @@ -76,12 +76,14 @@ std::pair build_graph(const std::vector &keypad) // between each pair of vertices and stored that in a map using Distances = std::map>; using Paths = std::map>; +using DirectionChanges = Distances; std::pair floyd_warshall(const std::pair& graph) { const auto& [vertices, edges] = graph; Distances dist; Paths prev; + DirectionChanges direction_changes; for (const auto &u : vertices) { @@ -89,6 +91,7 @@ std::pair floyd_warshall(const std::pair& gra { dist[u][v] = INT_MAX; prev[u][v] = Pos{.x = -1, .y = -1}; + direction_changes[u][v] = 0; } } @@ -98,9 +101,11 @@ std::pair floyd_warshall(const std::pair& gra { dist[u][v] = 1; prev[u][v] = u; + direction_changes[u][v] = 0; } dist[u][u] = 0; prev[u][u] = u; + direction_changes[u][u] = 0; } for (const auto &k : vertices) @@ -112,6 +117,10 @@ std::pair floyd_warshall(const std::pair& gra auto &dik = dist[i][k]; auto &dkj = dist[k][j]; auto &dij = dist[i][j]; + + auto &dik_dir = direction_changes[i][k]; + auto &dkj_dir = direction_changes[k][j]; + auto &dij_dir = direction_changes[i][j]; if (dik != INT_MAX && dkj != INT_MAX && dij > dik + dkj) { dij = dik + dkj; @@ -124,7 +133,7 @@ std::pair floyd_warshall(const std::pair& gra return {dist, prev}; } -std::vector shortest_path1(const Pos &start, const Pos &end, const Paths &paths, const Distances &distances, std::vector keypad) +std::vector shortest_path(const Pos &start, const Pos &end, const Paths &paths) { std::vector path; Pos current = end; @@ -138,63 +147,13 @@ std::vector shortest_path1(const Pos &start, const Pos &end, const Paths &p return path; } -// std::vector shortest_path2(const Pos &start, const Pos &end, const Paths &paths, const Distances &distances, std::vector keypad) -// { -// std::vector path; -// Pos current = end; - -// Pos last_direction = {0, 0}; - -// while (current != start) -// { -// path.push_back(current); - -// Pos next = paths.at(start).at(current); -// if (next != start) -// { -// Pos candidate_direction = current - next; - -// // Check if the same-distance alternative exists with the same direction -// Pos alternative = current; -// bool found_alternative = false; - -// // Iterate through potential neighbors of `current` -// for(auto& dir : directions) -// { -// Pos candidate_pos = current + dir; -// if (in_bounds(candidate_pos.x, candidate_pos.y, keypad) && keypad.at(candidate_pos.y).at(candidate_pos.x) != ' ' && -// distances.at(start).at(candidate_pos) == distances.at(start).at(current)) -// { -// alternative = candidate_pos; -// found_alternative = true; -// break; -// } -// } - -// if (found_alternative) -// { -// next = alternative; -// } - -// // Update the last direction -// last_direction = candidate_direction; -// } - -// current = next; -// } - -// path.push_back(start); -// std::reverse(path.begin(), path.end()); -// return path; -// } - std::string get_path(std::string path, const Paths& shortest_paths, const Distances& distances, std::vector keypad, std::map char_to_pos) { Pos start = char_to_pos['A']; std::string numeric_path; Pos current = start; for (char c : path) { Pos next = char_to_pos[c]; - auto path = shortest_path1(current, next, shortest_paths, distances, keypad); + auto path = shortest_path(current, next, shortest_paths); for(size_t i = 0; i < path.size() - 1; ++i) { Pos dir = path[i + 1] - path[i]; if (dir == up) { diff --git a/2024/src/day23.cpp b/2024/src/day23.cpp new file mode 100644 index 0000000..bf38371 --- /dev/null +++ b/2024/src/day23.cpp @@ -0,0 +1,227 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct Node { + std::string name; + bool name_has_t; + std::vector neighbors; + int id; +}; + +struct Data { + std::map nodes; + std::map nodes_by_id; + + ~Data() { + for (auto node : nodes) { + delete node.second; + } + } +}; + +using AdjacencyMatrix = std::vector>; + +// int DFS(const Data& data, const AdjacencyMatrix& graph, std::vector& visited, int n_cycles, int start) { +// int count = 0; +// // vertex, cycles, vertex with t in its name +// std::stack> stack; + +// stack.push({start, n_cycles, data.nodes_by_id.at(start)->name_has_t}); + +// while(!stack.empty()) { +// auto& [node, cycles, has_t] = stack.top(); +// visited[node] = 1; +// stack.pop(); +// if (cycles == 0) { +// visited[node] = 0; +// if(graph[node][start] == graph[start][node] && has_t) { +// ++count; +// } +// } + +// for(int i = 0; i < graph.size(); ++i) { +// if (graph[node][i] == 1 && visited[i] == 0) { +// stack.push({i, cycles - 1, has_t | data.nodes_by_id.at(i)->name_has_t}); +// } +// } +// } + +// return count; +// } + +struct Args { + int start; + int vert; + int n; + bool has_t; +}; + +void DFS(const Data& data, const AdjacencyMatrix& graph, std::vector& marked, int& count, Args args, int depth = 1) { + marked[args.vert] = 1; + + if (args.n == 0) { + marked[args.vert] = 0; + if(graph[args.vert][args.start] == graph[args.start][args.vert] && args.has_t) { + ++count; + } + return; + } + + for(auto& neighbor : data.nodes_by_id.at(args.vert)->neighbors) { + if (marked[neighbor->id] == 0) { + std::string indent(2*depth, ' '); + std::cout << indent << neighbor->name << std::endl; + Args newargs = { + .start = args.start, + .vert = neighbor->id, + .n = args.n - 1, + .has_t = args.has_t || neighbor->name_has_t + }; + DFS(data, graph, marked, count, newargs, depth + 1); + } + } + marked[args.vert] = 0; +} + +int count_cycles(const Data& data, const AdjacencyMatrix& graph, int n_cycles) { + std::vector visited(graph.size(), 0); + int count = 0; + for(const auto& [id, node] : data.nodes_by_id) { + bool d = node->name == "co"; + std::cout << node->name << std::endl; + Args args = { + .vert = id, + .start = id, + .n = n_cycles - 1, + .has_t = node->name_has_t + }; + DFS(data, graph, visited, count, args); + visited[id] = 1; + std::cout << std::endl; + } + return count / 2; +} + +int part1(const Data &data) +{ + AdjacencyMatrix graph(data.nodes.size(), std::vector(data.nodes.size(), 0)); + for(const auto& [id, node] : data.nodes_by_id) { + for(auto neighbor : node->neighbors) { + graph[id][neighbor->id] = 1; + } + } + + return count_cycles(data, graph, 3); +} + +int part2(const Data &data) +{ + return 0; +} + +Data parse() +{ + std::ifstream file(std::filesystem::path("inputs/day23.txt")); + if (!file.is_open()) + { + throw std::runtime_error("file not found"); + } + std::string line; + Data data; + + int id = 0; + while (std::getline(file, line)) + { + std::vector parts = split(line, "-"); + Node* n1 = nullptr; + Node* n2 = nullptr; + if (data.nodes.find(parts[0]) == data.nodes.end()) { + n1 = new Node(); + n1->name = parts[0]; + n1->id = id++; + n1->name_has_t = n1->name.find('t') != std::string::npos; + data.nodes[parts[0]] = n1; + data.nodes_by_id[n1->id] = n1; + } else { + n1 = data.nodes[parts[0]]; + } + if (data.nodes.find(parts[1]) == data.nodes.end()) { + n2 = new Node(); + n2->name = parts[1]; + n2->id = id++; + n2->name_has_t = n2->name.find('t') != std::string::npos; + data.nodes[parts[1]] = n2; + data.nodes_by_id[n2->id] = n2; + } else { + n2 = data.nodes[parts[1]]; + } + n1->neighbors.push_back(n2); + n2->neighbors.push_back(n1); + } + + return data; +} + +class BenchmarkFixture : public benchmark::Fixture +{ +public: + static Data data; +}; + +Data BenchmarkFixture::data = parse(); + +BENCHMARK_DEFINE_F(BenchmarkFixture, Part1Benchmark) +(benchmark::State &state) +{ + for (auto _ : state) + { + auto s = part1(data); + benchmark::DoNotOptimize(s); + } +} + +BENCHMARK_DEFINE_F(BenchmarkFixture, Part2Benchmark) +(benchmark::State &state) +{ + for (auto _ : state) + { + auto s = part2(data); + benchmark::DoNotOptimize(s); + } +} + +BENCHMARK_REGISTER_F(BenchmarkFixture, Part1Benchmark)->Unit(benchmark::kMillisecond); +BENCHMARK_REGISTER_F(BenchmarkFixture, Part2Benchmark)->Unit(benchmark::kMillisecond); + +int main(int argc, char **argv) +{ + Data data = parse(); + + int answer1 = 0; + int answer2 = 0; + + auto first = part1(data); + std::cout << "Part 1: " << first << std::endl; + + auto second = part2(data); + std::cout << "Part 2: " << second << std::endl; + + first != answer1 ? throw std::runtime_error("Part 1 incorrect") : nullptr; + second != answer2 ? throw std::runtime_error("Part 2 incorrect") : nullptr; + + for (int i = 1; i < argc; ++i) { + if (std::string(argv[i]) == "--benchmark") { + benchmark::Initialize(&argc, argv); + benchmark::RunSpecifiedBenchmarks(); + return 0; + } + } +}