In my previous post, I introduced you to the Advent of Code programming challenge, and explained how I’m going through the days, solving both parts of each puzzle. Continuing on, today we have day 7. In this challenge, Santa brought little Bobby Tables a bunch of wire and bitwise logic gates. Unfortunately, Bobby needs some help in getting this all assembled. The assembly instructions (here) tell you how to hook the wires up the the gates. A signal is provided to each wire by a gate, another wire, or a specific value. Each wire can only get a signal from one source, but it can provide its signal to multiple destinations. All of the instructions are 16-bit, in the range 0-65535. The instructions are in the form:

123 -> x
456 -> y
x AND y -> d
x OR y -> e
x LSHIFT 2 -> f
y RSHIFT 2 -> g
NOT x -> h
NOT y -> i

In this example, signal 123 is provided to wire x. Signal 456 is provided to wire y. A bitwise AND is performed on x and y, and the results are sent to wire d. A bitwise OR is performed on X and Y, and the results are sent to wire e. The value of wire x is bit-shifted to the left by 2 and sent to wire f. The value of wire y is bit-shifted to the right by 2 and sent to wire g. A bitwise NOT is performed on x and sent to wire h. Finally, a bitwise NOT is performed on x and sent to wire i. The final results of these will be:

d: 72
e: 507
f: 492
g: 114
h: 65412
i: 65079
x: 123
y: 456

In SQL Server, all of these bitwise operations can be performed, some more easily than others. The directly supported bitwise operators in SQL Server are:

Operator
& (Bitwise AND)
&= (Bitwise AND EQUALS)
| (Bitwise OR)
|= (Bitwise OR EQUALS)
^ (Bitwise Exclusive OR)
^= (Bitwise Exclusive OR EQUALS)
~ (Bitwise NOT)

Did you notices that the left-shift and right-shift bitwise operations are missing? In searching for these, I found this excellent post from Adam Machanic where he shows how to perform them (please read this for an explanation of what they are and how they work), but in a nutshell the left-shift can be performed by multiplying the value by the POWER(2, x) function, where x is the number of digits to shift. The right-shift can be performed by dividing the value by POWER(2, x). For more in Adam’s series on bitmask operations, see the bitmask category on his blog.

Now, to explain the NOT operator. What is does is reverse every bit of the value. In SQL Server, all of the numeric data types are signed, so that they can also represent a negative number. However, notice above that this was specified to be an unsigned value (values 0-65535). Thus, the bitwise NOT doesn’t work the way that we would expect it to – it makes the result be a negative number. So, what we need to do is to subtract the value from 65535.

For the above operations, let’s look at how we would perform these in SQL Server:

And we can see that we get the expected results.

Okay, time to attack this challenge. What we need to determine is what is the value being returned from wire “a”. First off, we will load in the instructions:

These instructions are short enough to not need to be split into segments, so we can proceed straight to the next step, in which a temporary table is created to hold these instructions. In this query, I also determine which bitwise operation is being performed, what the destination wire is, and what the source locations are. I’m also generating a SQL statement to run to use to update the destination. All of this information, and a placeholder to store the resultant value, are all put into this temporary table.

When this is being assembled, the wires and gates are put together in a random order. It’s not until everything is connected up that the signals will flow through the wires. So, the code needs to recursively process this data until everything has been assembled, and then it can determine what the desired value is.  Additionally, and just like the last puzzle, a cursor is going to be needed so that the values assigned from one operation are available to the next one(s) that can use it. In the above code, the SQL statement that is dynamically created and that will be run in the cursor can be seen. That dynamic code needs to get and store the source values for the operations, perform the proper bitwise operation, and then update the destination with the calculation. All of these statements will be performed in the following loop, which recursively repeats until there is an output on wire a. Finally, we get the results for wire a:

For Part 2, we are to change the value being supplied to wire b from it’s currently assigned value (1674) to 46065. We need to report on the new value for wire “a”. To accomplish this, I just inserted this bit of code before the cursor code: