1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
|
#advent of code 2018
#day 21
#part 1 and part 2
#this puzzle in my opinion was poorly worded, or I'm just overthinking
#part 1 was suprisingly simple since it only required running the solution for day 19
#unfortunately, bruteforcing the answer for part 2 didn't go as well
#reading through input its possible to identify instruction jumps and determine what causes them
#I was stuck for like 2 days for part 2: I couldn't find a bug in my reverse-engineering
#I even run someone else's solution (modified for my input) to verify it
#only to get another wrong answer
#I found a second solution and I compared it to mine
#only to find out that the issue wasn't in logic, I simply entered wrong value in 1 line
#at least this reverse-engineering puzzle was for me more enjoyable than the 2021 one
#part 1 bruteforce
#program halts if the value at register 0 matches the value at register X
#(register X is between 1 and 5, depends on the input)
#in one particular instruction near the end
#instruction 28 in my case
#calculating this value provides part 1 result
#part 2 reverse engineering
#you can simplify the input program by reverse-engineering
#basically the first few lines are trash, then the program is initiated with starting values
#if condition 1 is met, program enters a loop until condition 1 is no longer true
#after this loop, program checks if the value at register 0 is equal to corresponding register X
#if true, program halts
#you can print out all values at register X, first printed message is part1, last one is part 2
###opcode functions
#bit modified version of day 19
def addr(before, op):
bef = before.copy();
C = bef[op[1]] + bef[op[2]];
bef[op[3]] = C;
return bef;
def addi(before, op):
bef = before.copy();
C = bef[op[1]] + op[2];
bef[op[3]] = C;
return bef;
def mulr(before, op):
bef = before.copy();
C = bef[op[1]] * bef[op[2]];
bef[op[3]] = C;
return bef;
def muli(before, op):
bef = before.copy();
C = bef[op[1]] * op[2];
bef[op[3]] = C;
return bef;
def banr(before, op):
bef = before.copy();
C = int(bef[op[1]] & bef[op[2]]);
bef[op[3]] = C;
return bef;
def bani(before, op):
bef = before.copy();
C = int(bef[op[1]] & op[2]);
bef[op[3]] = C;
return bef;
def borr(before, op):
bef = before.copy();
C = int(bef[op[1]] | bef[op[2]]);
bef[op[3]] = C;
return bef;
def bori(before, op):
bef = before.copy();
C = int(bef[op[1]] | op[2]);
bef[op[3]] = C;
return bef;
def setr(before, op):
bef = before.copy();
C = bef[op[1]];
bef[op[3]] = C;
return bef;
def seti(before, op):
bef = before.copy();
C = op[1];
bef[op[3]] = C;
return bef;
def gtir(before, op):
bef = before.copy();
C = 0 + int( op[1] > bef[op[2]] );
bef[op[3]] = C;
return bef;
def gtri(before, op):
bef = before.copy();
C = 0 + int( op[2] < bef[op[1]] );
bef[op[3]] = C;
return bef;
def gtrr(before, op):
bef = before.copy();
C = 0 + int( bef[op[1]] > bef[op[2]] );
bef[op[3]] = C;
return bef;
def eqir(before, op):
bef = before.copy();
C = 0 + int( op[1] == bef[op[2]] );
bef[op[3]] = C;
return bef;
def eqri(before, op):
bef = before.copy();
C = 0 + int( op[2] == bef[op[1]] );
bef[op[3]] = C;
return bef;
def eqrr(before, op):
bef = before.copy();
C = 0 + int( bef[op[1]] == bef[op[2]] );
bef[op[3]] = C;
return bef;
MatchFunctions = {};
MatchFunctions.update({"addr":addr});
MatchFunctions.update({"addi":addi});
MatchFunctions.update({"mulr":mulr});
MatchFunctions.update({"muli":muli});
MatchFunctions.update({"banr":banr});
MatchFunctions.update({"bani":bani});
MatchFunctions.update({"borr":borr});
MatchFunctions.update({"bori":bori});
MatchFunctions.update({"setr":setr});
MatchFunctions.update({"seti":seti});
MatchFunctions.update({"gtir":gtir});
MatchFunctions.update({"gtri":gtri});
MatchFunctions.update({"gtrr":gtrr});
MatchFunctions.update({"eqir":eqir});
MatchFunctions.update({"eqri":eqri});
MatchFunctions.update({"eqrr":eqrr});
#end of day19 copy-paste
###############################################
f = open("input.txt",'r');
Testing = False;
#Testing = True;
if Testing:
f.close();
f = open("testinput.txt",'r');
ip = int(f.readline()[4:]);
instructions = [];
for l in f:
l = l.split();
i = [];
i.append(l[0]);
l_i = [int(x) for x in l[1:]];
i += l_i;
instructions.append(i);
part1 = None;
instr_lim = len(instructions);
while True:
reg = [0,0,0,0,0,0];
reg[ip] = 0;
part1 = None;
while True:
if( reg[ip] >= instr_lim): break;
if( reg[ip] >= 28):
#print(reg);
part1 = int(reg[5]);
break;
instr = instructions[reg[ip]];
fun = MatchFunctions[instr[0]];
reg = fun(reg,instr);
reg[ip] += 1;
if part1 != None:
break;
print("part 1 = ", part1, "(bruteforce)");
#part2
store1 = set(); #var ehich determines if the loop continues
store5 = set(); #var checked against the reg0
part1 = None;
part2 = None;
p2 = None;
reg5 = 10678677;
reg1 = 2**16;
while True:
reg4 = reg1%256;
reg5 += reg4;
reg5 = ((reg5%2**24)*65899)%(2**24);
if reg1<256:
if not store5:
part1 = int(reg5);
if reg5 not in store5:
part2 = int(reg5);
store5.add(reg5);
#print("regs", reg1, reg5)
reg1 = reg5 | 2**16;
if reg1 in store1:
break;
store1.add(reg1);
reg5 = 10678677;
continue;
reg1 = reg1//256;
print("part 1 = ", part1);
print("part 2 = ", part2);
#my input
'''
#ip 2
seti 123 0 5
bani 5 456 5
eqri 5 72 5
addr 5 2 2
seti 0 0 2
seti 0 4 5
bori 5 65536 1
seti 10678677 3 5
bani 1 255 4
addr 5 4 5
bani 5 16777215 5
muli 5 65899 5
bani 5 16777215 5
gtir 256 1 4
addr 4 2 2
addi 2 1 2
seti 27 5 2
seti 0 6 4
addi 4 1 3
muli 3 256 3
gtrr 3 1 3
addr 3 2 2
addi 2 1 2
seti 25 4 2
addi 4 1 4
seti 17 6 2
setr 4 6 1
seti 7 5 2
eqrr 5 0 4
addr 4 2 2
seti 5 4 2
'''
|