diff --git a/2022/15.cpp b/2022/15.cpp new file mode 100644 index 0000000..d2595de --- /dev/null +++ b/2022/15.cpp @@ -0,0 +1,181 @@ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include + +namespace { + +namespace phx = boost::phoenix; +namespace qi = boost::spirit::qi; + +struct Entry { + aocpp::Coord sensor; + aocpp::Coord beacon; +}; + +using Input = std::vector; + +// Input file grammar +template +class Grammar : public qi::grammar { + qi::rule coord; + qi::rule entry; + qi::rule input; + +public: + Grammar() : Grammar::base_type{input} { + using namespace qi::labels; + + coord = "x=" >> + qi::long_long [ phx::bind(&aocpp::Coord::x, _val) = _1 ] >> + ", y=" >> + qi::long_long [ phx::bind(&aocpp::Coord::y, _val) = _1 ]; + entry = "Sensor at " >> + coord [ phx::bind(&Entry::sensor, _val) = _1 ] >> + ": closest beacon is at " >> + coord [ phx::bind(&Entry::beacon, _val) = _1 ] >> + "\n"; + input = *entry; + } +}; + +/// Parse the complete input stream according to the rules defined in 'Grammar'. +/// Throws: std::runtime_error on failed parse +auto Parse(std::istream & in) -> Input +{ + auto result = Input{}; + auto const content = std::string{std::istreambuf_iterator{in}, {}}; + auto b = content.begin(); // updated on successful parse + auto const e = content.end(); + + if (!qi::parse(b, e, Grammar{}, result) || b != e) { + throw std::runtime_error{"Bad input file: " + content}; + } + + return result; +} + +struct Range { + std::int64_t lo, hi; + auto operator<=>(Range const& rhs) const = default; +}; + +template +auto subtract( + std::array x, + std::array y, + std::vector> & out +) -> void +{ + for (std::size_t i = 0; i < N; ++i) { + if (x[i].lo < y[i].lo) { + auto z = x; + z[i].hi = std::min(z[i].hi, y[i].lo); + out.push_back(z); + } + if (x[i].hi > y[i].hi) { + auto z = x; + z[i].lo = std::max(z[i].lo, y[i].hi); + out.push_back(z); + } + x[i].lo = std::max(x[i].lo, y[i].lo); + x[i].hi = std::min(x[i].hi, y[i].hi); + if (x[i].lo >= x[i].hi) { + return; + } + } +} + +auto Segment(std::int64_t center, std::int64_t radius) -> Range { + return { center - radius, center + radius + 1}; +} + +auto Square(aocpp::Coord center, std::int64_t radius) -> std::array { + return { Segment(center.x + center.y, radius), Segment(center.x - center.y, radius)}; +} + +auto Corner(std::array const& s) -> aocpp::Coord +{ + return { (s[0].lo + s[1].lo) / 2, (s[0].lo - s[1].lo) / 2}; +} + +auto Part2(Input const& input) -> void { + + auto region = std::vector>{Square({2'000'000, 2'000'000}, 2'000'000)}; + auto region_next = std::vector>{}; + + for (auto const& entry : input) { + auto radius = aocpp::Norm1(entry.beacon - entry.sensor); + auto s = Square(entry.sensor, radius); + for (auto const& x : region) { + subtract(x, s, region_next); + } + std::swap(region, region_next); + region_next.clear(); + } + + for (auto const& entry : region) { + auto corner = Corner(entry); + //if (0 <= corner.x && corner.x <= 4000000 && + // 0 <= corner.y && corner.y <= 4000000) + //{ + std::cout << corner << " " << 4'000'000 * corner.x + corner.y << std::endl; + //} + } +} + +} // namespace + +TEST_SUITE("2022-15 examples") { + /* + TEST_CASE("1D subtraction") { + CHECK(subtract<1>({1,3}, {4,5}) == std::vector>{{1,3}}); + CHECK(subtract<1>({4,5}, {1,3}) == std::vector>{{4,5}}); + CHECK(subtract<1>({1,3}, {2,4}) == std::vector>{{1,2}}); + CHECK(subtract<1>({1,3}, {0,2}) == std::vector>{{2,3}}); + CHECK(subtract<1>({1,3}, {1,3}) == std::vector>{}); + CHECK(subtract<1>({1,4}, {2,3}) == std::vector>{{1,2}, {3,4}}); + CHECK(subtract<1>({1,4}, {2,4}) == std::vector>{{1,2}}); + CHECK(subtract<1>({1,4}, {1,3}) == std::vector>{{3,4}}); + } + */ + + TEST_CASE("documented example") { + auto in = std::istringstream{ + "Sensor at x=2, y=18: closest beacon is at x=-2, y=15\n" + "Sensor at x=9, y=16: closest beacon is at x=10, y=16\n" + "Sensor at x=13, y=2: closest beacon is at x=15, y=3\n" + "Sensor at x=12, y=14: closest beacon is at x=10, y=16\n" + "Sensor at x=10, y=20: closest beacon is at x=10, y=16\n" + "Sensor at x=14, y=17: closest beacon is at x=10, y=16\n" + "Sensor at x=8, y=7: closest beacon is at x=2, y=10\n" + "Sensor at x=2, y=0: closest beacon is at x=2, y=10\n" + "Sensor at x=0, y=11: closest beacon is at x=2, y=10\n" + "Sensor at x=20, y=14: closest beacon is at x=25, y=17\n" + "Sensor at x=17, y=20: closest beacon is at x=21, y=22\n" + "Sensor at x=16, y=7: closest beacon is at x=15, y=3\n" + "Sensor at x=14, y=3: closest beacon is at x=15, y=3\n" + "Sensor at x=20, y=1: closest beacon is at x=15, y=3\n" + }; + auto const input = Parse(in); + } +} + +auto Main(std::istream & in, std::ostream & out) -> void +{ + auto const input = Parse(in); + //out << "Part 1: " << Part1(bottom, world) << std::endl; + Part2(input); +} diff --git a/2022/CMakeLists.txt b/2022/CMakeLists.txt index 68c2069..e14c5ab 100644 --- a/2022/CMakeLists.txt +++ b/2022/CMakeLists.txt @@ -34,6 +34,9 @@ target_link_libraries(2022_13 aocpp Boost::headers) add_executable(2022_14 14.cpp) target_link_libraries(2022_14 aocpp Boost::headers) +add_executable(2022_15 15.cpp) +target_link_libraries(2022_15 aocpp Boost::headers) + add_executable(2022_16 16.cpp) target_link_libraries(2022_16 aocpp Boost::headers) diff --git a/lib/include/aocpp/Generator.hpp b/lib/include/aocpp/Generator.hpp index 3348708..ed530c1 100644 --- a/lib/include/aocpp/Generator.hpp +++ b/lib/include/aocpp/Generator.hpp @@ -58,7 +58,7 @@ public: ~Generator() { if (h_) h_.destroy(); } std::optional operator()() { - h_(); + h_.resume(); if (h_.promise().exception_) { std::rethrow_exception(h_.promise().exception_); }