aboutsummaryrefslogtreecommitdiff
path: root/src/day20.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/day20.cpp')
-rw-r--r--src/day20.cpp204
1 files changed, 204 insertions, 0 deletions
diff --git a/src/day20.cpp b/src/day20.cpp
new file mode 100644
index 0000000..71b83a3
--- /dev/null
+++ b/src/day20.cpp
@@ -0,0 +1,204 @@
1#include <algorithm>
2#include <fstream>
3#include <iostream>
4#include <map>
5#include <memory>
6#include <queue>
7#include <string>
8#include <vector>
9
10using namespace std;
11
12vector<string>
13read_file(string_view filename)
14{
15 fstream input{ filename };
16 vector<string> data;
17
18 for ( string line; getline(input, line); ) {
19 data.emplace_back(line);
20 }
21
22 return data;
23}
24
25vector<string>
26split(string_view line, string_view delimiter)
27{
28 size_t pos_start = 0;
29 size_t pos_end = 0;
30
31 vector<string> res;
32
33 while ( (pos_end = line.find(delimiter, pos_start)) != string::npos ) {
34 auto token = line.substr(pos_start, pos_end - pos_start);
35 pos_start = pos_end + delimiter.length();
36
37 res.emplace_back(token);
38 }
39
40 if ( pos_start != line.size() ) {
41 res.emplace_back(line.substr(pos_start));
42 }
43 return res;
44}
45
46struct Module { // NOLINT
47protected:
48 explicit Module(string_view name, queue<tuple<string, int, string>>& queue)
49 : name_(name)
50 , queue_(queue)
51 {
52 }
53 virtual ~Module() = default;
54
55public:
56 virtual void trigger(string_view sender, int signal) = 0;
57
58 void register_sender(string_view sender) { senders_.emplace(sender, 0); }
59
60protected:
61 void send_signal(int signal) const
62 {
63 for ( const auto& link: links_ ) {
64 queue_.emplace(name_, signal, link);
65 }
66 }
67
68public:
69 void add_link(string_view link) { links_.emplace_back(link); }
70
71protected:
72 const string name_;
73 queue<tuple<string, int, string>>& queue_;
74
75public:
76 vector<string> links_;
77 map<string, int> senders_;
78};
79
80struct BroadcasterModuler : public Module {
81 explicit BroadcasterModuler(string_view name, queue<tuple<string, int, string>>& queue)
82 : Module(name, queue)
83 {
84 }
85 void trigger(string_view, int signal) override
86 {
87 send_signal(signal);
88 }
89};
90
91struct FlipFlopModule : public Module {
92 explicit FlipFlopModule(string_view name, queue<tuple<string, int, string>>& queue)
93 : Module(name, queue)
94 {
95 }
96 void trigger(string_view, int signal) override
97 {
98 if ( signal == 1 ) {
99 return;
100 }
101 state_ = (state_ + 1) % 2;
102 send_signal(state_);
103 }
104 int state_{ 0 };
105};
106
107struct ConjunctionModule : public Module {
108 explicit ConjunctionModule(string_view name, queue<tuple<string, int, string>>& queue)
109 : Module(name, queue)
110 {
111 }
112 void trigger(string_view sender, int signal) override
113 {
114 senders_[string(sender)] = signal;
115 if ( all_of(senders_.begin(), senders_.end(), [](const auto& link) { return link.second == 1; }) ) {
116 send_signal(0);
117 }
118 else {
119 send_signal(1);
120 }
121 }
122};
123
124struct OutputModule : public Module {
125 explicit OutputModule(string_view name, queue<tuple<string, int, string>>& queue)
126 : Module(name, queue)
127 {
128 }
129 void trigger(string_view, int) override
130 {
131 }
132};
133
134void
135part1()
136{
137 queue<tuple<string, int, string>> queue;
138 map<string, shared_ptr<Module>> modules;
139
140 modules["output"] = make_shared<OutputModule>("output", queue);
141
142 const auto input = read_file("data/day20.txt");
143 for ( const auto& line: input ) {
144 const auto parts = split(line, " -> ");
145 auto module = parts[0];
146 const auto dests = split(parts[1], ", ");
147
148 shared_ptr<Module> ptr;
149 if ( module == "broadcaster" ) {
150 ptr = make_shared<BroadcasterModuler>(module, queue);
151 }
152 else if ( module.starts_with('%') ) {
153 module.erase(0, 1);
154 ptr = make_shared<FlipFlopModule>(module, queue);
155 }
156 else if ( module.starts_with('&') ) {
157 module.erase(0, 1);
158 ptr = make_shared<ConjunctionModule>(module, queue);
159 }
160 else {
161 cerr << "unknown module type: " << module << endl;
162 return;
163 }
164
165 for ( const auto& dest: dests ) {
166 ptr->add_link(dest);
167 }
168
169 modules[module] = ptr;
170 }
171
172 // register senders
173 for ( auto& module: modules ) {
174 auto [name, ptr] = module;
175
176 for ( const auto& link: ptr->links_ ) {
177 if ( modules.contains(link) ) {
178 modules[link]->register_sender(name);
179 }
180 }
181 }
182
183 long sums[2] = { 0, 0 };
184 for ( int i = 0; i != 1000; ++i ) {
185 queue.emplace("button", 0, "broadcaster");
186 while ( !queue.empty() ) {
187 const auto [sender, signal, receiver] = queue.front();
188 queue.pop();
189
190 sums[signal]++;
191
192 if ( modules.contains(receiver) ) {
193 modules[receiver]->trigger(sender, signal);
194 }
195 }
196 }
197 cout << sums[0] * sums[1] << endl;
198}
199
200int
201main()
202{
203 part1();
204}