From 06ca806927a3eb8a412895ee9977d95af7efcca6 Mon Sep 17 00:00:00 2001 From: Bert Peters Date: Mon, 23 Dec 2019 20:32:22 +0100 Subject: [PATCH] Implement day 18 part 1. --- 2019/src/day18.cpp | 149 +++++++++++++++++++++------------- 2019/tests/samples/18-1-1.in | 3 + 2019/tests/samples/18-1-1.out | 1 + 2019/tests/samples/18-1-2.in | 5 ++ 2019/tests/samples/18-1-2.out | 1 + 2019/tests/samples/18-1-3.in | 5 ++ 2019/tests/samples/18-1-3.out | 1 + 2019/tests/samples/18-1-4.in | 9 ++ 2019/tests/samples/18-1-4.out | 1 + 2019/tests/samples/18-1-5.in | 6 ++ 2019/tests/samples/18-1-5.out | 1 + 11 files changed, 126 insertions(+), 56 deletions(-) create mode 100644 2019/tests/samples/18-1-1.in create mode 100644 2019/tests/samples/18-1-1.out create mode 100644 2019/tests/samples/18-1-2.in create mode 100644 2019/tests/samples/18-1-2.out create mode 100644 2019/tests/samples/18-1-3.in create mode 100644 2019/tests/samples/18-1-3.out create mode 100644 2019/tests/samples/18-1-4.in create mode 100644 2019/tests/samples/18-1-4.out create mode 100644 2019/tests/samples/18-1-5.in create mode 100644 2019/tests/samples/18-1-5.out diff --git a/2019/src/day18.cpp b/2019/src/day18.cpp index 077d4a9..1ddd2e5 100644 --- a/2019/src/day18.cpp +++ b/2019/src/day18.cpp @@ -3,18 +3,32 @@ #include #include #include -#include -#include -#include +#include +#include +#include #include "days.hpp" #include "point.hpp" -namespace { - typedef std::tuple state_t; +# - std::vector read_map(std::istream &input) { +static_assert(sizeof(int) >= 4, "Int should be at least 32 bits."); + +namespace { + typedef aoc2019::Point point_t; + typedef std::tuple state_t; + + typedef std::vector map_t; + + std::array DIRECTIONS = {{ + {0, -1}, + {0, 1}, + {-1, 0}, + {1, 0}, + }}; + + map_t read_map(std::istream &input) { std::string buffer; - std::vector map; + map_t map; while (std::getline(input, buffer)) { map.push_back(buffer); @@ -23,7 +37,7 @@ namespace { return map; } - std::pair find(const std::vector &map, char needle) { + point_t find(const std::vector &map, char needle) { for (int y = 0; y < map.size(); ++y) { auto x = map[y].find(needle); if (x != std::string::npos) { @@ -33,81 +47,104 @@ namespace { throw std::invalid_argument("Can't find it!"); } + + std::vector> find_edges(const map_t &map, point_t starting_point) { + std::vector> edges; + std::queue> todo; + todo.emplace(0, starting_point); + + std::unordered_set visited{starting_point}; + + while (!todo.empty()) { + const auto[dist, pos] = todo.front(); + todo.pop(); + + for (auto &direction : DIRECTIONS) { + auto next_pos = pos + direction; + const char at = map[next_pos[1]][next_pos[0]]; + + if (at == '#' || visited.count(next_pos)) { + // Wall or already visited, ignore + continue; + } + + visited.insert(next_pos); + + if (std::isalpha(at)) { + // Don't walk through stuff + edges.emplace_back(at, dist + 1); + } else { + todo.emplace(dist + 1, next_pos); + } + } + } + + return edges; + } } void aoc2019::day18_part1(std::istream &input, std::ostream &output) { const auto map = read_map(input); - std::priority_queue, std::vector>, std::greater<>> todo; - std::map visited; + std::unordered_map>> implied_graph; - const auto initial = find(map, '@'); - const state_t initial_state(initial.first, initial.second, ""); - visited[initial_state] = 0; - todo.emplace(0, initial_state); - - int keys_needed = 0; - for (auto &row : map) { - keys_needed += std::count_if(row.begin(), row.end(), isalpha); + 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}); + } + } } - // Don't count keys and locks double - keys_needed /= 2; + 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); }); while (!todo.empty()) { - const auto[dist, state] = todo.top(); + const auto [dist, state] = todo.top(); todo.pop(); - const auto[x, y, keys] = state; + if (visited.count(state)) { + continue; + } - if (keys.size() == keys_needed) { + visited.insert(state); + + auto [keys, pos] = state; + + if (std::__popcount(keys) == target_size) { output << dist << std::endl; return; } - std::array, 4> next_points = {{ - {x - 1, y}, - {x + 1, y}, - {x, y - 1}, - {x, y + 1} - }}; - - for (auto point : next_points) { - const auto [nx, ny] = point; + for (const auto &edge : implied_graph.at(pos)) { + auto next_dist = dist + edge.second; auto next_keys = keys; - - if (x < 0 || y < 0 || x >= map[0].size() || y >= map.size()) { - continue; - } - - char at_next = map[x][y]; - - if (at_next == '#') { - continue; - } else if (std::isupper(at_next)) { - // check if we have the key already - if (keys.find(at_next) == std::string::npos) { + if (std::islower(edge.first)) { + // Add the key to our collection + next_keys |= 1u << static_cast(edge.first - 'a'); + } else if (std::isupper(edge.first)) { + // Check if we have the required key already + if (!(next_keys & (1u << static_cast(edge.first - 'A')))) { continue; } - } else if (std::islower(at_next)) { - if (keys.find(std::toupper(at_next)) == std::string::npos) { - next_keys += std::toupper(at_next); - // Ensure unique representation - std::sort(next_keys.begin(), next_keys.end()); - } } - state_t next_state{nx, ny, std::move(next_keys)}; - if (auto it = visited.find(next_state); it == visited.end() || it->second < dist + 1) { - visited[next_state] = dist + 1; - todo.emplace(dist + 1, std::move(next_state)); + state_t next_state = {next_keys, edge.first}; + if (visited.count(next_state)) { + continue; } + + todo.emplace(next_dist, next_state); } } - output << "Not implemented\n"; + throw std::logic_error("Should have terminated by now."); } void aoc2019::day18_part2(std::istream &input, std::ostream &output) { - output << "Not implemented\n"; + output << "Not implemented\n"; } diff --git a/2019/tests/samples/18-1-1.in b/2019/tests/samples/18-1-1.in new file mode 100644 index 0000000..33802e1 --- /dev/null +++ b/2019/tests/samples/18-1-1.in @@ -0,0 +1,3 @@ +######### +#b.A.@.a# +######### diff --git a/2019/tests/samples/18-1-1.out b/2019/tests/samples/18-1-1.out new file mode 100644 index 0000000..45a4fb7 --- /dev/null +++ b/2019/tests/samples/18-1-1.out @@ -0,0 +1 @@ +8 diff --git a/2019/tests/samples/18-1-2.in b/2019/tests/samples/18-1-2.in new file mode 100644 index 0000000..af485bc --- /dev/null +++ b/2019/tests/samples/18-1-2.in @@ -0,0 +1,5 @@ +######################## +#f.D.E.e.C.b.A.@.a.B.c.# +######################.# +#d.....................# +######################## diff --git a/2019/tests/samples/18-1-2.out b/2019/tests/samples/18-1-2.out new file mode 100644 index 0000000..8cf5c1a --- /dev/null +++ b/2019/tests/samples/18-1-2.out @@ -0,0 +1 @@ +86 diff --git a/2019/tests/samples/18-1-3.in b/2019/tests/samples/18-1-3.in new file mode 100644 index 0000000..b650235 --- /dev/null +++ b/2019/tests/samples/18-1-3.in @@ -0,0 +1,5 @@ +######################## +#...............b.C.D.f# +#.###################### +#.....@.a.B.c.d.A.e.F.g# +######################## diff --git a/2019/tests/samples/18-1-3.out b/2019/tests/samples/18-1-3.out new file mode 100644 index 0000000..94361d4 --- /dev/null +++ b/2019/tests/samples/18-1-3.out @@ -0,0 +1 @@ +132 diff --git a/2019/tests/samples/18-1-4.in b/2019/tests/samples/18-1-4.in new file mode 100644 index 0000000..d5d888b --- /dev/null +++ b/2019/tests/samples/18-1-4.in @@ -0,0 +1,9 @@ +################# +#i.G..c...e..H.p# +########.######## +#j.A..b...f..D.o# +########@######## +#k.E..a...g..B.n# +########.######## +#l.F..d...h..C.m# +################# diff --git a/2019/tests/samples/18-1-4.out b/2019/tests/samples/18-1-4.out new file mode 100644 index 0000000..7296f25 --- /dev/null +++ b/2019/tests/samples/18-1-4.out @@ -0,0 +1 @@ +136 diff --git a/2019/tests/samples/18-1-5.in b/2019/tests/samples/18-1-5.in new file mode 100644 index 0000000..ee6598e --- /dev/null +++ b/2019/tests/samples/18-1-5.in @@ -0,0 +1,6 @@ +######################## +#@..............ac.GI.b# +###d#e#f################ +###A#B#C################ +###g#h#i################ +######################## diff --git a/2019/tests/samples/18-1-5.out b/2019/tests/samples/18-1-5.out new file mode 100644 index 0000000..d88e313 --- /dev/null +++ b/2019/tests/samples/18-1-5.out @@ -0,0 +1 @@ +81