aboutsummaryrefslogtreecommitdiff
path: root/2024/17/day17b.cpp
diff options
context:
space:
mode:
authorSebastiano Tronto <sebastiano@tronto.net>2024-12-17 08:39:11 +0100
committerSebastiano Tronto <sebastiano@tronto.net>2024-12-17 08:39:11 +0100
commita0e775b0a4805a7c1af12c1a956cd9fd74c54b2c (patch)
treeddfc21c0d865d6f871e6ffa0722747ce62077ec0 /2024/17/day17b.cpp
parent5a725f1b9e8cfbad2c31d9c220061e413adbbf8e (diff)
downloadaoc-a0e775b0a4805a7c1af12c1a956cd9fd74c54b2c.tar.gz
aoc-a0e775b0a4805a7c1af12c1a956cd9fd74c54b2c.zip
Day 17 2024 - this was fun
Diffstat (limited to '2024/17/day17b.cpp')
-rw-r--r--2024/17/day17b.cpp88
1 files changed, 88 insertions, 0 deletions
diff --git a/2024/17/day17b.cpp b/2024/17/day17b.cpp
new file mode 100644
index 0000000..499a559
--- /dev/null
+++ b/2024/17/day17b.cpp
@@ -0,0 +1,88 @@
1/*
2This solution is ad-hoc for my input.
3
4Brute force was not working, so I inspected the input. I noticed that
5the only jump instruction was at the end, jumping back to 0. So the
6program is a 'while (A != 0)' loop.
7
8Disassembling the program I got:
9
10start:
112 4 // B = A % 8
121 5 // B = B ^ 5
137 5 // C = A >> B
141 6 // B = B ^ 6
154 1 // B = B ^ C
165 5 // print B % 8
170 3 // A = A >> 3
183 0 // If A != 0 goto start
19
20Which can be rewritten as
21
22for (A = a; A != 0; A >>= 3) {
23 B1 = (A % 8) ^ 5;
24 C = A >> B1;
25 B2 = (B1 ^ 6) ^ C;
26 print(B2 % 8);
27}
28
29Where a is the value initially in register A. Here I split B in B1 and
30B2 for simplicity.
31
32What we need to do now is work out a sequence of values a_1, a_2, a_3...
33such that at step i the program prints p_i (the i-th instruction of
34the program itself, i.e. the desired input) and leaves a_{i+1} in the
35register. This is easier to do if we reason backwards: at the last step we
36want the program to print 0 and leave 0 in register A. From the equations
37above we can work out that this happens if at the second-to-last step
38the value in the A register is 3.
39
40Writing a_{i-1} = 8a_i + Y and x = B2 % 8 we have
41
42x = (B1 ^ 6) ^ (a_{i-1} >> B1) % 8 =
43 = (Y ^ 5 ^ 6) ^ (a_{i-1} >> (Y ^ 5)) % 8 =
44 = (Y ^ 3) ^ ((8*a_i+Y) >> (Y ^ 5)) % 8
45
46At each step there are multiple possible values for Y, we have to try
47them all.
48*/
49
50#include <cstdint>
51#include <iostream>
52#include <vector>
53using namespace std;
54
55uint64_t f(uint64_t a, uint64_t Y) {
56 // This is what my input program outputs at each iteration
57 // if the value in register A is 8*a+Y
58 return (Y ^ 3) ^ ((8*a + Y) >> (Y ^ 5));
59}
60
61bool tryi(const vector<uint64_t>& p, vector<uint64_t>& A, int i) {
62 if (i < 0)
63 return true;
64
65 for (uint64_t Y = 0; Y < 8; Y++) {
66 if (p[i] == f(A[i+1], Y) % 8) {
67 A[i] = (A[i+1] << 3) + Y;
68 if (tryi(p, A, i-1))
69 return true;
70 }
71 }
72
73 return false;
74}
75
76int main() {
77 // Hard-coded input
78 vector<uint64_t> p {2, 4, 1, 5, 7, 5, 1, 6, 4, 1, 5, 5, 0, 3, 3, 0};
79
80 uint64_t N {p.size()};
81 vector<uint64_t> A(N+1);
82 A[N] = 0; // Last value in the register, so the program stops
83
84 tryi(p, A, N-1);
85
86 cout << A[0] << endl;
87 return 0;
88}

Generated with cgit - Back to sebastiano.tronto.net