2
2
3
3
#include < cmath>
4
4
#include < cstdint>
5
+ #include < format>
6
+ #include < iostream>
7
+ #include < string_view>
5
8
6
9
namespace aoc ::day_17 {
7
10
8
- [[nodiscard]] auto transpile (program const & program_to_transpile) -> std::string {
9
- std::string result = R"( #pragma once
11
+ namespace {
12
+ constexpr std::string_view PROGRAM_HEADER = R"( #pragma once
10
13
#include <cmath>
11
14
#include <cstdint>
12
15
#include <iostream>
@@ -15,131 +18,97 @@ namespace aoc::day_17 {
15
18
void run_using_best_lang() {
16
19
bool first_out = true;)" ;
17
20
18
- result += " int64_t a = " + std::to_string (program_to_transpile.register_a ) + " ;\n " ;
19
- result += " int64_t b = " + std::to_string (program_to_transpile.register_b ) + " ;\n " ;
20
- result += " int64_t c = " + std::to_string (program_to_transpile.register_c ) + " ;\n " ;
21
+ constexpr std::string_view HELPERS_HEADER = R"( #pragma once
22
+ #include <cmath>
23
+ #include <cstdint>
24
+ #include <vector>
25
+
26
+ auto calculate_byte(int64_t a) -> int64_t {
27
+ )" ;
28
+
29
+ namespace opcode_translation {
30
+ static auto translate_div_operation (std::string const & target, int64_t operand) -> std::string {
31
+ if (operand < 4 ) {
32
+ return std::format (" {} = {} / {};\n " , target, target, static_cast <uint8_t >(std::pow (2 , operand)));
33
+ }
34
+ return std::format (" {} = {} / std::pow(2, {});\n " , target, target, to_combo_operand_literal (operand));
35
+ }
36
+
37
+ static auto translate_output (int64_t operand) -> std::string {
38
+ return std::format (R"( if(first_out) {{
39
+ std::cout << {} % 8 << std::endl;
40
+ first_out = false;
41
+ }} else {{
42
+ std::cout << "," << {} % 8 << std::endl;
43
+ }}
44
+ )" ,
45
+ to_combo_operand_literal (operand), to_combo_operand_literal (operand));
46
+ }
47
+
48
+ auto translate_opcode (opcode op, int64_t operand, size_t label_index = 0 ) -> std::string {
49
+ switch (op) {
50
+ case opcode::ADV:
51
+ return translate_div_operation (" a" , operand);
52
+ case opcode::BXL:
53
+ return std::format (" b ^= {};\n " , operand);
54
+ case opcode::BST:
55
+ return std::format (" b = {} % 8;\n " , to_combo_operand_literal (operand));
56
+ case opcode::JNZ:
57
+ return std::format (" if (a != 0) goto _{};\n " , operand);
58
+ case opcode::BXC:
59
+ return " b ^= c;\n " ;
60
+ case opcode::OUT:
61
+ return translate_output (operand);
62
+ case opcode::BDV:
63
+ return translate_div_operation (" b" , operand);
64
+ case opcode::CDV:
65
+ return translate_div_operation (" c" , operand);
66
+ default :
67
+ return " " ;
68
+ }
69
+ }
70
+ } // namespace opcode_translation
71
+
72
+ auto initialize_registers (program const & prog) -> std::string {
73
+ return std::format (" int64_t a = {};\n int64_t b = {};\n int64_t c = {};\n " , prog.register_a ,
74
+ prog.register_b , prog.register_c );
75
+ }
76
+
77
+ } // anonymous namespace
78
+
79
+ auto transpile (program const & program_to_transpile) -> std::string {
80
+ std::string result{PROGRAM_HEADER};
81
+ result += initialize_registers (program_to_transpile);
21
82
22
83
for (size_t i = 0 ; i < program_to_transpile.m_chunk .size (); i += 2 ) {
84
+ auto const [op, operand] =
85
+ std::tuple{program_to_transpile.m_chunk [i], i + 1 < program_to_transpile.m_chunk .size ()
86
+ ? static_cast <int64_t >(program_to_transpile.m_chunk [i + 1 ])
87
+ : 0 };
88
+
23
89
result += " _" + std::to_string (i * 5 ) + " : " ;
24
- auto op = program_to_transpile.m_chunk [i];
25
- auto operand =
26
- i + 1 < program_to_transpile.m_chunk .size () ? static_cast <int64_t >(program_to_transpile.m_chunk [i + 1 ]) : 0 ;
27
- switch (op) {
28
- case opcode::ADV:
29
- {
30
- if (operand < 4 ) {
31
- result += " a = a / " + std::to_string ((uint8_t )std::pow (2 , operand)) + " ;\n " ;
32
- } else {
33
- result += " a = a / std::pow(2, " + to_combo_operand_literal (operand) + " );\n " ;
34
- }
35
- break ;
36
- }
37
- case opcode::BXL:
38
- result += " b ^= " + std::to_string (operand) + " ;\n " ;
39
- break ;
40
- case opcode::BST:
41
- result += " b = " + to_combo_operand_literal (operand) + " % 8;\n " ;
42
- break ;
43
- case opcode::JNZ:
44
- result += " if (a != 0) goto _" + std::to_string (operand) + " ;\n " ;
45
- break ;
46
- case opcode::BXC:
47
- result += " b ^= c;\n " ;
48
- break ;
49
- case opcode::OUT:
50
- result += R"( if(first_out) {
51
- std::cout << )" ;
52
- result += to_combo_operand_literal (operand) + R"( % 8 << std::endl;
53
- first_out = false;
54
- } else {
55
- std::cout << "," << )" ;
56
- result += to_combo_operand_literal (operand) + R"( % 8 << std::endl;
57
- }
58
- )" ;
59
- break ;
60
- case opcode::BDV:
61
- {
62
- if (operand < 4 ) {
63
- result += " b = a / " + std::to_string ((uint8_t )std::pow (2 , operand)) + " ;\n " ;
64
- } else {
65
- result += " b = a / std::pow(2, " + to_combo_operand_literal (operand) + " );\n " ;
66
- }
67
- break ;
68
- }
69
- case opcode::CDV:
70
- {
71
- if (operand < 4 ) {
72
- result += " c = a / " + std::to_string ((uint8_t )std::pow (2 , operand)) + " ;\n " ;
73
- } else {
74
- result += " c = a / std::pow(2, " + to_combo_operand_literal (operand) + " );\n " ;
75
- }
76
- break ;
77
- }
78
- }
90
+ result += opcode_translation::translate_opcode (op, operand);
79
91
}
80
92
81
93
result += R"( if (!first_out) {
82
94
std::cout << std::endl;
83
95
}
84
- return;\n )" ;
85
- result += " } \n " ;
86
-
96
+ return;
97
+ }
98
+ )" ;
87
99
return result;
88
100
}
89
101
90
- [[nodiscard]] auto extract_helpers (chunk const & bytecode) -> std::string {
91
- std::string result = R"( #pragma once
92
- #include <cmath>
93
- #include <cstdint>
94
- #include <vector>
95
-
96
- auto calculate_byte(int64_t a) -> int64_t {
97
- )" ;
102
+ auto extract_helpers (chunk const & bytecode) -> std::string {
103
+ std::string result{HELPERS_HEADER};
98
104
result += " int64_t b = 0, c = 0;\n " ;
99
105
100
106
for (size_t i = 0 ; i < bytecode.size (); i += 2 ) {
101
- auto op = bytecode[i];
102
- auto operand = i + 1 < bytecode.size () ? static_cast <int64_t >(bytecode[i + 1 ]) : 0 ;
103
-
104
- switch (op) {
105
- case opcode::ADV:
106
- {
107
- if (operand < 4 ) {
108
- result += " a = a / " + std::to_string ((uint8_t )std::pow (2 , operand)) + " ;\n " ;
109
- } else {
110
- result += " a = a / std::pow(2, " + to_combo_operand_literal (operand) + " );\n " ;
111
- }
112
- break ;
113
- }
114
- case opcode::BXL:
115
- result += " b ^= " + std::to_string (operand) + " ;\n " ;
116
- break ;
117
- case opcode::BST:
118
- result += " b = " + to_combo_operand_literal (operand) + " % 8;\n " ;
119
- break ;
120
- case opcode::BXC:
121
- result += " b ^= c;\n " ;
122
- break ;
123
- case opcode::BDV:
124
- {
125
- if (operand < 4 ) {
126
- result += " b = a / " + std::to_string ((uint8_t )std::pow (2 , operand)) + " ;\n " ;
127
- } else {
128
- result += " b = a / std::pow(2, " + to_combo_operand_literal (operand) + " );\n " ;
129
- }
130
- break ;
131
- }
132
- case opcode::CDV:
133
- {
134
- if (operand < 4 ) {
135
- result += " c = a / " + std::to_string ((uint8_t )std::pow (2 , operand)) + " ;\n " ;
136
- } else {
137
- result += " c = a / std::pow(2, " + to_combo_operand_literal (operand) + " );\n " ;
138
- }
139
- break ;
140
- }
141
- default :
142
- break ;
107
+ auto const [op, operand] =
108
+ std::tuple{bytecode[i], i + 1 < bytecode.size () ? static_cast <int64_t >(bytecode[i + 1 ]) : 0 };
109
+
110
+ if (op != opcode::JNZ && op != opcode::OUT) {
111
+ result += opcode_translation::translate_opcode (op, operand);
143
112
}
144
113
}
145
114
@@ -161,4 +130,5 @@ auto calculate_byte(int64_t a) -> int64_t {
161
130
})" ;
162
131
return result;
163
132
}
133
+
164
134
} // namespace aoc::day_17
0 commit comments