aboutsummaryrefslogtreecommitdiff
path: root/2017/src/day07.cpp
diff options
context:
space:
mode:
Diffstat (limited to '2017/src/day07.cpp')
-rw-r--r--2017/src/day07.cpp145
1 files changed, 145 insertions, 0 deletions
diff --git a/2017/src/day07.cpp b/2017/src/day07.cpp
new file mode 100644
index 0000000..899375d
--- /dev/null
+++ b/2017/src/day07.cpp
@@ -0,0 +1,145 @@
1#include <filesystem>
2#include <fstream>
3#include <iostream>
4#include <map>
5#include <numeric>
6#include <vector>
7
8using namespace std;
9
10namespace {
11
12struct Node {
13 int weight;
14 optional<string> parent;
15 vector<string> children;
16};
17
18vector<string>
19split(const string& line, const string& delimiters)
20{
21 vector<string> result;
22
23 size_t start = 0;
24 size_t end = 0;
25
26 while ( (end = line.find_first_of(delimiters, start)) != string::npos ) {
27 if ( end != start ) {
28 result.emplace_back(line.substr(start, end - start));
29 }
30
31 start = end + 1;
32 }
33
34 if ( start != line.size() ) {
35 result.emplace_back(line.substr(start));
36 }
37
38 return result;
39}
40
41map<string, Node>
42read_file(const filesystem::path& filename)
43{
44 ifstream file{ filename };
45
46 map<string, Node> data; // name -> (weight, parent)
47
48 for ( string line; getline(file, line); ) {
49 const auto parts = split(line, " ()->,");
50 const auto& parent = parts.at(0);
51
52 data[parent].weight = stoi(parts.at(1));
53
54 for ( size_t idx = 2; idx != parts.size(); ++idx ) {
55 const auto& child = parts.at(idx);
56 data[child].parent = parent;
57 data[parent].children.emplace_back(child);
58 }
59 }
60
61 return data;
62}
63
64string
65root_node(const map<string, Node>& data)
66{
67 for ( const auto& [name, node]: data ) {
68 if ( !node.parent ) {
69 return name;
70 }
71 }
72 throw runtime_error("no root found");
73}
74
75void
76part1(const map<string, Node>& data)
77{
78 cout << "Part1: " << root_node(data) << '\n';
79}
80
81int
82calculate_weight(const map<string, Node>& data, const string& name) // NOLINT
83{
84 const auto& node = data.at(name);
85
86 if ( node.children.empty() ) {
87 return node.weight;
88 }
89
90 int total_weight = node.weight;
91
92 map<string, int> child_weights;
93 for ( const auto& child: node.children ) {
94 auto child_weight = calculate_weight(data, child);
95 child_weights.emplace(child, child_weight);
96 total_weight += child_weight;
97 }
98
99 map<int, vector<string>> grouped;
100 for ( const auto& [child, weight]: child_weights ) {
101 grouped[weight].emplace_back(child);
102 }
103
104 if ( grouped.size() != 1 ) {
105 int wrong_weight{};
106 int correct_weight{};
107 string wrong_name;
108
109 for ( const auto& [weight, names]: grouped ) {
110 if ( names.size() == 1 ) {
111 wrong_weight = weight;
112 wrong_name = names.front();
113 }
114 else {
115 correct_weight = weight;
116 }
117 }
118
119 const auto& wrong_node = data.at(wrong_name);
120 auto diff = wrong_weight - correct_weight;
121
122 cout << "Part2: " << wrong_node.weight - diff << '\n';
123
124 exit(0);
125 }
126
127 return total_weight;
128}
129
130void
131part2(const map<string, Node>& data)
132{
133 auto node = root_node(data);
134 calculate_weight(data, node);
135}
136
137} // namespace
138
139int
140main()
141{
142 auto data = read_file("data/day07.txt");
143 part1(data);
144 part2(data);
145}