#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); }