#include #include #include #include #include #include #include #include #include #include #include #include #include namespace { namespace phx = boost::phoenix; namespace qi = boost::spirit::qi; enum class Dir { L, R }; struct Command { Dir dir; std::size_t n; }; using Input = std::vector; // Input file grammar class Grammar : public qi::grammar { qi::rule dir; qi::rule command; qi::rule commands; public: Grammar() : Grammar::base_type{commands} { using namespace qi::labels; dir = qi::string("L") [ _val = Dir::L ] | qi::string("R") [ _val = Dir::R ]; command = qi::lexeme[ dir [ phx::bind(&Command::dir, _val) = _1] >> qi::ulong_long [ phx::bind(&Command::n, _val) = _1] ]; commands = command % ","; } }; auto Part1(Input const& input) -> std::int64_t { auto here = aocpp::Coord{}; auto face = aocpp::Coord{0,1}; for (auto const& command : input) { switch (command.dir) { case Dir::R: face = aocpp::CW(face); break; case Dir::L: face = aocpp::CCW(face); break; } here += command.n * face; } return aocpp::Norm1(here); } auto Part2(Input const& input) -> std::int64_t { auto seen = std::unordered_set{aocpp::Coord{0,0}}; auto here = aocpp::Coord{0,0}; auto face = aocpp::Coord{0,1}; for (auto const& command : input) { switch (command.dir) { case Dir::R: face = aocpp::CW(face); break; case Dir::L: face = aocpp::CCW(face); break; } for (auto const _ : boost::irange(command.n)) { here += face; if (!seen.insert(here).second) { return aocpp::Norm1(here); } } } throw std::runtime_error{"no solution to part 2"}; } } // namespace TEST_SUITE("2016-01 examples") { TEST_CASE("example 1") { auto in = std::istringstream{"R2, L3"}; auto const commands = aocpp::ParseGrammar_(Grammar{}, in); CHECK(5 == Part1(commands)); } TEST_CASE("example 2") { auto in = std::istringstream{"R2, R2, R2"}; auto const commands = aocpp::ParseGrammar_(Grammar{}, in); CHECK(2 == Part1(commands)); } TEST_CASE("example 3") { auto in = std::istringstream{"R5, L5, R5, R3"}; auto const commands = aocpp::ParseGrammar_(Grammar{}, in); CHECK(12 == Part1(commands)); } TEST_CASE("example 4") { auto in = std::istringstream{"R8, R4, R4, R8"}; auto const commands = aocpp::ParseGrammar_(Grammar{}, in); CHECK(4 == Part2(commands)); } } auto Main(std::istream & in, std::ostream & out) -> void { auto const input = aocpp::ParseGrammar_(Grammar{}, in); out << "Part 1: " << Part1(input) << std::endl; out << "Part 2: " << Part2(input) << std::endl; }