15 wip
This commit is contained in:
parent
9b4c881903
commit
f18d9043a9
181
2022/15.cpp
Normal file
181
2022/15.cpp
Normal file
@ -0,0 +1,181 @@
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include <cmath>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/phoenix.hpp>
|
||||
#include <boost/range/irange.hpp>
|
||||
#include <boost/spirit/include/qi.hpp>
|
||||
|
||||
#include <doctest.h>
|
||||
|
||||
#include <aocpp/Startup.hpp>
|
||||
#include <aocpp/Coord.hpp>
|
||||
|
||||
namespace {
|
||||
|
||||
namespace phx = boost::phoenix;
|
||||
namespace qi = boost::spirit::qi;
|
||||
|
||||
struct Entry {
|
||||
aocpp::Coord sensor;
|
||||
aocpp::Coord beacon;
|
||||
};
|
||||
|
||||
using Input = std::vector<Entry>;
|
||||
|
||||
// Input file grammar
|
||||
template <typename It>
|
||||
class Grammar : public qi::grammar<It, Input()> {
|
||||
qi::rule<It, aocpp::Coord> coord;
|
||||
qi::rule<It, Entry()> entry;
|
||||
qi::rule<It, Input()> 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<decltype(b)>{}, 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 <std::size_t N>
|
||||
auto subtract(
|
||||
std::array<Range, N> x,
|
||||
std::array<Range, N> y,
|
||||
std::vector<std::array<Range, N>> & 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<Range, 2> {
|
||||
return { Segment(center.x + center.y, radius), Segment(center.x - center.y, radius)};
|
||||
}
|
||||
|
||||
auto Corner(std::array<Range, 2> 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<std::array<Range, 2>>{Square({2'000'000, 2'000'000}, 2'000'000)};
|
||||
auto region_next = std::vector<std::array<Range, 2>>{};
|
||||
|
||||
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<std::array<Range, 1>>{{1,3}});
|
||||
CHECK(subtract<1>({4,5}, {1,3}) == std::vector<std::array<Range, 1>>{{4,5}});
|
||||
CHECK(subtract<1>({1,3}, {2,4}) == std::vector<std::array<Range, 1>>{{1,2}});
|
||||
CHECK(subtract<1>({1,3}, {0,2}) == std::vector<std::array<Range, 1>>{{2,3}});
|
||||
CHECK(subtract<1>({1,3}, {1,3}) == std::vector<std::array<Range, 1>>{});
|
||||
CHECK(subtract<1>({1,4}, {2,3}) == std::vector<std::array<Range, 1>>{{1,2}, {3,4}});
|
||||
CHECK(subtract<1>({1,4}, {2,4}) == std::vector<std::array<Range, 1>>{{1,2}});
|
||||
CHECK(subtract<1>({1,4}, {1,3}) == std::vector<std::array<Range, 1>>{{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);
|
||||
}
|
@ -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)
|
||||
|
||||
|
@ -58,7 +58,7 @@ public:
|
||||
~Generator() { if (h_) h_.destroy(); }
|
||||
std::optional<T> operator()()
|
||||
{
|
||||
h_();
|
||||
h_.resume();
|
||||
if (h_.promise().exception_) {
|
||||
std::rethrow_exception(h_.promise().exception_);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user