This commit is contained in:
Eric Mertens 2022-11-11 21:39:36 -08:00
parent 29146ec1ee
commit e96354c4ec
5 changed files with 172 additions and 96 deletions

124
2019/10.cpp Normal file
View File

@ -0,0 +1,124 @@
#include <algorithm>
#include <iostream>
#include <utility>
#include <numeric>
#include <set>
#include <map>
#include <aocpp/Startup.hpp>
#include <aocpp/Coord.hpp>
#include <aocpp/Grid.hpp>
using namespace aocpp;
namespace {
template<typename T>
struct Rational {
T numerator, denominator;
Rational() : numerator{0}, denominator{1} {}
Rational(T x) : numerator{x}, denominator{1} {}
Rational(T n, T d) {
if (d == 0) { numerator = 1; denominator = 0; return; }
if (d < 0) { d = -d; n = -n; }
T m = std::gcd(n,d);
numerator = n / m;
denominator = d / m;
}
auto constexpr operator<=>(Rational const& rhs) const -> std::strong_ordering {
return numerator * rhs.denominator <=> rhs.numerator * denominator;
}
};
template <typename T>
auto operator<<(std::ostream & out, Rational<T> const& r) -> std::ostream & {
return out << r.numerator << "/" << r.denominator;
}
/// Map a vector to a rational number such that the numbers are
/// ordered starting with up and proceeding clockwise.
/// Each quadrant is mapped to a whole number. Slopes in that
/// quadrant are mapped to a fraction between 0 and 1.
auto angle(Coord c) -> Rational<std::int64_t> {
auto mk = [](std::int64_t q, std::int64_t a, std::int64_t b) {
return Rational{q*(a+b)-b, a+b};
};
return
c.x == 0 && c.y == 0 ? -1 :
c.x >= 0 && c.y < 0 ? mk(1, c.x, -c.y) :
c.x > 0 && c.y >= 0 ? mk(2, c.y, c.x) :
c.x <= 0 && c.y > 0 ? mk(3,-c.x, c.y) :
mk(4, c.y, c.x);
}
auto Part1(Grid const& grid) {
std::size_t best = 0;
Coord base {};
grid.each([&](Coord src, char s) {
if ('#' == s) {
std::set<Rational<std::int64_t>> angles;
grid.each([&](Coord dst, char d){
if ('#' == d && src != dst) {
auto delta = dst - src;
angles.insert(angle(dst - src));
}
});
auto n = angles.size();
if (n > best) {
best = n;
base = src;
}
}
});
return std::make_pair(best, base);
}
auto Part2(Grid const& grid, Coord base) {
std::map<Rational<std::int64_t>, std::vector<Coord>> targets;
// arrange all the other asteroids by their angle relative to the base
grid.each([&](Coord c, char v){
if (c != base && v == '#') {
targets[angle(c-base)].push_back(c);
}
});
// Sort to vectors per angle such that the nearest asteroids are at
// the end of the list
for (auto & [_, vec] : targets) {
std::sort(vec.begin(), vec.end(), [](auto const& x, auto const& y) {
return Norm1(x) > Norm1(y);
});
}
// Remove 199 asteroids from the asteroid list
auto cursor = targets.begin();
for (std::size_t n = 199; n > 0; n--) {
if (targets.empty()) { throw std::runtime_error{"no solution to part 2"}; }
cursor->second.pop_back();
if (cursor->second.empty()) {
cursor = targets.erase(cursor);
} else {
cursor++;
}
if (cursor == targets.end()) {
cursor = targets.begin();
}
}
// Report the location of the 200th asteroid
auto const& asteroid = cursor->second.back();
return 100 * asteroid.x + asteroid.y;
}
} // namespace
auto main(int argc, char** argv) -> int {
auto grid = Grid::Parse(Startup(argc, argv));
auto [part1, base] = Part1(grid);
std::cout << "Part 1: " << part1 << std::endl;
std::cout << "Part 2: " << Part2(grid, base) << std::endl;
}

View File

@ -17,6 +17,7 @@
#include <aocpp/Startup.hpp>
#include <aocpp/Coord.hpp>
#include <aocpp/Grid.hpp>
using namespace aocpp;
@ -38,37 +39,18 @@ auto SetKey(Doors& doors, char key) {
return doors.set(std::toupper(key) - 'A');
}
struct Map {
std::vector<std::string> rows;
auto operator[](Coord c) -> char& { return rows[c.y][c.x]; }
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};
}
};
auto FindFeatures(Map const& map) -> Features {
auto FindFeatures(Grid const& grid) -> Features {
Features features;
for (std::size_t y = 0; y < map.rows.size(); y++) {
for (std::size_t x = 0; x < map.rows[y].size(); x++) {
auto const c = map[{std::int64_t(x),std::int64_t(y)}];
if ('#' != c && '.' != c) {
features[c] = {std::int64_t(x),std::int64_t(y)};
}
grid.each([&](Coord c, char v) {
if ('#' != v && '.' != v) {
features[v] = c;
}
}
});
return features;
}
auto FindDistancesFrom(
Map const& map,
Grid const& grid,
char const start_letter,
Coord const start
) {
@ -84,7 +66,7 @@ auto FindDistancesFrom(
// Don't visit the same coordinate twice
if (!seen.insert(here).second) continue;
auto const c = map[here];
auto const c = grid[here];
if (c == '#') continue; // avoid walls
// success, we've found a key, record the path
@ -107,11 +89,11 @@ auto FindDistancesFrom(
return result;
}
auto FindDistances(Map const& map, Features const& features) {
auto FindDistances(Grid const& grid, Features const& features) {
Distances distances;
for (auto const [start_letter, start_coord] : features) {
if (!std::isupper(start_letter)) {
distances[start_letter] = FindDistancesFrom(map, start_letter, start_coord);
distances[start_letter] = FindDistancesFrom(grid, start_letter, start_coord);
}
}
return distances;
@ -163,10 +145,10 @@ auto SolveMaze(
}
// Part 2 instructs us to update the map splitting it into 4 quadrants
auto Part2(Map& map, Features & features) {
auto Part2(Grid & grid, Features & features) {
auto const start = features['@'];
for (auto const fn : directions) {
map[fn(start)] = '#';
grid[fn(start)] = '#';
}
features.erase('@');
features['^'] = Up(Left (start));
@ -178,12 +160,12 @@ auto Part2(Map& map, Features & features) {
} // namespace
auto main(int argc, char** argv) -> int {
auto map = Map::Parse(Startup(argc, argv));
auto features = FindFeatures(map);
auto distances = FindDistances(map, features);
auto grid = Grid::Parse(Startup(argc, argv));
auto features = FindFeatures(grid);
auto distances = FindDistances(grid, features);
std::cout << "Part 1: " << SolveMaze(distances, "@") << std::endl;
Part2(map, features);
distances = FindDistances(map, features);
Part2(grid, features);
distances = FindDistances(grid, features);
std::cout << "Part 2: " << SolveMaze(distances, "^&*$") << std::endl;
}

View File

@ -17,6 +17,7 @@
#include <aocpp/Startup.hpp>
#include <aocpp/Coord.hpp>
#include <aocpp/Grid.hpp>
using namespace aocpp;
@ -28,43 +29,27 @@ using Name = std::string;
using Portals = std::map<std::string, Coord>;
using Distances = std::map<Name,std::vector<std::pair<Name, std::int64_t>>>;
struct Map {
std::vector<std::string> rows;
auto operator[](Coord c) -> char& { return rows[c.y][c.x]; }
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};
}
};
auto FindPortals(Map const& map) -> Portals {
auto FindPortals(Grid const& grid) -> Portals {
Portals portals;
std::int64_t w = map.rows[0].size();
std::int64_t h = map.rows.size();
std::int64_t w = grid.rows[0].size();
std::int64_t h = grid.rows.size();
for (std::int64_t x = 1; x < w-1; x++) {
for (std::int64_t y = 1; y < h-1; y++) {
Coord const c = {x,y};
auto const v = map[c];
auto const v = grid[c];
if (std::isupper(v)) {
char polarity = x==1 || x==w-2 || y==1 || y==h-2
? '-' : '+';
if (map[Up(c)] == '.') {
portals[{polarity, v, map[Down(c)]}] = Up(c);
} else if (map[Down(c)] == '.') {
portals[{polarity, map[Up(c)], v}] = Down(c);
} else if (map[Left(c)] == '.') {
portals[{polarity, v, map[Right(c)]}] = Left(c);
} else if (map[Right(c)] == '.') {
portals[{polarity, map[Left(c)], v}] = Right(c);
if (grid[Up(c)] == '.') {
portals[{polarity, v, grid[Down(c)]}] = Up(c);
} else if (grid[Down(c)] == '.') {
portals[{polarity, grid[Up(c)], v}] = Down(c);
} else if (grid[Left(c)] == '.') {
portals[{polarity, v, grid[Right(c)]}] = Left(c);
} else if (grid[Right(c)] == '.') {
portals[{polarity, grid[Left(c)], v}] = Right(c);
}
}
}
@ -73,7 +58,7 @@ auto FindPortals(Map const& map) -> Portals {
}
auto FindDistancesFrom(
Map const& map,
Grid const& grid,
std::map<Coord, Name> const& names,
std::string const start_name,
Coord const start
@ -90,7 +75,7 @@ auto FindDistancesFrom(
// Don't visit the same coordinate twice
if (!seen.insert(here).second) continue;
auto const c = map[here];
auto const c = grid[here];
if (c != '.') continue; // avoid walls
// success, we've found a key, record the path
@ -113,7 +98,7 @@ auto OtherName(Name name) {
return name;
}
auto FindDistances(Map const& map, Portals const& portals) {
auto FindDistances(Grid const& grid, Portals const& portals) {
Distances distances;
std::map<Coord, Name> names;
@ -122,7 +107,7 @@ auto FindDistances(Map const& map, Portals const& portals) {
}
for (auto const& [start_name, start_coord] : portals) {
distances[start_name] = FindDistancesFrom(map, names, start_name, start_coord);
distances[start_name] = FindDistancesFrom(grid, names, start_name, start_coord);
}
return distances;
@ -165,7 +150,7 @@ auto SolveMaze(Distances const& distances, bool const recursive) -> std::int64_t
} // namespace
auto main(int argc, char** argv) -> int {
auto map = Map::Parse(Startup(argc, argv));
auto map = Grid::Parse(Startup(argc, argv));
auto portals = FindPortals(map);
auto distances = FindDistances(map, portals);

View File

@ -12,39 +12,21 @@
#include <aocpp/Startup.hpp>
#include <aocpp/Coord.hpp>
#include <aocpp/Grid.hpp>
using namespace aocpp;
namespace {
struct Map {
std::vector<std::string> rows;
auto operator[](Coord c) -> char& { return rows[c.y][c.x]; }
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};
}
};
auto FindBugs(Map const& map) -> std::vector<Coord> {
auto FindBugs(Grid const& grid) -> std::vector<Coord> {
std::vector<Coord> result;
std::int64_t w = map.rows[0].size();
std::int64_t h = map.rows.size();
std::int64_t w = grid.rows[0].size();
std::int64_t h = grid.rows.size();
for (std::int64_t x = 0; x < w; x++) {
for (std::int64_t y = 0; y < h; y++) {
Coord const c = {x,y};
if (map[c] == '#') result.push_back(c);
}
}
grid.each([&](Coord c, char v) {
if (v == '#') result.push_back(c);
});
return result;
}
@ -60,9 +42,9 @@ struct Neighbor1 {
struct Neighbor2 {
using C3 = std::pair<Coord, std::int64_t>;
auto operator()(C3 cd, auto f) const -> void {
auto const [c,d] = cd;
auto left_neighbors = [&](auto k_, auto k) {
auto left_neighbors = [cd,f](auto k_, auto k) {
auto const [c,d] = cd;
auto c_ = k_(c);
if (c_.x == 1 && c_.y == 0) {
for (std::int64_t yi = -2; yi <= 2; yi++) {
@ -139,7 +121,7 @@ auto Part2(std::vector<Coord> const& bugs) {
} // namespace
auto main(int argc, char** argv) -> int {
auto const bugs = FindBugs(Map::Parse(Startup(argc, argv)));
auto const bugs = FindBugs(Grid::Parse(Startup(argc, argv)));
std::cout << "Part 1: " << Part1(bugs) << std::endl;
std::cout << "Part 2: " << Part2(std::move(bugs)) << std::endl;
}

View File

@ -25,6 +25,9 @@ target_link_libraries(08 aocpp)
add_executable(09 09.cpp)
target_link_libraries(09 aocpp intcode)
add_executable(10 10.cpp)
target_link_libraries(10 aocpp)
add_executable(11 11.cpp)
target_link_libraries(11 aocpp intcode)