summaryrefslogtreecommitdiff
path: root/2023/19/src/part1.cpp
diff options
context:
space:
mode:
Diffstat (limited to '2023/19/src/part1.cpp')
-rw-r--r--2023/19/src/part1.cpp125
1 files changed, 125 insertions, 0 deletions
diff --git a/2023/19/src/part1.cpp b/2023/19/src/part1.cpp
new file mode 100644
index 0000000..b63f05d
--- /dev/null
+++ b/2023/19/src/part1.cpp
@@ -0,0 +1,125 @@
1#include <iostream>
2#include <fstream>
3#include <array>
4#include <vector>
5#include <unordered_map>
6#include <functional>
7
8#include "util.h"
9
10using Name = std::string;
11using Part = std::array<int,4>;
12using Cond = std::function<bool(const Part&)>;
13using Rule = std::pair<Cond,Name>;
14using Workflow = std::vector<Rule>;
15using Workflows = std::unordered_map<Name,Workflow>;
16
17const std::unordered_map<char,int> fields{ {'x', 0}, {'m', 1}, {'a', 2}, {'s', 3} };
18
19std::pair<std::vector<Part>,Workflows> parse(const char* file)
20{
21 using namespace util::separators;
22
23 Workflows wfs;
24 std::vector<Part> parts;
25
26 if (std::ifstream input{ file }; input.is_open())
27 {
28 std::string line;
29 std::getline(input,line);
30 while (not line.empty())
31 {
32 auto bw = line.find('{');
33 Name name = line.substr(0, bw);
34
35 std::vector<Rule> rules;
36 line = line.substr(bw + 1, line.size() - bw - 2);
37 for (auto srule : util::split<COMMA>(std::string_view{ line }))
38 {
39 auto tokens = util::split<COLON>(srule);
40 if (tokens.size() > 1)
41 {
42 int f = fields.at(tokens[0][0]);
43 int v = std::stoi(std::string(tokens[0].substr(2)));
44 switch (tokens[0][1])
45 {
46 case '<':
47 rules.push_back({
48 [f,v](const Part& p) { return p[f] < v; },
49 Name{ tokens[1] }
50 });
51 break;
52 default:
53 rules.push_back({
54 [f,v](const Part& p) { return p[f] > v; },
55 Name{ tokens[1] }
56 });
57 };
58 }
59 else
60 {
61 rules.push_back({
62 [](const Part& p) { return true; },
63 Name{ tokens[0] }
64 });
65 }
66 }
67 wfs.insert({ name, std::move(rules) });
68 std::getline(input,line);
69 }
70
71 while (not std::getline(input,line).eof())
72 {
73 Part part; int i{};
74 util::accumulate<COMMA>(std::string_view{ line }.substr(1, line.size() - 2),
75 [&part,&i](std::string_view& v)
76 {
77 part[i++] = std::stoi(std::string{ v.substr(2) });
78 }
79 );
80 parts.push_back(std::move(part));
81 }
82 }
83 return { std::move(parts), std::move(wfs) };
84}
85
86Name apply_workflow(const Workflow& wf, const Part& p)
87{
88 for (const auto& rule : wf)
89 {
90 auto [cond, name] = rule;
91 if (cond(p)) return name;
92 }
93 return "R";
94}
95
96int value(const Part& p)
97{
98 return p[0] + p[1] + p[2] + p[3];
99}
100
101int process(const Part& p, const Workflows& wfs)
102{
103 Name wname = "in";
104 while (wname != "A")
105 {
106 if (wname == "R") return 0;
107 wname = apply_workflow(wfs.at(wname), p);
108 }
109 return value(p);
110}
111
112int main(int argc, char* argv[])
113{
114 int answer{};
115
116 auto [parts, workflows] = parse(argv[1]);
117
118 for (const auto& part : parts)
119 {
120 answer += process(part, workflows);
121 }
122
123 std::cout << answer << std::endl;
124 return 0;
125}