#include #include #include #include #include #include #include "util.h" using Name = std::string; using Part = std::array; using Cond = std::function; using Rule = std::pair; using Workflow = std::vector; using Workflows = std::unordered_map; const std::unordered_map fields{ {'x', 0}, {'m', 1}, {'a', 2}, {'s', 3} }; std::pair,Workflows> parse(const char* file) { using namespace util::separators; Workflows wfs; std::vector parts; if (std::ifstream input{ file }; input.is_open()) { std::string line; std::getline(input,line); while (not line.empty()) { auto bw = line.find('{'); Name name = line.substr(0, bw); std::vector rules; line = line.substr(bw + 1, line.size() - bw - 2); for (auto srule : util::split(std::string_view{ line })) { auto tokens = util::split(srule); if (tokens.size() > 1) { int f = fields.at(tokens[0][0]); int v = std::stoi(std::string(tokens[0].substr(2))); switch (tokens[0][1]) { case '<': rules.push_back({ [f,v](const Part& p) { return p[f] < v; }, Name{ tokens[1] } }); break; default: rules.push_back({ [f,v](const Part& p) { return p[f] > v; }, Name{ tokens[1] } }); }; } else { rules.push_back({ [](const Part& p) { return true; }, Name{ tokens[0] } }); } } wfs.insert({ name, std::move(rules) }); std::getline(input,line); } while (not std::getline(input,line).eof()) { Part part; int i{}; util::accumulate(std::string_view{ line }.substr(1, line.size() - 2), [&part,&i](std::string_view& v) { part[i++] = std::stoi(std::string{ v.substr(2) }); } ); parts.push_back(std::move(part)); } } return { std::move(parts), std::move(wfs) }; } Name apply_workflow(const Workflow& wf, const Part& p) { for (const auto& rule : wf) { auto [cond, name] = rule; if (cond(p)) return name; } return "R"; } int value(const Part& p) { return p[0] + p[1] + p[2] + p[3]; } int process(const Part& p, const Workflows& wfs) { Name wname = "in"; while (wname != "A") { if (wname == "R") return 0; wname = apply_workflow(wfs.at(wname), p); } return value(p); } int main(int argc, char* argv[]) { int answer{}; auto [parts, workflows] = parse(argv[1]); for (const auto& part : parts) { answer += process(part, workflows); } std::cout << answer << std::endl; return 0; }