aboutsummaryrefslogtreecommitdiff
path: root/2016/src/day23.cpp
diff options
context:
space:
mode:
Diffstat (limited to '2016/src/day23.cpp')
-rw-r--r--2016/src/day23.cpp287
1 files changed, 287 insertions, 0 deletions
diff --git a/2016/src/day23.cpp b/2016/src/day23.cpp
new file mode 100644
index 0000000..81bffe4
--- /dev/null
+++ b/2016/src/day23.cpp
@@ -0,0 +1,287 @@
1#include <filesystem>
2#include <fstream>
3#include <iostream>
4#include <map>
5#include <optional>
6#include <sstream>
7#include <string>
8#include <utility>
9#include <vector>
10
11using namespace std;
12
13namespace {
14
15enum class OpCode : uint8_t {
16 CPY,
17 INC,
18 DEC,
19 JNZ,
20 TGL
21};
22
23using memory_type = map<char, int>;
24
25struct Argument {
26 explicit Argument(string value)
27 : value{ std::move(value) }
28 {
29 }
30
31 [[nodiscard]]
32 int eval(const memory_type& memory) const
33 {
34 const auto chr = value.at(0);
35
36 if ( chr >= 'a' && chr <= 'z' ) {
37 return memory.at(chr);
38 }
39 else {
40 return stoi(value);
41 }
42 }
43
44 [[nodiscard]]
45 char reg() const
46 {
47 if ( !is_reg() ) {
48 throw runtime_error("invalid register access! "s + value);
49 }
50
51 return value.at(0);
52 }
53
54 [[nodiscard]]
55 bool is_reg() const
56 {
57 const auto chr = value.at(0);
58
59 return chr >= 'a' && chr <= 'z';
60 }
61
62 string value;
63};
64
65struct Instruction {
66 Instruction(OpCode opCode, const Argument& x)
67 : opCode{ opCode }
68 , x{ x }
69 {
70 }
71
72 Instruction(OpCode opCode, const Argument& x, const Argument& y)
73 : opCode{ opCode }
74 , x{ x }
75 , y{ y }
76 {
77 }
78
79 OpCode opCode;
80 optional<Argument> x;
81 optional<Argument> y;
82};
83
84vector<string>
85split_words(const string& line, char sep = ' ')
86{
87 vector<string> words;
88 stringstream strm{ line };
89
90 for ( string word; getline(strm, word, sep); ) {
91 words.emplace_back(word);
92 }
93
94 return words;
95}
96
97vector<Instruction>
98read_file(const filesystem::path& filename)
99{
100 ifstream input{ filename };
101
102 vector<Instruction> instructions;
103
104 for ( string line; getline(input, line); ) {
105 const auto words = split_words(line);
106
107 if ( words.at(0) == "cpy" ) {
108 instructions.emplace_back(OpCode::CPY, Argument(words.at(1)), Argument(words.at(2)));
109 }
110 else if ( words.at(0) == "inc" ) {
111 instructions.emplace_back(OpCode::INC, Argument(words.at(1)));
112 }
113 else if ( words.at(0) == "dec" ) {
114 instructions.emplace_back(OpCode::DEC, Argument(words.at(1)));
115 }
116 else if ( words.at(0) == "jnz" ) {
117 instructions.emplace_back(OpCode::JNZ, Argument(words.at(1)), Argument(words.at(2)));
118 }
119 else if ( words.at(0) == "tgl" ) {
120 instructions.emplace_back(OpCode::TGL, Argument(words.at(1)));
121 }
122 else {
123 cerr << "unknown opcode..." << '\n';
124 }
125 }
126
127 return instructions;
128}
129
130#define JIT
131
132void
133execute(memory_type& memory, vector<Instruction> instructions)
134{
135 for ( size_t ip = 0; ip < instructions.size(); ) {
136#if defined(JIT)
137 if ( ip + 2 < instructions.size() ) {
138 const auto& i0 = instructions[ip];
139 const auto& i1 = instructions[ip + 1];
140 const auto& i2 = instructions[ip + 2];
141
142 if ( i0.opCode == OpCode::INC &&
143 i1.opCode == OpCode::DEC &&
144 i2.opCode == OpCode::JNZ &&
145 i2.x && i2.x->value == i1.x->value &&
146 i2.y && i2.y->value == "-2" ) {
147 char X = i0.x->reg();
148 char Y = i1.x->reg();
149 memory[X] += memory[Y];
150 memory[Y] = 0;
151 ip += 3;
152 continue;
153 }
154 }
155#endif
156
157#if defined(JIT)
158 if ( ip + 5 < instructions.size() ) {
159 const auto& i0 = instructions[ip];
160 const auto& i1 = instructions[ip + 1];
161 const auto& i2 = instructions[ip + 2];
162 const auto& i3 = instructions[ip + 3];
163 const auto& i4 = instructions[ip + 4];
164 const auto& i5 = instructions[ip + 5];
165
166 if ( i0.opCode == OpCode::CPY &&
167 i1.opCode == OpCode::INC &&
168 i2.opCode == OpCode::DEC &&
169 i3.opCode == OpCode::JNZ &&
170 i4.opCode == OpCode::DEC &&
171 i5.opCode == OpCode::JNZ &&
172 i3.x && i3.y && i3.x->value == i2.x->value && i3.y->value == "-2" &&
173 i5.x && i5.y && i5.x->value == i4.x->value && i5.y->value == "-5" &&
174 i0.y->is_reg() && i1.x->is_reg() && i2.x->is_reg() && i4.x->is_reg() ) {
175 char X = i0.x->is_reg() ? i0.x->reg() : 0;
176 int valX = i0.x->is_reg() ? memory[X] : stoi(i0.x->value);
177
178 char Y = i0.y->reg();
179 char Z = i1.x->reg();
180 char W = i4.x->reg();
181
182 memory[Z] += valX * memory[W];
183 memory[Y] = 0;
184 memory[W] = 0;
185 ip += 6;
186 continue;
187 }
188 }
189#endif
190
191 const auto& instruction = instructions.at(ip);
192
193 // cout << "#" << ip << " - " << memory['a'] << ", " << memory['b'] << ", " << memory['c'] << ", " << memory['d'] << ": " << (int) instruction.opCode << '\n';
194
195 switch ( instruction.opCode ) {
196 using enum OpCode;
197 case CPY:
198 memory[instruction.y->reg()] = instruction.x->eval(memory);
199 ++ip;
200 break;
201 case INC:
202 memory[instruction.x->reg()]++;
203 ++ip;
204 break;
205 case DEC:
206 memory[instruction.x->reg()]--;
207 ++ip;
208 break;
209 case JNZ:
210 if ( instruction.x->eval(memory) != 0 ) {
211 ip += static_cast<size_t>(instruction.y->eval(memory));
212 }
213 else {
214 ++ip;
215 }
216 break;
217 case TGL:
218 if ( auto foo = ip + static_cast<size_t>(instruction.x->eval(memory)); foo < instructions.size() ) {
219 switch ( instructions[foo].opCode ) {
220 case CPY:
221 instructions[foo].opCode = JNZ;
222 break;
223 case INC:
224 instructions[foo].opCode = DEC;
225 break;
226 case DEC:
227 instructions[foo].opCode = INC;
228 break;
229 case JNZ:
230 instructions[foo].opCode = CPY;
231 break;
232 case TGL:
233 instructions[foo].opCode = INC;
234 break;
235 }
236 }
237
238 ++ip;
239 break;
240 }
241 }
242}
243
244void
245part1(const vector<Instruction>& instructions)
246{
247 map<char, int> memory;
248
249 memory['a'] = 7;
250 memory['b'] = 0;
251 memory['c'] = 0;
252 memory['d'] = 0;
253
254 execute(memory, instructions);
255
256 cout << "Part1: " << memory['a'] << '\n';
257}
258
259void
260part2(const vector<Instruction>& instructions)
261{
262 map<char, int> memory;
263
264 memory['a'] = 12;
265 memory['b'] = 0;
266 memory['c'] = 0;
267 memory['d'] = 0;
268
269 execute(memory, instructions);
270
271 cout << "Part2: " << memory['a'] << '\n';
272}
273
274} // namespace
275
276int
277main()
278{
279 const auto instructions = read_file("data/day23.txt");
280 try {
281 part1(instructions);
282 part2(instructions);
283 }
284 catch ( exception& e ) {
285 cerr << e.what() << '\n';
286 }
287}