10
This commit is contained in:
parent
29146ec1ee
commit
e96354c4ec
124
2019/10.cpp
Normal file
124
2019/10.cpp
Normal 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;
|
||||
}
|
52
2019/18.cpp
52
2019/18.cpp
|
@ -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;
|
||||
}
|
||||
|
|
51
2019/20.cpp
51
2019/20.cpp
|
@ -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);
|
||||
|
||||
|
|
38
2019/24.cpp
38
2019/24.cpp
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user