Introduction
Unfortunately, bitwise operators are rarely utilized in the scripts that I’ve been seeing on Quadropolis. Whether this is because their use is scarcely needed or because people just don’t know how to use them, I don’t know. However, I’d like to take this opportunity to inform you on the magic of bitwise operators. I’ll focus on cubescript, but this can sort of be expanded to many other computer languages; bitwise operators are fairly universal.
Binary System
To understand how bitwise operators work, you’ll first need to understand how a computer interprets numbers – in base-2. If you input a number in our normal base-10 system, the computer will translate it into base-2 and work with it that way. Converting numbers to and from binary (i.e. base-2) is easy, but here are the first few to give you a feel of how the system works,
0 0000
1 0001
2 0010
3 0011
4 0100
5 0101
6 0110
7 0111
8 1000
Note that if you have a zero at the start of the number, it can be omitted - I just included it to have everything line up. So, let’s say we wanted to convert 13 to a binary number, there are many algorithms to do this but essentially what we must do is write 13 as a sum of powers of 2, and then ‘concatenate’ the coefficients to obtain a base-2 number. This is what I mean,
13 = 1*(8) + 1*(4) + 0*(2) + 1*(1) = 1*(2^3) + 1*(2^2) + 0*(2^1) + 1*(2^0)
We can better visualize this by writing the right-hand side of the equality above vertically,
1*(2^3)
1*(2^2)
0*(2^1)
1*(2^0)
The vertical column of 0s and 1s tells us the value of each bits (a bit is either a 0 or a 1; binary numbers are composed of these) in the base-2 number,
13 in binary = 1101
Essentially, we are determining which powers of two are ‘turned on or off’ and expressing that by writing out a string of 1s and 0s. Now that we have that sorted, we can move on to actual bitwise operators.
‘And’ Operator: &
Not to be confused with ‘&&’, the ‘and’ bitwise operator, denoted by the single ampersand ‘&’, is the first bitwise operator that we will consider. This operator essentially determines whether both bits are 1. For example, if we wanted to use this operator on the numbers 3 and 5, we would determine the result by converting both 3 and 5 to binary and determining each bit of the result.
3 = 011
5 = 101
Working bit by bit,
0 and 1 are not both 1, so the first bit is 0,
1 and 0 are not both 1, so the second bit is 0,
1 and 1 are both 1, so the third bit is 1.
So the result is 001, which is 1 in base-10. You can try it out in cubescript, just type /echo (& 3 5), in the cubescript language the bitwise operator comes first and is followed by the two numbers, much like the ways in which addition and subtraction are done. We will return to this operator later to show how it can be used to perform some nifty tricks.
‘Or’ Operator: |
Again, not to be confused with ‘||’, the single vertical line ‘|’ is used to signify the ‘or’ operator. Unlike the ‘and’ operator, this operator will determine whether either of the bits are 1. For example, again using 3 and 5:
3 = 011
5 = 101
Working bit by bit,
Either 0 and 1 are 1, so the first bit is 1,
Either 1 and 0 are 1, so the second bit is 1,
Either 1 and 1 are 1, so the third bit is also 1.
So the result is 111, which is 7 in base-10. Again, you can try it in cubescript by issuing the command /echo (| 3 5).
'Xor' Operator: ^
Here’s yet another one. This will determine whether both bits are different. Lets try it with 3 and 5:
3 = 011
5 = 101
Working bit by bit,
0 and 1 are different, so the first bit is 1,
1 and 0 are different, so the second bit is 1,
1 and 1 are not different, so the third bit is 0.
And so we have 110, or 6 in base-10. You can verify this with /echo (^ 3 5).
'Not' Operator: ~
Don’t confuse this with ‘!’. This operator simply switches the value of each bit; it’s only used on one number as opposed to the other bitwise operators we’ve looked at which involve two numbers. Lets try it with the 3:
3 = 011
Bit by bit,
Not 0 is 1, so the first bit is 1,
Not 1 is 0, so the second bit is 0,
Not 1 is 0, so the third bit is 0.
So we would expect to get 100 or 4 in base-10. BUT, this is clearly not what we receive if you try /echo (~ 3), in fact, we actually get -4! Why? Because one bit is allocated to a +/- sign before the number, and this operator switches ALL of the bits, therefore the number changes sign as well. Here’s a fancy trick for adding 1 to the value of a variable (I used x in this case):
x = (* -1 (~ $x))
This can always be replaced with the simpler x = (+ 1 $x), but the above example is included to illustrate that these operators are far from useless, as can be seen below.
GUI Bit Fields
Arguably one of the most eloquent uses of bitwise operators in cubescript, the GUI bit field allows us to create complex scripts in which very few variables are used. These GUI elements have the following format:
guibitfield [name of bitfield] [v - variable to effect] [power of 2]
So how does it work? Well, when the bit field is turned on, the bit it corresponds to is also turned on in the variable v (above). Here’s an example:
var1 = 0;
newgui gbf [
guibitfield “GBF1” var1 1
guibitfield “GBF2” var1 2
guibitfield “GBF3” var1 4
guibitfield “GBF4” var1 8
]
We initially set var1 to 0, as you can see from above. Lets say we activate GBF2, this would in turn activate the ‘2’ bit on in var1 and so var1 would equal 2. Now, if we have GBF2 and GBF3 on, we would have turned on the ‘2’ bit and the ‘4’ bit, so var1 would equal 6. Simple enough, right? Now how can we extract this information from the value of var1? We use the ‘and’ operator. If we have GBF2 and GBF3 activated, then var1 in binary would be 110 (6 in base-10). What we really care about is finding a way to determine whether various bit fields are indeed turned on, and we can do this in the following manner:
if (& $var1 2) [echo “GBF2 is on!”]
if (& $var1 4) [echo “GBF3 is on!”]
Pretty cool, huh? Take a look at what we’re really doing (consider the first ‘if’ statement), we’re using the ‘and’ operator on var1 and 2 (number 2, not var2):
$var1 = 110
2 = 010
Notice that the '2' bit is on in both of the binary numbers above.
The only way for GBF2 to be on is if the ‘2’ bit is on in var1, and therefore (& $var1 2) is non-zero! A similar argument goes for GBF1, 3 and 4. With this, you can ‘squeeze’ many variables into one all-inclusive variable.
Well that’s my little tutorial, hope you enjoyed reading it as much as I did writing it. Please let me know if there’s anything that you want me to make more clear or elaborate on.