14
This commit is contained in:
parent
a5fe5c007f
commit
62944c8f1c
167
2022/14.cpp
Normal file
167
2022/14.cpp
Normal file
|
@ -0,0 +1,167 @@
|
||||||
|
#include <cstdint>
|
||||||
|
#include <iostream>
|
||||||
|
#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;
|
||||||
|
|
||||||
|
using Input = std::vector<std::vector<aocpp::Coord>>;
|
||||||
|
|
||||||
|
const aocpp::Coord TOP {500, 0};
|
||||||
|
|
||||||
|
// Input file grammar
|
||||||
|
template <typename It>
|
||||||
|
class Grammar : public qi::grammar<It, Input()> {
|
||||||
|
qi::rule<It, aocpp::Coord> coord;
|
||||||
|
qi::rule<It, std::vector<aocpp::Coord>()> line;
|
||||||
|
qi::rule<It, Input()> input;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Grammar() : Grammar::base_type{input} {
|
||||||
|
using namespace qi::labels;
|
||||||
|
|
||||||
|
coord = qi::long_long [ phx::bind(&aocpp::Coord::x, _val) = _1 ] >>
|
||||||
|
"," >>
|
||||||
|
qi::long_long [ phx::bind(&aocpp::Coord::y, _val) = _1 ];
|
||||||
|
line = coord % " -> " >> "\n";
|
||||||
|
input = *line;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ExpandLines(Input const& lines) -> std::set<aocpp::Coord>
|
||||||
|
{
|
||||||
|
auto result = std::set<aocpp::Coord>{};
|
||||||
|
for (auto const& line : lines) {
|
||||||
|
for (auto const i : boost::irange(std::size_t{1}, line.size())) {
|
||||||
|
auto const& a = line[i-1];
|
||||||
|
auto const& b = line[i];
|
||||||
|
|
||||||
|
if (a.x == b.x) {
|
||||||
|
for (auto const y : boost::irange(std::min(a.y, b.y), 1+std::max(a.y, b.y))) {
|
||||||
|
result.insert({a.x, y});
|
||||||
|
}
|
||||||
|
} else if (a.y == b.y) {
|
||||||
|
for (auto const x : boost::irange(std::min(a.x, b.x), 1+std::max(a.x, b.x))) {
|
||||||
|
result.insert({x, a.y});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new std::runtime_error{"Bad line segment"};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto FindBottom(Input const& input) -> std::int64_t
|
||||||
|
{
|
||||||
|
auto result = std::int64_t{TOP.y};
|
||||||
|
for (auto const& line : input) {
|
||||||
|
for (auto const& coord : line) {
|
||||||
|
result = std::max(result, coord.y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Part1(std::int64_t bottom, std::set<aocpp::Coord> world) -> std::size_t
|
||||||
|
{
|
||||||
|
auto path = std::vector<aocpp::Coord>{TOP};
|
||||||
|
auto const starting_size = world.size();
|
||||||
|
|
||||||
|
while (!path.empty()) {
|
||||||
|
auto & here = path.back();
|
||||||
|
if (here.y == bottom) {
|
||||||
|
return world.size() - starting_size;
|
||||||
|
} else if (!world.contains(aocpp::Down(here))) {
|
||||||
|
path.push_back(aocpp::Down(here));
|
||||||
|
} else if (!world.contains(aocpp::Left(aocpp::Down(here)))) {
|
||||||
|
path.push_back(aocpp::Left(aocpp::Down(here)));
|
||||||
|
} else if (!world.contains(aocpp::Right(aocpp::Down(here)))) {
|
||||||
|
path.push_back(aocpp::Right(aocpp::Down(here)));
|
||||||
|
} else {
|
||||||
|
world.insert(here);
|
||||||
|
path.pop_back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return world.size() - starting_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Part2(std::int64_t bottom, std::set<aocpp::Coord> world) -> std::size_t
|
||||||
|
{
|
||||||
|
auto path = std::vector<aocpp::Coord>{TOP};
|
||||||
|
auto const starting_size = world.size();
|
||||||
|
|
||||||
|
while (!path.empty()) {
|
||||||
|
auto & here = path.back();
|
||||||
|
if (here.y == 1 + bottom) {
|
||||||
|
world.insert(here);
|
||||||
|
path.pop_back();
|
||||||
|
} else if (!world.contains(aocpp::Down(here))) {
|
||||||
|
path.push_back(aocpp::Down(here));
|
||||||
|
} else if (!world.contains(aocpp::Left(aocpp::Down(here)))) {
|
||||||
|
path.push_back(aocpp::Left(aocpp::Down(here)));
|
||||||
|
} else if (!world.contains(aocpp::Right(aocpp::Down(here)))) {
|
||||||
|
path.push_back(aocpp::Right(aocpp::Down(here)));
|
||||||
|
} else {
|
||||||
|
world.insert(here);
|
||||||
|
path.pop_back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return world.size() - starting_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
TEST_SUITE("2022-14 examples") {
|
||||||
|
TEST_CASE("documented example") {
|
||||||
|
auto in = std::istringstream{
|
||||||
|
"498,4 -> 498,6 -> 496,6\n"
|
||||||
|
"503,4 -> 502,4 -> 502,9 -> 494,9\n"
|
||||||
|
};
|
||||||
|
auto const input = Parse(in);
|
||||||
|
auto const bottom = FindBottom(input);
|
||||||
|
auto world = ExpandLines(input);
|
||||||
|
CHECK(24 == Part1(bottom, world));
|
||||||
|
CHECK(93 == Part2(bottom, std::move(world)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Main(std::istream & in, std::ostream & out) -> void
|
||||||
|
{
|
||||||
|
auto const input = Parse(in);
|
||||||
|
auto const bottom = FindBottom(input);
|
||||||
|
auto world = ExpandLines(input);
|
||||||
|
out << "Part 1: " << Part1(bottom, world) << std::endl;
|
||||||
|
out << "Part 2: " << Part2(bottom, std::move(world)) << std::endl;
|
||||||
|
}
|
|
@ -31,6 +31,9 @@ target_link_libraries(2022_12 aocpp)
|
||||||
add_executable(2022_13 13.cpp)
|
add_executable(2022_13 13.cpp)
|
||||||
target_link_libraries(2022_13 aocpp Boost::headers)
|
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_16 16.cpp)
|
add_executable(2022_16 16.cpp)
|
||||||
target_link_libraries(2022_16 aocpp Boost::headers)
|
target_link_libraries(2022_16 aocpp Boost::headers)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user