@link["http://adventofcode.com/day/21"]{The puzzle}. Our @link-rp["day23-input.txt"]{input} is a list of instructions representing a program for a two-register virtual machine.
@chunk[<day23>
<day23-setup>
<day23-q1>
<day23-q2>
<day23-test>]
@section{What's the value in register @tt{b} after the program runs?}
The virtual machine has two registers, @tt{a} and @tt{b}, that both start at 0. It also has six instructions:
@itemlist[
@item{@tt{hlf r} sets register r to half its current value, then continues.}
@item{@tt{tpl r} sets register r to triple its current value, then continues.}
@item{@tt{inc r} adds 1 to register r, then continues.}
@item{@tt{jmp offset} jumps the instruction that is @tt{offset} steps away. An @tt{offset} can be positive or negative.}
@item{@tt{jie r, offset} is like @tt{jmp}, but only jumps if r is even.}
@item{@tt{jio r, offset} jumps by @tt{offset} if register r = 1.}
]
Although the virtual machine has the equivalent of functions & variables, the jump instructions add a complication. We can't just evaluate the instructions top to bottom. We have to maintain a list of all the instructions, and a pointer to where we are, so if we get a jump instruction, we can move to the right place.
Because we have to repeatedly update the values of the register, it'll be more convenient to use a hash table. Overall, the solution follows the general pattern of @secref{Day_7}.
Notice also that we're encasing the lines of the VM program in @racket[thunk*]. This creates a function wrapper around each instruction so that its evaluation is delayed until we explicitly ask for it. The @racket[inst] transformer turns the lines of the program into equivalent operations on our register hash table. All these functions return a number that indicates the offset of the next instruction (if it's not a jump instruction, then this value is just 1).
With the instructions set up as functions, running the program is easy. We start at index 0 and evaluate the first instruction in our list (which will possibly update one of the registers). The result is the offset for the next instruction. We continue until our index exceeds the number of instructions available.