Many times you want to use a bit of basic logic to determine what to do. Usually you want to compare two values to see if some relationship between them is true. Based on the result of this comparison, you want to do one thing or another. This is where the logic operators come in handy. There are several functions that all act relatively the same in the BasicLogic class. Essentially, they compare certain values, then return a boolean.
Let's take the
lt() function into consideration. lt returns true if the value on the left is less than the value on the right. In a typical algebra class, when comparing two numbers, you would write something like this:
x < y
Assuming x is 3 and y is 4, this statement is true. However, if we swap the values, and make x 4 and y 3, the statement is false. Written in code, it would look like this:
All the functions in the BasicLogic class return a boolean based on certain conditions. You should be familiar with the lt (less than), lte (less than or equals to), gt (greater than), gte (greater than or equals) functions from a basic algebra class that covers inequalities.
Some of the functions you may not have seen before if you haven't taken a logic or programming class are the boolean logic operators. For a full discussion of boolean logic, you may wish to read up on wikipedia for more information, however a basic treatment is covered below.
The three main operators: and, or, not are the building blocks for more complicated logic statements. These functions deal with the overall truth value of a construct, not individual bits (see the bit_and and bit_or functions).
and() returns true if all the parameters resolve to true:
and(true, true, true, true) # returns true and(true, true, false, true) # returns false
or() returns true if any of the parameters are true
or(true, false, false, false) # returns true or(false, false, false, false) # returns false
not() returns the opposite truth value of the parameter:
not(true) # returns false not(false) # returns true
xor() returns true if both parameters are different
xor(true, true) # returns false xor(false, false) # returns false xor(true, false) # returns true xor(false, true) # returns true
For convenience, there are also the nand, nor, xnor functions, which are equivalent respectively to not(and()), not(or()), and not(xor()).
The three bitwise functions bit_and, bit_or, and bit_not work similarly to
not, but they only work with integers, and they work on a binary level to determine the bitwise equivalent of two or more integers, and return that integer. Again, a full discussion of how bitwise operations work is beyond the scope of this article, but some examples are below:
bit_and(4, 7) # binary equivalent: (100, 111) returns 100 = 4 bit_and(7, 5) # binary equivalent: (111, 101) returns 101 = 5 bit_and(1, 4) # binary equivalent: (001, 100) returns 000 = 0 bit_or(1, 3) # binary equivalent: (001, 011) returns 011 = 3 bit_or(2, 4) # binary equivalent: (010, 100) returns 110 = 6 bit_not(4) # binary equivalent: (0..100) returns 1..011 = -5
Bitwise operations are useful for storing many boolean values as a single integer, among other uses. It may be useful to note that integers are stored as 64 bit two's compliment values.
urshift are also available. lshift(value, bitsToShift) is the general format for all three.
lshift(4, 2) # returns 16 urshift(10, 2) # returns 2 rshift(-10, 2) # returns -3 urshift(-10, 2) # returns 4611686018427387901 rshift(3, 1) # returns 1
Now that we have established that some conditions are true or not, we may want to do different things depending. This is where the
if() function comes in. We are creating "code branches" when we use if and other conditional statements, which means that sometimes code will not get run. The syntax of the if statements is as follows:
if(condition, code to run if true, code to run if false)
The condition and code to run if true are required, but the code to run if false is optional. If it is left off, and the condition is false, void is returned. Only one branch of code is executed here. If condition resolves to true (which may itself contain more complex code), then the second argument is evaluated and returned, otherwise the third argument is evaluated and returned. Note that the other code branch is not even evaluated. Most functions evaluate all arguments, even if they are not used, so the following code would only message the player once:
if(true, msg('Once'), msg('Twice'))
Truth value testing
Are considered true in the first argument to
- Any non-empty string
- Any number different from 0
Anything else, including —at the time of writing— Arrays, is considered false.
ifelse() function allows you to chain if statements in a more maintainable way that using if statements alone. A large if/else chain without the ifelse function would quickly get very messy. Instead, you may use this function, and in fact, you can use this function in place of any if statement as well. Let's look at basic usage first:
ifelse(val1, code1, val2, code2, val3, code3 )
In this usage, the
vals will be evaluated from top to bottom, and once the first val is true, the corresponding code will be run, and the value returned. If none of the vals are true, then ifelse will return void.
ifelse(val1, code1, val2, code2, val3, code3, #else code4 )
In this usage, we can imagine a "default" case. If at least one of the
vals is true, then it will behave the same. However, if none of the vals are true, then the final code block will be run instead. This is the final "else" clause of the statement.
A switch statement works by simplifying comparisons. Unlike ifelse, switch checks to see if some value is equal to another value, then running that code, instead of just seeing if the value itself is true. Switch statements can actually be written using ifelse, so to demonstrate, here is the same code written both ways:
assign(@value, value) ifelse(equals(@value, value1), code1, equals(@value, value2), code2, equals(@value, value3), code3, #default/"else" condition code4 ) switch(@value, value1, code1, value2, code2, value3, code3, #default code4 )
As you can see, it's a bit less code using the switch statement, but the results can be achieved either way. Sometimes you may want to do a different type of comparison, other than equals, so you have to use ifelse. As with ifelse, a "default" condition can be stated, in the event none of the given conditions are satisfied.
switch(val, test1, code1, test2, code2, test3, code3, #default defaultCode )
Sometimes you may want to run some code given that the value equals one of any number of values. In this case, you can send an array as the test parameter, and if the value equals any of the values in the array, the corresponding code is run.
#if val equals either test2, test3, or test4, code234 is run switch(val, test1, code1, array(test2, test3, test4), code234, #default defaultCode )
Though you can technically use non-string and non-integer values as the comparison types, it is not recommended, and in fact, arrays may not be used at all. When writing code, you should only use integers and strings whenever possible.