There has to be a more elegant way to approach solving this thing than just guessing and testing like a knuckle dragging rocks banger. Simon from Cracking the Cryptic would *never* stoop so low and who am I to question his methods? Let's have another look at the code: 0 2 4: bst a ;b = a & 7 2 1 1: bxl 1 ;b ^= 1 4 7 5: cdv b ;c = a >> b 6 1 5: bxl 5 ;b ^= 5 10 4 3: bxc ;b ^= c 12 0 3: adv 3 ;a >>= 3 14 5 5: out b ;out b & 7 16 3 0: jnz 0 ;goto 0 if a So, first thing: it's going to stop when A gets to 0, which it will do eventually because it's being shifted right 3 bits at a time and nothing is getting written back to the upper bits. Therefore, the last octal digit remaining in A is going to have zero bits all the way to its left, so it should be easy to work out what 3-bit value in A can produce any last output digit we want. The sequence we're after is the program itself: with the encodings I was given, as listed above, that's 2,4,1,1,7,5,1,5,4,3,0,3,5,5,3,0 The last digit emitted is the one that comes out when A has a nonzero value that fits in a single octal digit (it makes sense to work in octal when dealing with 3-bit shifts and a 3-bit instruction set). If pqr are the bottom 3 bits put into C by the C = A >> B step, then the rightmost 10 bits of A must always have contents as follows (. marks an unknown bit, blanks inserted for grouping by octal digit): B = 0: A = . ... ... pqr B = 1: A = . ... ..p qr. B = 2: A = . ... .pq r.. B = 3: A = . ... pqr ... B = 4: A = . ..p qr. ... B = 5: A = . .pq r.. ... B = 6: A = . pqr ... ... B = 7: A = p qr. ... ... But the number in B at that step is just the bottom 3 bits of A (which I will from now on refer to as a) xor'd with a 3 bit constant (1 for my input, see instruction at 2) which constrains those possibilities like so: B = 0: A = . ... ... 001, pqr = 001 B = 1: A = . ... ..p 000, qr = 00 B = 2: A = . ... .pq 011, r = 0 B = 3: A = . ... pqr 010 B = 4: A = . ..p qr. 101 B = 5: A = . .pq r.. 100 B = 6: A = . pqr ... 111 B = 7: A = p qr. ... 110 Constraints are good. We like constraints. Simon would approve. The digit that gets output is (a xor 1 xor 5 xor pqr) = (a xor 4 xor pqr), so we can work out what (a xor pqr) has to be to get any given output by xoring that output value with 4. And in the case of the last digit to go out, every A bit to the left of a is 0, so any of pqr that don't overlap that digit are all 0: B = 0: A = 0 000 000 001, pqr = 001 B = 1: A = 0 000 00p 000, pqr = 000 B = 2: A = 0 000 0pq 011, pqr = 000 B = 3: A = 0 000 pqr 010, pqr = 000 B = 4: A = 0 00p qr0 101, pqr = 000 B = 5: A = 0 0pq r00 100, pqr = 000 B = 6: A = 0 pqr 000 111, pqr = 000 B = 7: A = p qr0 000 110, pqr = 000 Last digit out in this instance (or any, I suspect, given that it's the operand of the JNZ instruction that loops the code back to the start) is 0, so (a xor pqr) has to be 4, which can only happen when a is 4, so all of A has to be 4. So the leftmost digit of the A value we seek has got to be 4. 4 -> 0 That puts constraints on the contents of A that generate the next digit along, the one that remains in A when it's two shifts away from stopping: B = 0: A = 0 000 100 001, pqr = 001, a xor pqr = 0 B = 1: A = 0 000 100 000, pqr = 000, a xor pqr = 0 B = 2: A = 0 000 100 011, pqr = 000, a xor pqr = 3 B = 3: A = 0 000 100 010, pqr = 100, a xor pqr = 6 B = 4: A = 0 00p 100 101, pqr = 010, a xor pqr = 7 B = 5: A = 0 0pq 100 100, pqr = 001, a xor pqr = 5 B = 6: A = 0 pqr 100 111, pqr = 000, a xor pqr = 7 B = 7: A = p qr0 100 110, pqr = 000, a xor pqr = 6 Again, any unknown pqr are still 0 at this point. Next digit that has to come out is 3, so (a xor pqr) has to be (3 xor 4 = 7), which happens when A = 45 or 47 (the b = 4 and b = 6 cases above). Using try.pl, just because it's there, confirms that both of these emit the sequence 3,0 so we've not gone wrong yet. Using s to refer to the unknown bit that distinguishes 5 from 7, we now have the following constraints on the third-last digit of A: B = 0: A = 0 100 1s1 001, pqr = 001, a xor pqr = 0 B = 1: A = 0 100 1s1 000, pqr = 100, a xor pqr = 4 B = 2: A = 0 100 1s1 011, pqr = s10, a xor pqr = s?5:1 B = 3: A = 0 100 1s1 010, pqr = 1s1, a xor pqr = s?5:7 B = 4: A = 0 100 1s1 101, pqr = 11s, a xor pqr = s?2:3 B = 5: A = 0 100 1s1 100, pqr = 001, a xor pqr = 5 B = 6: A = 0 100 1s1 111, pqr = 100, a xor pqr = 3 B = 7: A = p 100 1s1 110, pqr = 010, a xor pqr = 4 Digit coming out of that mess has to be 5, so (a xor pqr) has to be (5 xor 4 = 1), which makes A = 453. Checking with try.pl confirms 453 -> 5,3,0. Which sets up: B = 0: A = 100 101 011 001, pqr = 001, a xor pqr = 0 B = 1: A = 100 101 011 000, pqr = 100, a xor pqr = 4 B = 2: A = 100 101 011 011, pqr = 110, a xor pqr = 5 B = 3: A = 100 101 011 010, pqr = 011, a xor pqr = 1 B = 4: A = 100 101 011 101, pqr = 101, a xor pqr = 0 B = 5: A = 100 101 011 100, pqr = 010, a xor pqr = 6 B = 6: A = 100 101 011 111, pqr = 101, a xor pqr = 2 B = 7: A = 100 101 011 110, pqr = 010, a xor pqr = 4 Need a 5 to make 5,5,3,0. So a xor pqr must be 1, so A = 4532. Since p can't ever be further left than bit 9, we don't care about more than four digits and can start using a sliding window instead of listing all of them. So 532 sets up B = 0: A = xxx 101 011 010 001, pqr = 001, a xor pqr = 0, out = 4 B = 1: A = xxx 101 011 010 000, pqr = 000, a xor pqr = 0, out = 4 B = 2: A = xxx 101 011 010 011, pqr = 100, a xor pqr = 7, out = 3 <- B = 3: A = xxx 101 011 010 010, pqr = 010, a xor pqr = 0, out = 4 B = 4: A = xxx 101 011 010 101, pqr = 101, a xor pqr = 0, out = 4 B = 5: A = xxx 101 011 010 100, pqr = 110, a xor pqr = 2, out = 6 B = 6: A = xxx 101 011 010 111, pqr = 011, a xor pqr = 4, out = 0 B = 7: A = xxx 101 011 010 110, pqr = 101, a xor pqr = 3, out = 7 A = 45323 This is all very well but it's getting a bit labour intensive. #!/usr/bin/perl -p use v5.35; my $A = oct $_; for my $B (0 .. 7) { my $a = $B ^ 1; my $new_A = (($A & 0777) << 3) | $a; my $pqr = ($new_A >> $B) & 7; my $axp = $a ^ $pqr; my $out = $axp ^ 4; my $a_bits = sprintf('%012b', $new_A); substr($a_bits, $_, 0) = ' ' for (3, 7, 11); my $pqr_bits = sprintf('%03b', $pqr); say "B = $B: A = xxx $a_bits, pqr = $pqr_bits, a xor pqr = $axp, out = $out"; } $_ = ''; 4532 B = 0: A = xxx 101 011 010 001, pqr = 001, a xor pqr = 0, out = 4 B = 1: A = xxx 101 011 010 000, pqr = 000, a xor pqr = 0, out = 4 B = 2: A = xxx 101 011 010 011, pqr = 100, a xor pqr = 7, out = 3 B = 3: A = xxx 101 011 010 010, pqr = 010, a xor pqr = 0, out = 4 B = 4: A = xxx 101 011 010 101, pqr = 101, a xor pqr = 0, out = 4 B = 5: A = xxx 101 011 010 100, pqr = 110, a xor pqr = 2, out = 6 B = 6: A = xxx 101 011 010 111, pqr = 011, a xor pqr = 4, out = 0 B = 7: A = xxx 101 011 010 110, pqr = 101, a xor pqr = 3, out = 7 Seems legit. 2,4,1,1,7,5,1,5,4,3,0, 3,5,5,3,0 45323 B = 0: A = xxx 011 010 011 001, pqr = 001, a xor pqr = 0, out = 4 B = 1: A = xxx 011 010 011 000, pqr = 100, a xor pqr = 4, out = 0 < B = 2: A = xxx 011 010 011 011, pqr = 110, a xor pqr = 5, out = 1 B = 3: A = xxx 011 010 011 010, pqr = 011, a xor pqr = 1, out = 5 B = 4: A = xxx 011 010 011 101, pqr = 001, a xor pqr = 4, out = 0 < B = 5: A = xxx 011 010 011 100, pqr = 100, a xor pqr = 0, out = 4 B = 6: A = xxx 011 010 011 111, pqr = 010, a xor pqr = 5, out = 1 B = 7: A = xxx 011 010 011 110, pqr = 101, a xor pqr = 3, out = 7 Trouble: two a values fit (000, 101). Again, substitute s for the bits that make the difference: 2,4,1,1,7,5,1,5,4,3, 0,3,5,5,3,0 45323(s?5:0) B = 0: A = xxx 010 011 s0s 001, pqr = 001, a xor pqr = 0, out = 4 B = 1: A = xxx 010 011 s0s 000, pqr = s00, a xor pqr = s?4:0, out = s?0:4 B = 2: A = xxx 010 011 s0s 011, pqr = 0s0, a xor pqr = s?1:3, out = s?5:7 B = 3: A = xxx 010 011 s0s 010, pqr = s0s, a xor pqr = s?7:2, out = s?3:6 < s=1 B = 4: A = xxx 010 011 s0s 101, pqr = 1s0, a xor pqr = s?3:1, out = s?7:5 B = 5: A = xxx 010 011 s0s 100, pqr = 11s, a xor pqr = s?3:2, out = s?7:6 B = 6: A = xxx 010 011 s0s 111, pqr = 011, a xor pqr = 4, out = 0 B = 7: A = xxx 010 011 s0s 110, pqr = 001, a xor pqr = 7, out = 3 < Two values fit, a = 2 with s=1 and a = 6 that doesn't depend on s. Using t for the new difference bit, t = 0 forces s = 1, t = 1 leaves s undetermined. 2,4,1,1,7,5,1,5,4, 3,0,3,5,5,3,0 45323(t?(s?5:0)6:52) B = 0: A = xxx 011 s0s t10 001, pqr = 001, a xor pqr = 0, out = 4 < st = ?? B = 1: A = xxx 011 s0s t10 000, pqr = 000, a xor pqr = 0, out = 4 < st = ?? B = 2: A = xxx 011 s0s t10 011, pqr = 100, a xor pqr = 7, out = 3 B = 3: A = xxx 011 s0s t10 010, pqr = t10, a xor pqr = t?4:0, out = t?0:4 < st = 10 B = 4: A = xxx 011 s0s t10 101, pqr = st1, a xor pqr = t?s?2:6:0, out = t?s?6:2:4 < st = 10 B = 5: A = xxx 011 s0s t10 100, pqr = 0st, a xor pqr = t?s?7:5:6, out = t?s?3:1:2 B = 6: A = xxx 011 s0s t10 111, pqr = s0s, a xor pqr = s?2:7, out = s?6:3 B = 7: A = xxx 011 s0s t10 110, pqr = 1s0, a xor pqr = s?0:2, out = s?4:6 < st = 01 and at this point it becomes clear that just establishing leading digits, then trying out candidate last digits in order from 0 through 7 to find the lowest solution first, with occasional backtracking at dead ends, is by far the easier way to tackle this. And the backtracking will never have to cancel more than three digits, which makes it quick. Sorry, Simon.