diff options
Diffstat (limited to '2023/19/src/part1.cpp')
-rw-r--r-- | 2023/19/src/part1.cpp | 125 |
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 | |||
10 | using Name = std::string; | ||
11 | using Part = std::array<int,4>; | ||
12 | using Cond = std::function<bool(const Part&)>; | ||
13 | using Rule = std::pair<Cond,Name>; | ||
14 | using Workflow = std::vector<Rule>; | ||
15 | using Workflows = std::unordered_map<Name,Workflow>; | ||
16 | |||
17 | const std::unordered_map<char,int> fields{ {'x', 0}, {'m', 1}, {'a', 2}, {'s', 3} }; | ||
18 | |||
19 | std::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 | |||
86 | Name 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 | |||
96 | int value(const Part& p) | ||
97 | { | ||
98 | return p[0] + p[1] + p[2] + p[3]; | ||
99 | } | ||
100 | |||
101 | int 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 | |||
112 | int 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 | } | ||