aocpp/2020/18.cpp

100 lines
2.6 KiB
C++
Raw Normal View History

2022-11-20 19:44:38 -08:00
#include <algorithm>
#include <cctype>
#include <cstdint>
#include <cstdlib>
#include <functional>
#include <iostream>
#include <map>
#include <tuple>
#include <vector>
#include <doctest.h>
#include <aocpp/Startup.hpp>
namespace {
auto Eval(
std::string const& input,
std::map<char, std::pair<int, std::function<std::int64_t(std::int64_t,std::int64_t)>>> cfg
) -> std::int64_t
{
std::vector<char> ops;
std::vector<std::int64_t> vals;
auto const eval1 = [&](){
char o = ops.back(); ops.pop_back();
std::int64_t y = vals.back(); vals.pop_back();
std::int64_t x = vals.back(); vals.pop_back();
vals.push_back(cfg[o].second(x,y));
};
for (auto it = input.begin(); it != input.end(); it++) {
char const c = *it;
if (c == ' ') continue;
if (std::isdigit(c)) {
vals.push_back(c - '0');
} else if ('(' == c) {
ops.push_back('(');
} else if (')' == c) {
while (ops.back() != '(') eval1();
ops.pop_back();
} else if (auto opit = cfg.find(c); opit != cfg.end()) {
while (!ops.empty() && cfg[ops.back()].first >= opit->second.first) eval1();
ops.push_back(c);
}
}
while (!ops.empty()) eval1();
return vals.back();
}
auto Part1(std::string const& line) {
return Eval(line, {{'+', {1, std::plus<std::int64_t>()}},{'*', {1, std::multiplies<std::int64_t>()}}});
}
auto Part2(std::string const& line) {
return Eval(line, {{'+', {2, std::plus<std::int64_t>()}},{'*', {1, std::multiplies<std::int64_t>()}}});
}
} // namespace
TEST_SUITE("documented examples") {
TEST_CASE("part 1") {
REQUIRE(Part1("1 + 2 * 3 + 4 * 5 + 6") == 71);
REQUIRE(Part1("1 + (2 * 3) + (4 * (5 + 6))") == 51);
REQUIRE(Part1("2 * 3 + (4 * 5)") == 26);
REQUIRE(Part1("5 + (8 * 3 + 9 + 3 * 4 * 3)") == 437);
REQUIRE(Part1("5 * 9 * (7 * 3 * 3 + 9 * 3 + (8 + 6 * 4))") == 12240);
REQUIRE(Part1("((2 + 4 * 9) * (6 + 9 * 8 + 6) + 6) + 2 + 4 * 2") == 13632);
}
TEST_CASE("part 2") {
REQUIRE(Part2("1 + 2 * 3 + 4 * 5 + 6") == 231);
REQUIRE(Part2("1 + (2 * 3) + (4 * (5 + 6))") == 51);
REQUIRE(Part2("2 * 3 + (4 * 5)") == 46);
REQUIRE(Part2("5 + (8 * 3 + 9 + 3 * 4 * 3)") == 1445);
REQUIRE(Part2("5 * 9 * (7 * 3 * 3 + 9 * 3 + (8 + 6 * 4))") == 669060);
REQUIRE(Part2("((2 + 4 * 9) * (6 + 9 * 8 + 6) + 6) + 2 + 4 * 2") == 23340);
}
}
auto main(int argc, char** argv) -> int {
auto & in = aocpp::Startup(argc, argv);
std::int64_t part1 = 0;
std::int64_t part2 = 0;
std::string line;
while (std::getline(in, line)) {
part1 += Part1(line);
part2 += Part2(line);
}
std::cout << "Part 1: " << part1 << std::endl;
std::cout << "Part 2: " << part2 << std::endl;
}