AoC 2021 D24: Arithmetic Logic Unit
| Problem statement | Source code | Tags: VMManual inspectionPuzzle
← Previous Back to AoC Index Next →
Part 1
This is a question type I enjoy a lot: there's more pen-and-paper (or, for me, iPad and typing in a text file) than coding.
I tried to formally work out the required input range, using Hoare logic to symbolically deduce the weakest precondition for each line of code, given that the postcondition is z = 0. This is actually feasible given that no loops exist. I even have a solution that I believe works; the problem is that the branching still leads to an exponential number of paths, and Node OOMs. So I was forced back to manual inspection.
The program has 14 chunks, each of the form:
Among the 14 chunks, only lines 5, 6, 16 may be different in their constant. In particular, <n0> can either be 1 or 26; <n1> can be between -15 and 15; <n2> can be between 1 and 14. Furthermore, n1 <= n0 iff n0 == 26.
If we convert this to TypeScript:
More compactly:
Note that while n1 can be negative, all other numbers are always positive, including z.
This is using z as a stack in base-26:
- If
z.top() == w - n1andn0 == 26, thenz.pop(). - If
z.top() == w - n1andn0 == 1, then do nothing. - If
z.top() != w - n1andn0 == 1, thenz.push(w + n2). - If
z.top() != w - n1andn0 == 26, thenz.replaceTop(w + n2).
The goal at the end is to have z empty, and we have 7 n0 == 1 chunks and 7 n0 == 26 chunks, so we need to pop every time we can. We can pair up each push-chunk and pop-chunk, such that w_push + n2_push == w_pop - n1_pop. This creates 7 equations, each of the form w[i] - w[j] = n where i > j.
Because we want to maximize w, we can just greedily maximize each w[i], since these equations are independent of each other. If w[i] - w[j] = n, then when n is positive, set w[i] = 9 and w[j] = 9 - n; when n is negative, set w[j] = 9 and w[i] = 9 + n.
Part 2
Exactly the same, except we minimize w instead of maximizing it. In this case we want w[i] and w[j] as close to 1 as possible.