From 4c268eae6066846d17823d838370b4344d60dbe9 Mon Sep 17 00:00:00 2001 From: Bert Peters Date: Tue, 10 Dec 2019 18:44:39 +0100 Subject: [PATCH] Implement day 10 part 2. --- 2019/src/day10.cpp | 89 ++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 74 insertions(+), 15 deletions(-) diff --git a/2019/src/day10.cpp b/2019/src/day10.cpp index 1b76f1e..33bf1d0 100644 --- a/2019/src/day10.cpp +++ b/2019/src/day10.cpp @@ -1,13 +1,15 @@ +#include #include #include #include +#include #include "days.hpp" #include "point.hpp" namespace { typedef aoc2019::Point point_t; - std::vector read_points(std::istream& input) { + std::vector read_points(std::istream &input) { std::vector result; int y = 0; @@ -27,31 +29,88 @@ namespace { point_t simplify(point_t x) { auto gcd = std::abs(std::gcd(x[0], x[1])); if (gcd > 1) { - return { x[0] / gcd, x[1] / gcd }; + return {x[0] / gcd, x[1] / gcd}; } return x; } + + std::pair part1(const std::vector &points) { + std::size_t best = 0; + std::size_t best_index = 0; + + for (std::size_t i = 0; i < points.size(); ++i) { + std::unordered_set visible; + const auto point = points[i]; + + for (auto asteroid : points) { + if (asteroid == point) continue; + visible.insert(simplify(asteroid - point)); + } + + if (visible.size() > best) { + best = visible.size(); + best_index = i; + } + + best = std::max(visible.size(), best); + } + + return {best, best_index}; + } } void aoc2019::day10_part1(std::istream &input, std::ostream &output) { const auto points = read_points(input); - std::size_t best = 0; - for (auto point : points) { - std::unordered_set visible; + auto[best, _] = part1(points); - for (auto asteroid : points) { - if (asteroid == point) continue; - visible.insert(simplify(asteroid - point)); - } - - best = std::max(visible.size(), best); - } - - output << best << std::endl; + output << best << std::endl; } void aoc2019::day10_part2(std::istream &input, std::ostream &output) { - output << "Not implemented\n"; + const auto points = read_points(input); + const auto[_, base] = part1(points); + const auto base_point = points[base]; + + std::unordered_map> angle_points; + + for (auto point : points) { + if (point == base_point) continue; + auto diff = point - base_point; + + angle_points[simplify(diff)].push_back(diff); + } + + std::vector> angles; + + for (auto &entry : angle_points) { + angles.emplace_back(std::atan2(entry.first[1], entry.first[0]), entry.first); + // Sort entries in descending order of distance so we can pop_back() them + std::sort(entry.second.begin(), entry.second.end(), [](auto a, auto b) { return a.l1() > b.l1(); }); + } + + std::sort(angles.begin(), angles.end(), std::greater<>{}); + + const auto starting_point = std::make_pair(float(0.5 * M_PI), + point_t{std::numeric_limits::max(), + std::numeric_limits::max()}); + + auto it = std::lower_bound(angles.begin(), angles.end(), starting_point, std::greater<>{}); + + for (int hits = 0; hits < 199; ++hits) { + angle_points[it->second].pop_back(); + + // Advance it to the next asteroid we can hit. + while (angle_points[it->second].empty()) { + ++it; + if (it == angles.end()) { + it = angles.begin(); + } + } + } + + auto final_asteroid = angle_points[it->second].back() + base_point; + + output << final_asteroid[0] * 100 + final_asteroid[1] << std::endl; }