diff --git a/2019/18.cpp b/2019/18.cpp new file mode 100644 index 0000000..05f6d74 --- /dev/null +++ b/2019/18.cpp @@ -0,0 +1,157 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +// lowercase key +// uppercase door +// start at @ +// wall # +// boring . + +namespace { + +using namespace aocpp; +using Map = std::vector; +using Features = std::map; +using Doors = std::bitset<26>; +using Distances = std::map>>; + +auto ReadMap(std::istream & in) -> Map { + Map result; + std::string line; + while (std::getline(in, line)) { + result.emplace_back(std::move(line)); + } + return result; +} + +auto FindFeatures(Map const& map) -> Features { + std::map features; + for (std::int64_t y = 0; y < map.size(); y++) { + for (std::int64_t x = 0; x < map[y].size(); x++) { + auto c = map[y][x]; + switch (c) { + default: features[c] = Coord{x,y}; + case '#': + case '.': {} + } + } + } + return features; +} + +auto FindDistancesFrom( + Map const& map, Features const& features, + Distances & distances, + char start_letter, Coord start +) { + std::map> result; + std::set seen; + std::deque> todo + {{0, start, {}}}; + + while (!todo.empty()) { + auto [steps, here, doors] = todo.front(); + todo.pop_front(); + if (seen.insert(here).second) { + auto c = map[here.y][here.x]; + if (c == '#') { + continue; + } + if (c != start_letter && std::islower(c)) { + distances[start_letter][c] = {steps, doors}; + continue; + } + if (std::isupper(c)) { + doors.set(c - 'A'); + } + for (auto && fn : {Up,Down,Left,Right}) { + auto here_ = fn(here); + todo.push_back({steps+1, here_, doors}); + } + } + } + + return result; +} + +auto FindDistances(Map const& map, Features const& features) -> Distances { + Distances distances; + + for (auto && [start_letter, start_coord] : features) { + if (islower(start_letter) || start_letter == '@') { + FindDistancesFrom(map, features, distances, start_letter, start_coord); + } + } + + return distances; +} + +struct P1S { + char location; + unsigned long long keys; + auto operator<=>(P1S const&) const = default; +}; + +auto HasKey(Doors doors, char key) { + return doors.test(std::toupper(key) - 'A'); +} + +auto SetKey(Doors doors, char key) { + return doors.set(std::toupper(key) - 'A'); +} + +auto Part1(Distances const& distances) -> std::int64_t { + std::set seen; + std::multimap> todo + {{0, {'@', Doors()}}}; + + while (!todo.empty()) { + auto it = todo.begin(); + auto [steps, ld] = *it; + auto& [l,keys] = ld; + todo.erase(it); + + if (keys.all()) { return steps; } + + if (seen.insert({l,keys.to_ullong()}).second) { + auto dit = distances.find(l); + if (dit != distances.end()) { + for (auto && [next, costneed] : dit->second) { + auto [cost, need] = costneed; + if ((need & (~keys)).none()) { + todo.insert({steps + cost, {next, SetKey(keys, next)}}); + } + } + } + } + } + + throw std::runtime_error{"no solution to part 1"}; +} + +} // namespace + +auto main(int argc, char** argv) -> int { + auto map = ReadMap(Startup(argc, argv)); + auto features = FindFeatures(map); + auto distances = FindDistances(map, features); + + std::cout << "Part 1: " << Part1(distances) << std::endl; + //std::cout << "Part 2: " << part2 << std::endl; +} diff --git a/2019/CMakeLists.txt b/2019/CMakeLists.txt index c76d1cf..f91ac7d 100644 --- a/2019/CMakeLists.txt +++ b/2019/CMakeLists.txt @@ -35,10 +35,13 @@ add_executable(13 13.cpp) target_link_libraries(13 aocpp intcode) add_executable(14 14.cpp) -target_link_libraries(14 aocpp) +target_link_libraries(14 aocpp Boost::boost) add_executable(15 15.cpp) target_link_libraries(15 aocpp intcode) +add_executable(18 18.cpp) +target_link_libraries(18 aocpp) + add_executable(23 23.cpp) target_link_libraries(23 aocpp intcode)