From 8f112aa91f373f5b8bf44153df53ed25f0ea22b3 Mon Sep 17 00:00:00 2001 From: Bert Peters Date: Mon, 23 Dec 2019 22:25:21 +0100 Subject: [PATCH] Implement day 18 part 2. It's really slow so I'll have to improve it. --- 2019/src/day18.cpp | 124 ++++++++++++++++++++++++++++------ 2019/tests/samples/18-2-1.in | 7 ++ 2019/tests/samples/18-2-1.out | 1 + 3 files changed, 113 insertions(+), 19 deletions(-) create mode 100644 2019/tests/samples/18-2-1.in create mode 100644 2019/tests/samples/18-2-1.out diff --git a/2019/src/day18.cpp b/2019/src/day18.cpp index 1ddd2e5..161c8cf 100644 --- a/2019/src/day18.cpp +++ b/2019/src/day18.cpp @@ -2,20 +2,18 @@ #include #include #include -#include #include #include #include #include "days.hpp" #include "point.hpp" -# - static_assert(sizeof(int) >= 4, "Int should be at least 32 bits."); +using namespace std::string_view_literals; + namespace { typedef aoc2019::Point point_t; - typedef std::tuple state_t; typedef std::vector map_t; @@ -81,30 +79,43 @@ namespace { return edges; } + + auto compute_implied_graph(const map_t &map) { + std::unordered_map>> implied_graph; + + for (int y = 0; y < map.size(); ++y) { + for (int x = 0; x < map[y].size(); ++x) { + char at = map[y][x]; + if ("@/^*"sv.find(at) != std::string_view::npos || std::isalpha(at)) { + implied_graph[at] = find_edges(map, {x, y}); + } + } + } + + return implied_graph; + } + + inline unsigned int key_index(char c) { + return 1u << static_cast(c - 'A'); + } } void aoc2019::day18_part1(std::istream &input, std::ostream &output) { + using state_t = std::tuple; + const auto map = read_map(input); - std::unordered_map>> implied_graph; - - for (int y = 0; y < map.size(); ++y) { - for (int x = 0; x < map[y].size(); ++x) { - char at = map[y][x]; - if (at == '@' || std::isalpha(at)) { - implied_graph[at] = find_edges(map, {x, y}); - } - } - } + auto implied_graph = compute_implied_graph(map); std::priority_queue, std::vector>, std::greater<>> todo; std::set visited; todo.emplace(0, std::make_pair(0, '@')); - auto target_size = std::count_if(implied_graph.cbegin(), implied_graph.cend(), [](auto &x) { return std::islower(x.first); }); + auto target_size = std::count_if(implied_graph.cbegin(), implied_graph.cend(), + [](auto &x) { return std::islower(x.first); }); while (!todo.empty()) { - const auto [dist, state] = todo.top(); + const auto[dist, state] = todo.top(); todo.pop(); if (visited.count(state)) { @@ -113,7 +124,7 @@ void aoc2019::day18_part1(std::istream &input, std::ostream &output) { visited.insert(state); - auto [keys, pos] = state; + auto[keys, pos] = state; if (std::__popcount(keys) == target_size) { output << dist << std::endl; @@ -125,10 +136,10 @@ void aoc2019::day18_part1(std::istream &input, std::ostream &output) { auto next_keys = keys; if (std::islower(edge.first)) { // Add the key to our collection - next_keys |= 1u << static_cast(edge.first - 'a'); + next_keys |= key_index(edge.first);; } else if (std::isupper(edge.first)) { // Check if we have the required key already - if (!(next_keys & (1u << static_cast(edge.first - 'A')))) { + if (!(next_keys & key_index(edge.first))) { continue; } } @@ -146,5 +157,80 @@ void aoc2019::day18_part1(std::istream &input, std::ostream &output) { } void aoc2019::day18_part2(std::istream &input, std::ostream &output) { + using state_t = std::tuple>; + + auto map = read_map(input); + + // problem statement says to duplicate @ but where's the fun in that + const auto initial_pos = find(map, '@'); + + // problem statement says to duplicate @ but where's the fun in that, let's have different starting positions + std::array overlay = { + "@#*", + "###", + "^#/", + }; + + for (int y = 0; y < 3; ++y) { + auto &row = map[initial_pos[1] + y - 1]; + std::copy(overlay[y].begin(), overlay[y].end(), row.data() + initial_pos[0] - 1); + } + + const auto implied_graph = compute_implied_graph(map); + + std::priority_queue, std::vector>, std::greater<>> todo; + std::set visited; + todo.emplace(0, state_t(0, {'@', '*', '^', '/'})); + + auto target_size = std::count_if(implied_graph.cbegin(), implied_graph.cend(), + [](auto &x) { return std::islower(x.first); }); + + while (!todo.empty()) { + const auto[dist, state] = todo.top(); + todo.pop(); + + if (visited.count(state)) { + continue; + } + + visited.insert(state); + + auto[keys, pos] = state; + + if (std::__popcount(keys) == target_size) { + output << dist << std::endl; + return; + } + + for (int i = 0; i < 4; ++i) { + auto next_pos = pos; + char &subpos = next_pos[i]; + + for (const auto &edge : implied_graph.at(subpos)) { + auto next_dist = dist + edge.second; + auto next_keys = keys; + if (std::islower(edge.first)) { + // Add the key to our collection + next_keys |= key_index(edge.first);; + } else if (std::isupper(edge.first)) { + // Check if we have the required key already + if (!(next_keys & key_index(edge.first))) { + continue; + } + } + + subpos = edge.first; + + state_t next_state = {next_keys, next_pos}; + if (visited.count(next_state)) { + continue; + } + + todo.emplace(next_dist, next_state); + } + } + } + + output << "Not implemented\n"; } diff --git a/2019/tests/samples/18-2-1.in b/2019/tests/samples/18-2-1.in new file mode 100644 index 0000000..a2cfd7e --- /dev/null +++ b/2019/tests/samples/18-2-1.in @@ -0,0 +1,7 @@ +############### +#d.ABC.#.....a# +######...###### +######.@.###### +######...###### +#b.....#.....c# +############### diff --git a/2019/tests/samples/18-2-1.out b/2019/tests/samples/18-2-1.out new file mode 100644 index 0000000..a45fd52 --- /dev/null +++ b/2019/tests/samples/18-2-1.out @@ -0,0 +1 @@ +24