aboutsummaryrefslogtreecommitdiff
path: root/2017/src/day18.cpp
diff options
context:
space:
mode:
authorThomas Schmucker <ts@its1.de>2025-11-02 21:41:58 +0100
committerThomas Schmucker <ts@its1.de>2025-11-02 21:41:58 +0100
commit756f22d58bb198b8f34589c112e1003614ccdcd6 (patch)
tree4cdeba335f1ea67f7ead9e9f763ba1c3c206fc4d /2017/src/day18.cpp
parentfcbb722bd4c5ca2bd34a7cf9c0ba48f2f955da13 (diff)
downloadadvent-of-code-756f22d58bb198b8f34589c112e1003614ccdcd6.tar.gz
advent-of-code-756f22d58bb198b8f34589c112e1003614ccdcd6.tar.bz2
advent-of-code-756f22d58bb198b8f34589c112e1003614ccdcd6.zip
aoc 2017, days 1-20
Diffstat (limited to '2017/src/day18.cpp')
-rw-r--r--2017/src/day18.cpp266
1 files changed, 266 insertions, 0 deletions
diff --git a/2017/src/day18.cpp b/2017/src/day18.cpp
new file mode 100644
index 0000000..bfdd7e3
--- /dev/null
+++ b/2017/src/day18.cpp
@@ -0,0 +1,266 @@
1#include <charconv>
2#include <filesystem>
3#include <fstream>
4#include <iostream>
5#include <map>
6#include <queue>
7#include <sstream>
8#include <string>
9#include <vector>
10
11using namespace std;
12
13namespace {
14
15template<typename T>
16struct CPU {
17 [[nodiscard]]
18 T get(const string& ref)
19 {
20 T value{};
21 auto [ptr, ec] = from_chars(ref.data(), ref.data() + ref.size(), value);
22
23 if ( ec == errc() ) {
24 return value;
25 }
26
27 return memory[ref];
28 }
29
30 void set(const string& ref, T value)
31 {
32 memory[ref] = value;
33 }
34
35 void add(const string& ref, T value)
36 {
37 memory[ref] += value;
38 }
39
40 void mul(const string& ref, T value)
41 {
42 memory[ref] *= value;
43 }
44
45 void mod(const string& ref, T value)
46 {
47 memory[ref] %= value;
48 }
49
50 T execute(const vector<vector<string>>& code)
51 {
52 long played_sound{};
53
54 for ( size_t ip = 0; ip < code.size(); ++ip ) {
55 const auto& line = code.at(ip);
56 const auto& opcode = line.at(0);
57
58 if ( opcode == "snd" ) {
59 played_sound = get(line.at(1));
60 }
61 else if ( opcode == "rcv" ) {
62 auto value = get(line.at(1));
63 if ( value != 0 ) {
64 return played_sound;
65 }
66 }
67 else if ( opcode == "set" ) {
68 set(line.at(1), get(line.at(2)));
69 }
70 else if ( opcode == "add" ) {
71 add(line.at(1), get(line.at(2)));
72 }
73 else if ( opcode == "mul" ) {
74 mul(line.at(1), get(line.at(2)));
75 }
76 else if ( opcode == "mod" ) {
77 mod(line.at(1), get(line.at(2)));
78 }
79 else if ( opcode == "jgz" ) {
80 auto value = get(line.at(1));
81 if ( value > 0 ) {
82 auto offset = get(line.at(2));
83 ip += static_cast<size_t>(offset - 1);
84 }
85 }
86 else {
87 cerr << "unknown opcode: " << opcode << '\n';
88 return -1;
89 }
90 }
91 return -1;
92 }
93
94 map<string, T> memory;
95};
96
97template<typename T>
98struct CPU2 {
99 CPU2(queue<T>& in, queue<T>& out)
100 : in{ in }
101 , out{ out }
102 {
103 }
104
105 [[nodiscard]]
106 T get(const string& ref)
107 {
108 T value{};
109 auto [ptr, ec] = from_chars(ref.data(), ref.data() + ref.size(), value);
110
111 if ( ec == errc() ) {
112 return value;
113 }
114
115 return memory[ref];
116 }
117
118 void set(const string& ref, T value)
119 {
120 memory[ref] = value;
121 }
122
123 void add(const string& ref, T value)
124 {
125 memory[ref] += value;
126 }
127
128 void mul(const string& ref, T value)
129 {
130 memory[ref] *= value;
131 }
132
133 void mod(const string& ref, T value)
134 {
135 memory[ref] %= value;
136 }
137
138 bool step(const vector<vector<string>>& code)
139 {
140 if ( ip >= code.size() ) {
141 return false;
142 }
143
144 const auto& line = code.at(ip);
145 const auto& opcode = line.at(0);
146
147 if ( opcode == "snd" ) {
148 out.push(get(line.at(1)));
149 ++send_count;
150 }
151 else if ( opcode == "rcv" ) {
152 if ( in.empty() ) {
153 waiting = true;
154 return true;
155 }
156 else {
157 auto value = in.front();
158 in.pop();
159 set(line.at(1), value);
160 waiting = false;
161 }
162 }
163 else if ( opcode == "set" ) {
164 set(line.at(1), get(line.at(2)));
165 }
166 else if ( opcode == "add" ) {
167 add(line.at(1), get(line.at(2)));
168 }
169 else if ( opcode == "mul" ) {
170 mul(line.at(1), get(line.at(2)));
171 }
172 else if ( opcode == "mod" ) {
173 mod(line.at(1), get(line.at(2)));
174 }
175 else if ( opcode == "jgz" ) {
176 auto value = get(line.at(1));
177 if ( value > 0 ) {
178 auto offset = get(line.at(2));
179 ip += static_cast<size_t>(offset);
180 return true;
181 }
182 }
183 else {
184 cerr << "unknown opcode: " << opcode << '\n';
185 return false;
186 }
187
188 ++ip;
189
190 return true;
191 }
192
193 size_t ip{};
194 queue<T>& in;
195 queue<T>& out;
196 bool waiting{ false };
197 T send_count{};
198 map<string, T> memory;
199};
200
201vector<string>
202split(const string& line)
203{
204 stringstream strm{ line };
205 vector<string> data;
206
207 for ( string line; strm >> line; ) {
208 data.emplace_back(line);
209 }
210
211 return data;
212}
213
214vector<vector<string>>
215read_file(const filesystem::path& filename)
216{
217 ifstream file{ filename };
218 vector<vector<string>> data;
219
220 for ( string line; getline(file, line); ) {
221 const auto parts = split(line);
222 data.emplace_back(parts);
223 }
224
225 return data;
226}
227
228void
229part1(const vector<vector<string>>& code)
230{
231 CPU<long> cpu{};
232
233 cout << "Part1: " << cpu.execute(code) << '\n';
234}
235
236void
237part2(const vector<vector<string>>& code)
238{
239 queue<long> queue1;
240 queue<long> queue2;
241 CPU2<long> cpu1{ queue1, queue2 };
242 CPU2<long> cpu2{ queue2, queue1 };
243
244 cpu1.set("p", 0);
245 cpu2.set("p", 1);
246
247 for ( ;; ) {
248 auto cpu1_running = cpu1.step(code);
249 auto cpu2_running = cpu2.step(code);
250
251 if ( (cpu1.waiting || !cpu1_running) && (cpu2.waiting || !cpu2_running) ) {
252 break;
253 }
254 }
255 cout << "Part2: " << cpu2.send_count << '\n';
256}
257
258} // namespace
259
260int
261main()
262{
263 auto instr = read_file("data/day18.txt");
264 part1(instr);
265 part2(instr);
266}