cleanup
This commit is contained in:
parent
6865e3594e
commit
85deec0dae
100
2019/18.cpp
100
2019/18.cpp
|
@ -18,6 +18,8 @@
|
||||||
#include <aocpp/Startup.hpp>
|
#include <aocpp/Startup.hpp>
|
||||||
#include <aocpp/Coord.hpp>
|
#include <aocpp/Coord.hpp>
|
||||||
|
|
||||||
|
using namespace aocpp;
|
||||||
|
|
||||||
// lowercase key
|
// lowercase key
|
||||||
// uppercase door
|
// uppercase door
|
||||||
// start at @
|
// start at @
|
||||||
|
@ -26,8 +28,8 @@
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
using namespace aocpp;
|
Coord(* const directions[4])(Coord) = {Up, Down, Left, Right};
|
||||||
using Map = std::vector<std::string>;
|
|
||||||
using Features = std::map<char, Coord>;
|
using Features = std::map<char, Coord>;
|
||||||
using Doors = std::bitset<26>;
|
using Doors = std::bitset<26>;
|
||||||
using Distances = std::map<char,std::map<char, std::pair<std::int64_t, Doors>>>;
|
using Distances = std::map<char,std::map<char, std::pair<std::int64_t, Doors>>>;
|
||||||
|
@ -36,22 +38,29 @@ auto SetKey(Doors& doors, char key) {
|
||||||
return doors.set(std::toupper(key) - 'A');
|
return doors.set(std::toupper(key) - 'A');
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ReadMap(std::istream & in) -> Map {
|
struct Map {
|
||||||
Map result;
|
std::vector<std::string> rows;
|
||||||
std::string line;
|
|
||||||
while (std::getline(in, line)) {
|
auto operator[](Coord c) -> char& { return rows[c.y][c.x]; }
|
||||||
result.emplace_back(std::move(line));
|
auto operator[](Coord c) const -> char { return rows[c.y][c.x]; }
|
||||||
|
|
||||||
|
static auto Parse(std::istream & in) -> Map {
|
||||||
|
Map result;
|
||||||
|
std::string line;
|
||||||
|
while (std::getline(in, line)) {
|
||||||
|
result.rows.emplace_back(std::move(line));
|
||||||
|
}
|
||||||
|
return {result};
|
||||||
}
|
}
|
||||||
return result;
|
};
|
||||||
}
|
|
||||||
|
|
||||||
auto FindFeatures(Map const& map) -> Features {
|
auto FindFeatures(Map const& map) -> Features {
|
||||||
std::map<char,Coord> features;
|
Features features;
|
||||||
for (std::int64_t y = 0; y < map.size(); y++) {
|
for (std::int64_t y = 0; y < map.rows.size(); y++) {
|
||||||
for (std::int64_t x = 0; x < map[y].size(); x++) {
|
for (std::int64_t x = 0; x < map.rows[y].size(); x++) {
|
||||||
auto const c = map[y][x];
|
auto const c = map[{x,y}];
|
||||||
if ('#' != c && '.' != c) {
|
if ('#' != c && '.' != c) {
|
||||||
features[c] = Coord{x,y};
|
features[c] = {x,y};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -59,15 +68,15 @@ auto FindFeatures(Map const& map) -> Features {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto FindDistancesFrom(
|
auto FindDistancesFrom(
|
||||||
Map const& map, Features const& features,
|
Map const& map,
|
||||||
|
Features const& features,
|
||||||
Distances & distances,
|
Distances & distances,
|
||||||
char start_letter,
|
char const start_letter,
|
||||||
Coord start
|
Coord const start
|
||||||
) {
|
) {
|
||||||
std::map<char, std::pair<std::int64_t, Doors>> result;
|
std::map<char, std::pair<std::int64_t, Doors>> result;
|
||||||
|
|
||||||
std::deque<std::tuple<std::int64_t, Coord, Doors>> todo
|
std::deque<std::tuple<std::int64_t, Coord, Doors>> todo {{0, start, {}}};
|
||||||
{{0, start, {}}};
|
|
||||||
|
|
||||||
std::set<Coord> seen;
|
std::set<Coord> seen;
|
||||||
|
|
||||||
|
@ -77,7 +86,7 @@ auto FindDistancesFrom(
|
||||||
// Don't visit the same coordinate twice
|
// Don't visit the same coordinate twice
|
||||||
if (!seen.insert(here).second) continue;
|
if (!seen.insert(here).second) continue;
|
||||||
|
|
||||||
auto const c = map[here.y][here.x];
|
auto const c = map[here];
|
||||||
if (c == '#') continue; // avoid walls
|
if (c == '#') continue; // avoid walls
|
||||||
|
|
||||||
// success, we've found a key, record the path
|
// success, we've found a key, record the path
|
||||||
|
@ -92,7 +101,7 @@ auto FindDistancesFrom(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Visit all neighbors
|
// Visit all neighbors
|
||||||
for (auto && fn : {Up,Down,Left,Right}) {
|
for (auto const fn : directions) {
|
||||||
todo.emplace_back(steps+1, fn(here), doors);
|
todo.emplace_back(steps+1, fn(here), doors);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -100,15 +109,13 @@ auto FindDistancesFrom(
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto FindDistances(Map const& map, Features const& features) -> Distances {
|
auto FindDistances(Map const& map, Features const& features) {
|
||||||
Distances distances;
|
Distances distances;
|
||||||
|
for (auto const [start_letter, start_coord] : features) {
|
||||||
for (auto && [start_letter, start_coord] : features) {
|
|
||||||
if (!std::isupper(start_letter)) {
|
if (!std::isupper(start_letter)) {
|
||||||
FindDistancesFrom(map, features, distances, start_letter, start_coord);
|
FindDistancesFrom(map, features, distances, start_letter, start_coord);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return distances;
|
return distances;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,11 +128,12 @@ auto SolveMaze(
|
||||||
using Visited = std::pair<std::string, unsigned long long>;
|
using Visited = std::pair<std::string, unsigned long long>;
|
||||||
std::set<Visited> seen;
|
std::set<Visited> seen;
|
||||||
|
|
||||||
using QElt = std::tuple<std::int64_t, std::string, Doors>;
|
// Priority queue returning lowest path cost states first.
|
||||||
struct Cmp { auto operator()(QElt const& x, QElt const& y) -> bool {
|
using PqElt = std::tuple<std::int64_t, std::string, Doors>;
|
||||||
return std::get<0>(x) > std::get<0>(y);
|
using PqCmp = decltype([](PqElt const& x, PqElt const& y) {
|
||||||
}};
|
return std::get<0>(x) > std::get<0>(y); });
|
||||||
std::priority_queue<QElt, std::vector<QElt>, Cmp> todo;
|
std::priority_queue<PqElt, std::vector<PqElt>, PqCmp> todo;
|
||||||
|
|
||||||
todo.emplace(0, initial_locations, Doors());
|
todo.emplace(0, initial_locations, Doors());
|
||||||
|
|
||||||
while(!todo.empty()) {
|
while(!todo.empty()) {
|
||||||
|
@ -138,10 +146,10 @@ auto SolveMaze(
|
||||||
if (seen.emplace(locations, keys.to_ullong()).second) {
|
if (seen.emplace(locations, keys.to_ullong()).second) {
|
||||||
|
|
||||||
for (auto& location : locations) {
|
for (auto& location : locations) {
|
||||||
auto save = location;
|
auto const save = location;
|
||||||
|
|
||||||
for (auto [next, costneed] : distances.at(location)) {
|
for (auto const [next, costneed] : distances.at(location)) {
|
||||||
auto [cost, need] = costneed;
|
auto const [cost, need] = costneed;
|
||||||
if ((need & ~keys).none()) { // no missing keys
|
if ((need & ~keys).none()) { // no missing keys
|
||||||
location = next;
|
location = next;
|
||||||
auto keys_ = keys; SetKey(keys_, next);
|
auto keys_ = keys; SetKey(keys_, next);
|
||||||
|
@ -156,30 +164,28 @@ auto SolveMaze(
|
||||||
throw std::runtime_error{"no solution to part 1"};
|
throw std::runtime_error{"no solution to part 1"};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto UpdateMap(Map& map, Features & features) {
|
// Part 2 instructs us to update the map splitting it into 4 quadrants
|
||||||
auto start = features['@'];
|
auto Part2(Map& map, Features & features) {
|
||||||
map[start.y][start.x] = '#';
|
auto const start = features['@'];
|
||||||
map[start.y][start.x+1] = '#';
|
for (auto const fn : directions) {
|
||||||
map[start.y][start.x-1] = '#';
|
map[fn(start)] = '#';
|
||||||
map[start.y+1][start.x] = '#';
|
}
|
||||||
map[start.y-1][start.x] = '#';
|
|
||||||
features.erase('@');
|
features.erase('@');
|
||||||
features['^'] = Up(Left(start));
|
features['^'] = Up(Left (start));
|
||||||
features['&'] = Down(Left(start));
|
features['&'] = Down(Left (start));
|
||||||
features['*'] = Up(Right(start));
|
features['*'] = Up(Right(start));
|
||||||
features['$'] = Down(Right(start));
|
features['$'] = Down(Right(start));
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
auto main(int argc, char** argv) -> int {
|
auto main(int argc, char** argv) -> int {
|
||||||
auto map = ReadMap(Startup(argc, argv));
|
auto map = Map::Parse(Startup(argc, argv));
|
||||||
auto features = FindFeatures(map);
|
auto features = FindFeatures(map);
|
||||||
auto distances = FindDistances(map, features);
|
auto distances = FindDistances(map, features);
|
||||||
|
|
||||||
std::cout << "Part 1: " << SolveMaze(distances, "@") << std::endl;
|
std::cout << "Part 1: " << SolveMaze(distances, "@") << std::endl;
|
||||||
|
|
||||||
UpdateMap(map, features);
|
Part2(map, features);
|
||||||
distances = FindDistances(map, features);
|
distances = FindDistances(map, features);
|
||||||
std::cout << "Part 2: " << SolveMaze(distances, "^&*$") << std::endl;
|
std::cout << "Part 2: " << SolveMaze(distances, "^&*$") << std::endl;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user