aocpp/2023/02.cpp

119 lines
3.2 KiB
C++
Raw Permalink Normal View History

2023-12-02 20:15:21 -08:00
#include <algorithm>
#include <cstdint>
#include <iostream>
#include <sstream>
#include <string>
#include <tuple>
#include <unordered_map>
#include <vector>
#include <boost/fusion/adapted/std_tuple.hpp>
#include <boost/phoenix.hpp>
#include <boost/spirit/include/qi.hpp>
#include <doctest.h>
#include <aocpp/Parsing.hpp>
#include <aocpp/Startup.hpp>
namespace {
namespace qi = boost::spirit::qi;
namespace phx = boost::phoenix;
namespace ascii = boost::spirit::ascii;
struct Game
{
unsigned long long game_id;
std::vector<std::vector<std::tuple<unsigned long long, std::string>>> rounds;
};
struct Grammar : public qi::grammar<std::string::const_iterator, std::vector<Game>(), ascii::space_type> {
qi::rule<iterator_type, Game(), ascii::space_type> game;
qi::rule<iterator_type, std::vector<Game>(), ascii::space_type> games;
qi::rule<iterator_type, std::tuple<unsigned long long, std::string>(), ascii::space_type> entry;
Grammar() : base_type{games} {
using namespace qi::labels;
games = *game;
game =
"Game" >> qi::ulong_long [ phx::bind(&Game::game_id, _val) = _1] >> ":" >>
(entry % "," % ";") [ phx::bind(&Game::rounds, _val) = _1];
entry = qi::ulong_long >> qi::lexeme [ qi::as_string[+qi::alpha] ];
}
};
auto Part1(std::vector<Game> const& input) -> unsigned long long
{
static auto const limits = std::unordered_map<std::string, unsigned long long>{
{"red", 12},
{"green", 13},
{"blue", 14},
};
unsigned long long result = 0;
for (auto const& game : input)
{
auto const good = std::all_of(game.rounds.begin(), game.rounds.end(), [](auto const& round)
{
return std::all_of(round.begin(), round.end(), [](auto const& entry)
{
auto const limit = limits.find(std::get<1>(entry));
return limit != limits.end() && limit->second >= std::get<0>(entry);
});
});
if (good)
{
result += game.game_id;
}
}
return result;
}
auto Part2(std::vector<Game> const& input) -> unsigned long long
{
unsigned long long result = 0;
for (auto const& game : input)
{
std::unordered_map<std::string, unsigned long long> maxes;
for (auto const& round : game.rounds) {
for (auto const& [count, color] : round)
{
auto& entry = maxes[color];
entry = std::max(entry, count);
}
}
result += std::transform_reduce(
maxes.begin(), maxes.end(),
1ULL, std::multiplies{}, [](auto& kv) { return kv.second; });
}
return result;
}
} // namespace
TEST_SUITE("2023-02 examples") {
TEST_CASE("example") {
std::istringstream in {
R"(Game 1: 3 blue, 4 red; 1 red, 2 green, 6 blue; 2 green
Game 2: 1 blue, 2 green; 3 green, 4 blue, 1 red; 1 green, 1 blue
Game 3: 8 green, 6 blue, 20 red; 5 blue, 4 red, 13 green; 5 green, 1 red
Game 4: 1 green, 3 red, 6 blue; 3 green, 6 red; 3 green, 15 blue, 14 red
Game 5: 6 red, 1 blue, 3 green; 2 blue, 1 red, 2 green
)"
};
auto const input = aocpp::ParseGrammar_(Grammar{}, in);
CHECK(Part1(input) == 8);
CHECK(Part2(input) == 2'286);
}
}
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;
}