22
22
}
23
23
24
24
{
25
- long part2 = machine . SolveQuine ( ) ;
26
- Console . WriteLine ( $ "Part 2: { part2 } ") ;
25
+ long ? solution = null ;
26
+ long minSolution = - 1 ;
27
+
28
+ while ( ( solution = machine . SolveQuine ( solution ) ) != null ) {
29
+ Console . WriteLine ( $ "Found solution: { solution . Value } ") ;
30
+ minSolution = solution . Value ;
31
+ }
32
+
33
+ Console . WriteLine ( $ "Part 2: { minSolution } ") ;
27
34
28
- machine . Registers [ 0 ] = part2 ;
35
+ machine . Registers [ 0 ] = minSolution ;
29
36
List < long > output = machine . Run ( ) ;
30
37
Console . WriteLine ( $ "(outputs { string . Join ( "," , output ) } )") ;
31
38
}
@@ -113,7 +120,7 @@ private List<long> RunOptimizedInputProgram()
113
120
return outputs ;
114
121
}
115
122
116
- public long SolveQuine ( )
123
+ public long ? SolveQuine ( long ? upperBound = null )
117
124
{
118
125
// For part 2 we use an approach inspired by a Reddit post by deferring the
119
126
// heavy-lifting to the Z3 SMT solver:
@@ -135,14 +142,14 @@ public long SolveQuine()
135
142
int outputs = 0 ;
136
143
int iterations = 0 ;
137
144
138
- string Int2Bv ( int value ) => $ "((_ int2bv { bits } ) { value } )";
145
+ string Long2Bv ( long value ) => $ "((_ int2bv { bits } ) { value } )";
139
146
string Register ( int i , int offset = 0 ) => $ "{ registerVars [ i ] } { registerCounts [ i ] + offset } ";
140
147
141
148
for ( int i = 0 ; i < Program . Count ; )
142
149
{
143
150
int opcode = Program [ i ] ;
144
151
int operand = Program [ i + 1 ] ;
145
- string literal = Int2Bv ( operand ) ;
152
+ string literal = Long2Bv ( operand ) ;
146
153
string combo = operand >= 4 && operand < 7 ? Register ( operand - 4 ) : literal ;
147
154
bool jumped = false ;
148
155
switch ( opcode )
@@ -156,7 +163,7 @@ public long SolveQuine()
156
163
registerCounts [ 1 ] ++ ;
157
164
break ;
158
165
case 2 : // bst (B store?)
159
- smtAssertions . Add ( $ "(assert (= { Register ( 1 , 1 ) } (bvand { combo } { Int2Bv ( 0b111 ) } )))") ;
166
+ smtAssertions . Add ( $ "(assert (= { Register ( 1 , 1 ) } (bvand { combo } { Long2Bv ( 0b111 ) } )))") ;
160
167
registerCounts [ 1 ] ++ ;
161
168
break ;
162
169
case 3 : // jnz (jump not zero)
@@ -169,15 +176,15 @@ public long SolveQuine()
169
176
else
170
177
{
171
178
// After the unrolled iterations we want the jump to fail so the loop exits
172
- smtAssertions . Add ( $ "(assert (= { Int2Bv ( 0 ) } { Register ( 0 ) } ))") ;
179
+ smtAssertions . Add ( $ "(assert (= { Long2Bv ( 0 ) } { Register ( 0 ) } ))") ;
173
180
}
174
181
break ;
175
182
case 4 : // bxc (B xor C)
176
183
smtAssertions . Add ( $ "(assert (= { Register ( 1 , 1 ) } (bvxor { Register ( 1 ) } { Register ( 2 ) } )))") ;
177
184
registerCounts [ 1 ] ++ ;
178
185
break ;
179
186
case 5 : // out (output)
180
- smtAssertions . Add ( $ "(assert (= (bvand { combo } { Int2Bv ( 0b111 ) } ) { Int2Bv ( Program [ outputs ] ) } ))") ;
187
+ smtAssertions . Add ( $ "(assert (= (bvand { combo } { Long2Bv ( 0b111 ) } ) { Long2Bv ( Program [ outputs ] ) } ))") ;
181
188
outputs ++ ;
182
189
break ;
183
190
case 6 : // bdv (B divide)
@@ -195,12 +202,17 @@ public long SolveQuine()
195
202
}
196
203
}
197
204
205
+ if ( upperBound != null )
206
+ {
207
+ smtAssertions . Add ( $ "(assert (bvult a0 { Long2Bv ( upperBound . Value ) } ))") ;
208
+ }
209
+
198
210
var smtDeclarations = registerCounts . Zip ( registerVars ) . SelectMany ( p => Enumerable . Range ( 0 , p . First + 1 ) . Select ( i => $ "(declare-const { p . Second } { i } (_ BitVec { bits } ))") ) . ToList ( ) ;
199
211
var smtTrailer = new List < string > { "(check-sat)" , "(get-model)" } ;
200
212
var smtProgram = smtDeclarations . Concat ( smtAssertions ) . Concat ( smtTrailer ) . ToList ( ) ;
201
213
202
214
// Uncomment to debug-log the generated SMT-LIB program
203
- Console . WriteLine ( string . Join ( "\n " , smtProgram ) ) ;
215
+ // Console.WriteLine(string.Join("\n", smtProgram));
204
216
205
217
using ( var process = new Process ( ) )
206
218
{
@@ -237,7 +249,7 @@ public long SolveQuine()
237
249
}
238
250
}
239
251
}
240
- throw new Exception ( "No result found" ) ;
252
+ return null ;
241
253
}
242
254
}
243
255
0 commit comments