1
+ #include < fstream>
2
+ #include < iostream>
3
+ #include < string>
4
+ #include < unordered_map>
5
+ #include < vector>
6
+ #include < variant>
7
+ #include < queue>
8
+
9
+ // HINT: When the puzzle says X or Y, unless it specifies register, X or Y can be a number
10
+ // jgz 1 3 is a possibility
11
+ // add p b is a possibility
12
+
13
+ enum class InstructionType {
14
+ UNKNOWN, SND, SET, ADD, MUL, MOD, RCV, JGZ
15
+ };
16
+
17
+ struct Instruction {
18
+ std::string line;
19
+ InstructionType type;
20
+ std::array<std::variant<long long , char >,2 > args;
21
+
22
+ long long reg () const {
23
+ return std::get<char >(args[0 ]);
24
+ }
25
+
26
+ long long get_value (const int idx, std::unordered_map<char , long long >& regs) const {
27
+ return args[idx].index () == 0 ? std::get<long long >(args[idx]) : regs[std::get<char >(args[idx])];
28
+ }
29
+ };
30
+
31
+ InstructionType parse_type (const std::string& instr) {
32
+ if (instr == " snd" ) {
33
+ return InstructionType::SND;
34
+ } else if (instr == " set" ) {
35
+ return InstructionType::SET;
36
+ } else if (instr == " add" ) {
37
+ return InstructionType::ADD;
38
+ } else if (instr == " mul" ) {
39
+ return InstructionType::MUL;
40
+ } else if (instr == " mod" ) {
41
+ return InstructionType::MOD;
42
+ } else if (instr == " rcv" ) {
43
+ return InstructionType::RCV;
44
+ } else if (instr == " jgz" ) {
45
+ return InstructionType::JGZ;
46
+ }
47
+ std::cout << " UNKNOWN" << ' \n ' ;
48
+ exit (0 );
49
+ return InstructionType::UNKNOWN;
50
+ }
51
+
52
+ struct Program {
53
+ Program (const int id) : id(id) {
54
+ for (char ch = ' a' ; ch <= ' z' ; ch++) {
55
+ regs[ch] = 0 ;
56
+ // std::cout << ch << ' ' << regs[ch] << '\n';
57
+ }
58
+ regs[' p' ] = id;
59
+ // std::cout << 'p' << ' ' << regs['p'] << '\n' << '\n';
60
+ }
61
+ int id;
62
+ std::queue<int > q;
63
+ std::size_t instruction_ptr = 0 ;
64
+ std::unordered_map<char , long long > regs;
65
+ bool stuck = false ;
66
+ bool complete = false ;
67
+
68
+ std::pair<bool , long long > execute (const std::vector<Instruction>& instructions) {
69
+ if (complete) {
70
+ return {false ,0 };
71
+ }
72
+ if (instruction_ptr >= instructions.size ()) {
73
+ complete = true ;
74
+ std::cout << " Complete" << ' \n ' ;
75
+ return {false ,0 };
76
+ }
77
+ const auto & instruction = instructions[instruction_ptr];
78
+ // std::cout << id<< ": " << instruction_ptr << " -> " << instruction.line << '\n';
79
+ if (instruction.type == InstructionType::SND) {
80
+ instruction_ptr++;
81
+ // if (regs[instruction.reg()] >= 0) {
82
+ return {true , instruction.get_value (0 , regs)};
83
+ // }
84
+ } else if (instruction.type == InstructionType::SET) {
85
+ regs[instruction.reg ()] = instruction.get_value (1 , regs);
86
+ instruction_ptr++;
87
+ } else if (instruction.type == InstructionType::ADD) {
88
+ regs[instruction.reg ()] += instruction.get_value (1 , regs);
89
+ instruction_ptr++;
90
+ } else if (instruction.type == InstructionType::MUL) {
91
+ regs[instruction.reg ()] *= instruction.get_value (1 , regs);
92
+ instruction_ptr++;
93
+ } else if (instruction.type == InstructionType::MOD) {
94
+ regs[instruction.reg ()] = regs[instruction.reg ()] % instruction.get_value (1 , regs);
95
+ instruction_ptr++;
96
+ } else if (instruction.type == InstructionType::RCV) {
97
+ if (!q.empty ()) {
98
+ regs[instruction.reg ()] = q.front ();
99
+ q.pop ();
100
+ stuck = false ;
101
+ // std::cout << id <<": Un Stuck " << '\n';
102
+ instruction_ptr++;
103
+ } else {
104
+ // std::cout << id <<": Stuck " << '\n';
105
+ stuck = true ;
106
+ }
107
+ } else if (instruction.type == InstructionType::JGZ) {
108
+ // std::cout << instruction.get_value(0, regs) << '\n';
109
+ if (instruction.get_value (0 , regs) > 0 ) {
110
+ // std::cout << instruction.get_value(1, regs) << '\n';
111
+ // std::cout << "Jump: " << instruction_ptr << ": " << instructions[instruction_ptr].line << " ---> ";
112
+ instruction_ptr += instruction.get_value (1 , regs);
113
+ // std::cout << instruction_ptr << ": " << instructions[instruction_ptr].line << '\n';
114
+ } else {
115
+ instruction_ptr++;
116
+ }
117
+ } else {
118
+ std::cout << " UNKNOWN" << ' \n ' ;
119
+ exit (0 );
120
+ }
121
+ // std::cout << id << ": ";
122
+ // for (char ch = 'a'; ch <= 'z'; ch++) {
123
+ // if (regs[ch] != 0) {
124
+ // std::cout << '(' << ch << "," << regs[ch] << ')' << ' ';
125
+ // }
126
+ // }
127
+ // std::cout << '\n';
128
+ return {false , 0 };
129
+ }
130
+ };
131
+
132
+ std::vector<Instruction> parse_instructions (std::ifstream& file) {
133
+ std::vector<Instruction> instructions;
134
+ std::string line;
135
+ while (std::getline (file, line)) {
136
+ // std::cout << line << '\n';
137
+ Instruction i;
138
+ i.line = line;
139
+ i.type = parse_type (line.substr (0 , 3 ));
140
+ int next = 0 ;
141
+ if (line[4 ] >= ' a' && line[4 ] <=' z' ) {
142
+ // std::cout << "Args 1 is a register: " << char(line[4]) <<'\n';
143
+ i.args [0 ] = char (line[4 ]);
144
+ next = 6 ;
145
+ } else {
146
+ next = line.find (' ' , 4 );
147
+ if (next == std::string::npos) {
148
+ // std::cout << "npos" << '\n';
149
+ next == line.size ();
150
+ }
151
+ // std::cout << "Args 1 is a number: " << std::stoi(line.substr(4, next - 4)) << '\n';
152
+ i.args [0 ] = std::stoi (line.substr (4 , next - 4 ));
153
+ if (next != std::string::npos) {
154
+ next++;
155
+ }
156
+ }
157
+ // std::cout << line.size() << ' ' << next << '\n';
158
+ if (line.size () >= next) {
159
+ // std::cout << "Second args exists; size == " << line.size() << " > " << next << '\n';
160
+ if (line[next] >= ' a' && line[next] <=' z' ) {
161
+ i.args [1 ] = char (line[next]);
162
+ // std::cout << "Args 2 is a register: " << char(line[next]) <<'\n';
163
+ } else {
164
+ // std::cout << "Args 2 is a number: " << std::stoi(line.substr(next, line.size() - next)) << '\n';
165
+ i.args [1 ] = std::stoi (line.substr (next, line.size () - next));
166
+ }
167
+ }
168
+
169
+ instructions.push_back (i);
170
+ }
171
+ // exit(0);
172
+ return instructions;
173
+ }
174
+
175
+ int main (int argc, char * argv[]) {
176
+ const std::string input = (argc > 1 ) ? argv[1 ] : " ../input/day_18_input" ;
177
+ std::ifstream file (input);
178
+ std::vector<Program> programs = {Program (0 ), Program (1 )};
179
+ const std::vector<Instruction> instructions = parse_instructions (file);
180
+ std::size_t ans = 0 ;
181
+ while (!(programs[0 ].stuck || programs[0 ].complete ) || !(programs[1 ].stuck || programs[1 ].complete )) {
182
+ // std::cout << programs[0].stuck << programs[1].stuck << programs[0].complete << programs[1].complete << '\n';
183
+ // if ((programs[0].stuck && programs[1].stuck)) {
184
+ // std::cout << "both stuck" << '\n';
185
+ // }
186
+ // if (programs[0].complete && programs[1].complete) {
187
+ // std::cout << "both complete" << '\n';
188
+ // }
189
+ std::pair<bool , long long > result_0 = programs[0 ].execute (instructions);
190
+ std::pair<bool , long long > result_1 = programs[1 ].execute (instructions);
191
+ if (result_0.first ) {
192
+ programs[1 ].q .push (result_0.second );
193
+ programs[1 ].stuck = false ;
194
+ }
195
+ if (result_1.first ) {
196
+ ans++;
197
+ programs[0 ].q .push (result_1.second );
198
+ programs[0 ].stuck = false ;
199
+ }
200
+ }
201
+ // std::cout << programs[0].stuck << programs[1].stuck << programs[0].complete << programs[1].complete << '\n';
202
+
203
+ std::cout << ans << ' \n ' ;
204
+ return 0 ;
205
+ }
0 commit comments