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/Startup.hpp>
|
||||||
#include <aocpp/Coord.hpp>
|
#include <aocpp/Coord.hpp>
|
||||||
|
#include <aocpp/Grid.hpp>
|
||||||
|
|
||||||
using namespace aocpp;
|
using namespace aocpp;
|
||||||
|
|
||||||
|
@ -38,37 +39,18 @@ auto SetKey(Doors& doors, char key) {
|
||||||
return doors.set(std::toupper(key) - 'A');
|
return doors.set(std::toupper(key) - 'A');
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Map {
|
auto FindFeatures(Grid const& grid) -> Features {
|
||||||
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 {
|
|
||||||
Features features;
|
Features features;
|
||||||
for (std::size_t y = 0; y < map.rows.size(); y++) {
|
grid.each([&](Coord c, char v) {
|
||||||
for (std::size_t x = 0; x < map.rows[y].size(); x++) {
|
if ('#' != v && '.' != v) {
|
||||||
auto const c = map[{std::int64_t(x),std::int64_t(y)}];
|
features[v] = c;
|
||||||
if ('#' != c && '.' != c) {
|
|
||||||
features[c] = {std::int64_t(x),std::int64_t(y)};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
return features;
|
return features;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto FindDistancesFrom(
|
auto FindDistancesFrom(
|
||||||
Map const& map,
|
Grid const& grid,
|
||||||
char const start_letter,
|
char const start_letter,
|
||||||
Coord const start
|
Coord const start
|
||||||
) {
|
) {
|
||||||
|
@ -84,7 +66,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];
|
auto const c = grid[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
|
||||||
|
@ -107,11 +89,11 @@ auto FindDistancesFrom(
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto FindDistances(Map const& map, Features const& features) {
|
auto FindDistances(Grid const& grid, Features const& features) {
|
||||||
Distances distances;
|
Distances distances;
|
||||||
for (auto const [start_letter, start_coord] : features) {
|
for (auto const [start_letter, start_coord] : features) {
|
||||||
if (!std::isupper(start_letter)) {
|
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;
|
return distances;
|
||||||
|
@ -163,10 +145,10 @@ auto SolveMaze(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Part 2 instructs us to update the map splitting it into 4 quadrants
|
// 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['@'];
|
auto const start = features['@'];
|
||||||
for (auto const fn : directions) {
|
for (auto const fn : directions) {
|
||||||
map[fn(start)] = '#';
|
grid[fn(start)] = '#';
|
||||||
}
|
}
|
||||||
features.erase('@');
|
features.erase('@');
|
||||||
features['^'] = Up(Left (start));
|
features['^'] = Up(Left (start));
|
||||||
|
@ -178,12 +160,12 @@ auto Part2(Map& map, Features & features) {
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
auto main(int argc, char** argv) -> int {
|
auto main(int argc, char** argv) -> int {
|
||||||
auto map = Map::Parse(Startup(argc, argv));
|
auto grid = Grid::Parse(Startup(argc, argv));
|
||||||
auto features = FindFeatures(map);
|
auto features = FindFeatures(grid);
|
||||||
auto distances = FindDistances(map, features);
|
auto distances = FindDistances(grid, features);
|
||||||
std::cout << "Part 1: " << SolveMaze(distances, "@") << std::endl;
|
std::cout << "Part 1: " << SolveMaze(distances, "@") << std::endl;
|
||||||
|
|
||||||
Part2(map, features);
|
Part2(grid, features);
|
||||||
distances = FindDistances(map, features);
|
distances = FindDistances(grid, features);
|
||||||
std::cout << "Part 2: " << SolveMaze(distances, "^&*$") << std::endl;
|
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/Startup.hpp>
|
||||||
#include <aocpp/Coord.hpp>
|
#include <aocpp/Coord.hpp>
|
||||||
|
#include <aocpp/Grid.hpp>
|
||||||
|
|
||||||
using namespace aocpp;
|
using namespace aocpp;
|
||||||
|
|
||||||
|
@ -28,43 +29,27 @@ using Name = std::string;
|
||||||
using Portals = std::map<std::string, Coord>;
|
using Portals = std::map<std::string, Coord>;
|
||||||
using Distances = std::map<Name,std::vector<std::pair<Name, std::int64_t>>>;
|
using Distances = std::map<Name,std::vector<std::pair<Name, std::int64_t>>>;
|
||||||
|
|
||||||
struct Map {
|
auto FindPortals(Grid const& grid) -> Portals {
|
||||||
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 {
|
|
||||||
Portals portals;
|
Portals portals;
|
||||||
|
|
||||||
std::int64_t w = map.rows[0].size();
|
std::int64_t w = grid.rows[0].size();
|
||||||
std::int64_t h = map.rows.size();
|
std::int64_t h = grid.rows.size();
|
||||||
|
|
||||||
for (std::int64_t x = 1; x < w-1; x++) {
|
for (std::int64_t x = 1; x < w-1; x++) {
|
||||||
for (std::int64_t y = 1; y < h-1; y++) {
|
for (std::int64_t y = 1; y < h-1; y++) {
|
||||||
Coord const c = {x,y};
|
Coord const c = {x,y};
|
||||||
auto const v = map[c];
|
auto const v = grid[c];
|
||||||
if (std::isupper(v)) {
|
if (std::isupper(v)) {
|
||||||
char polarity = x==1 || x==w-2 || y==1 || y==h-2
|
char polarity = x==1 || x==w-2 || y==1 || y==h-2
|
||||||
? '-' : '+';
|
? '-' : '+';
|
||||||
if (map[Up(c)] == '.') {
|
if (grid[Up(c)] == '.') {
|
||||||
portals[{polarity, v, map[Down(c)]}] = Up(c);
|
portals[{polarity, v, grid[Down(c)]}] = Up(c);
|
||||||
} else if (map[Down(c)] == '.') {
|
} else if (grid[Down(c)] == '.') {
|
||||||
portals[{polarity, map[Up(c)], v}] = Down(c);
|
portals[{polarity, grid[Up(c)], v}] = Down(c);
|
||||||
} else if (map[Left(c)] == '.') {
|
} else if (grid[Left(c)] == '.') {
|
||||||
portals[{polarity, v, map[Right(c)]}] = Left(c);
|
portals[{polarity, v, grid[Right(c)]}] = Left(c);
|
||||||
} else if (map[Right(c)] == '.') {
|
} else if (grid[Right(c)] == '.') {
|
||||||
portals[{polarity, map[Left(c)], v}] = Right(c);
|
portals[{polarity, grid[Left(c)], v}] = Right(c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -73,7 +58,7 @@ auto FindPortals(Map const& map) -> Portals {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto FindDistancesFrom(
|
auto FindDistancesFrom(
|
||||||
Map const& map,
|
Grid const& grid,
|
||||||
std::map<Coord, Name> const& names,
|
std::map<Coord, Name> const& names,
|
||||||
std::string const start_name,
|
std::string const start_name,
|
||||||
Coord const start
|
Coord const start
|
||||||
|
@ -90,7 +75,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];
|
auto const c = grid[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
|
||||||
|
@ -113,7 +98,7 @@ auto OtherName(Name name) {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto FindDistances(Map const& map, Portals const& portals) {
|
auto FindDistances(Grid const& grid, Portals const& portals) {
|
||||||
Distances distances;
|
Distances distances;
|
||||||
|
|
||||||
std::map<Coord, Name> names;
|
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) {
|
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;
|
return distances;
|
||||||
|
@ -165,7 +150,7 @@ auto SolveMaze(Distances const& distances, bool const recursive) -> std::int64_t
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
auto main(int argc, char** argv) -> int {
|
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 portals = FindPortals(map);
|
||||||
auto distances = FindDistances(map, portals);
|
auto distances = FindDistances(map, portals);
|
||||||
|
|
||||||
|
|
38
2019/24.cpp
38
2019/24.cpp
|
@ -12,39 +12,21 @@
|
||||||
|
|
||||||
#include <aocpp/Startup.hpp>
|
#include <aocpp/Startup.hpp>
|
||||||
#include <aocpp/Coord.hpp>
|
#include <aocpp/Coord.hpp>
|
||||||
|
#include <aocpp/Grid.hpp>
|
||||||
|
|
||||||
using namespace aocpp;
|
using namespace aocpp;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
struct Map {
|
auto FindBugs(Grid const& grid) -> std::vector<Coord> {
|
||||||
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> {
|
|
||||||
std::vector<Coord> result;
|
std::vector<Coord> result;
|
||||||
|
|
||||||
std::int64_t w = map.rows[0].size();
|
std::int64_t w = grid.rows[0].size();
|
||||||
std::int64_t h = map.rows.size();
|
std::int64_t h = grid.rows.size();
|
||||||
|
|
||||||
for (std::int64_t x = 0; x < w; x++) {
|
grid.each([&](Coord c, char v) {
|
||||||
for (std::int64_t y = 0; y < h; y++) {
|
if (v == '#') result.push_back(c);
|
||||||
Coord const c = {x,y};
|
});
|
||||||
if (map[c] == '#') result.push_back(c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,9 +42,9 @@ struct Neighbor1 {
|
||||||
struct Neighbor2 {
|
struct Neighbor2 {
|
||||||
using C3 = std::pair<Coord, std::int64_t>;
|
using C3 = std::pair<Coord, std::int64_t>;
|
||||||
auto operator()(C3 cd, auto f) const -> void {
|
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);
|
auto c_ = k_(c);
|
||||||
if (c_.x == 1 && c_.y == 0) {
|
if (c_.x == 1 && c_.y == 0) {
|
||||||
for (std::int64_t yi = -2; yi <= 2; yi++) {
|
for (std::int64_t yi = -2; yi <= 2; yi++) {
|
||||||
|
@ -139,7 +121,7 @@ auto Part2(std::vector<Coord> const& bugs) {
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
auto main(int argc, char** argv) -> int {
|
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 1: " << Part1(bugs) << std::endl;
|
||||||
std::cout << "Part 2: " << Part2(std::move(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)
|
add_executable(09 09.cpp)
|
||||||
target_link_libraries(09 aocpp intcode)
|
target_link_libraries(09 aocpp intcode)
|
||||||
|
|
||||||
|
add_executable(10 10.cpp)
|
||||||
|
target_link_libraries(10 aocpp)
|
||||||
|
|
||||||
add_executable(11 11.cpp)
|
add_executable(11 11.cpp)
|
||||||
target_link_libraries(11 aocpp intcode)
|
target_link_libraries(11 aocpp intcode)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user