18p1
This commit is contained in:
parent
35e31bf67f
commit
56288c6ed3
157
2019/18.cpp
Normal file
157
2019/18.cpp
Normal file
|
@ -0,0 +1,157 @@
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <iostream>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <fstream>
|
||||||
|
#include <iterator>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <vector>
|
||||||
|
#include <set>
|
||||||
|
#include <string>
|
||||||
|
#include <tuple>
|
||||||
|
#include <bitset>
|
||||||
|
#include <deque>
|
||||||
|
#include <cctype>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
#include <aocpp/Startup.hpp>
|
||||||
|
#include <aocpp/Coord.hpp>
|
||||||
|
|
||||||
|
// lowercase key
|
||||||
|
// uppercase door
|
||||||
|
// start at @
|
||||||
|
// wall #
|
||||||
|
// boring .
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
using namespace aocpp;
|
||||||
|
using Map = std::vector<std::string>;
|
||||||
|
using Features = std::map<char, Coord>;
|
||||||
|
using Doors = std::bitset<26>;
|
||||||
|
using Distances = std::map<char,std::map<char, std::pair<std::int64_t, Doors>>>;
|
||||||
|
|
||||||
|
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<char,Coord> 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<char, std::pair<std::int64_t, Doors>> result;
|
||||||
|
std::set<Coord> seen;
|
||||||
|
std::deque<std::tuple<std::int64_t, Coord, Doors>> 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<P1S> seen;
|
||||||
|
std::multimap<std::int64_t, std::pair<char, Doors>> 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;
|
||||||
|
}
|
|
@ -35,10 +35,13 @@ add_executable(13 13.cpp)
|
||||||
target_link_libraries(13 aocpp intcode)
|
target_link_libraries(13 aocpp intcode)
|
||||||
|
|
||||||
add_executable(14 14.cpp)
|
add_executable(14 14.cpp)
|
||||||
target_link_libraries(14 aocpp)
|
target_link_libraries(14 aocpp Boost::boost)
|
||||||
|
|
||||||
add_executable(15 15.cpp)
|
add_executable(15 15.cpp)
|
||||||
target_link_libraries(15 aocpp intcode)
|
target_link_libraries(15 aocpp intcode)
|
||||||
|
|
||||||
|
add_executable(18 18.cpp)
|
||||||
|
target_link_libraries(18 aocpp)
|
||||||
|
|
||||||
add_executable(23 23.cpp)
|
add_executable(23 23.cpp)
|
||||||
target_link_libraries(23 aocpp intcode)
|
target_link_libraries(23 aocpp intcode)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user