Difference between revisions of "Operators"

From Kolmafia
Jump to navigation Jump to search
imported>Efilnikufecin
 
(→‎Relational Operators: Add info on string comparisons, add approximately equal operator)
 
(48 intermediate revisions by 8 users not shown)
Line 1: Line 1:
'''if(boolean)'''
+
{{TOCright}}
 +
==Mathematical Operators==
  
determines whether to execute a code block which follows or not.
+
The following mathematical operators are used in KoLmafia:
 +
{{
 +
eztable|
 +
{{eztr|{{eztd| + |Addition|Performs addition and string concatenation}}}}
 +
{{eztr|{{eztd| - |Subtraction|Performs subtraction}}}}
 +
{{eztr|{{eztd| * |Multiplication|Performs multiplication}}}}
 +
{{eztr|{{eztd| / |Division|Performs division}}}}
 +
{{eztr|{{eztd| % |Modulo|Returns the remainder after division}}}}
 +
{{eztr|{{eztd| ** |Exponent|Performs exponentiation}}}}
 +
}}
 +
Note that, with the exception of using <nowiki>"+"</nowiki> for string concatenation, these operators can only be used on int or float datatypes.
  
<code>
+
==Bitwise Operators==
  if(true)
 
    {
 
    print("this line gets printed");
 
    }
 
  if(false)
 
    {
 
    print("this line never gets printed");
 
    } 
 
</code>
 
  
in order to create more complex if statements we need to understand the basic relational operators:
+
The following mathematical operators are used for operating on the bits of integers. The logical operators (&, |, ^) work either with booleans or integers while the others operate upon integers only. If the operands are booleans, then result will also be a boolean.
 +
{{
 +
eztable|
 +
{{eztr|{{eztd| <nowiki>&</nowiki> |and|a & b}}}}
 +
{{eztr|{{eztd| <nowiki>|</nowiki> |or|a <nowiki>|</nowiki> b}}}}
 +
{{eztr|{{eztd| <nowiki>^</nowiki> |XOR|a <nowiki>^</nowiki> b}}}}
 +
{{eztr|{{eztd| ~ |not|~a}}}}
 +
{{eztr|{{eztd| << |left shift|a << b}}}}
 +
{{eztr|{{eztd| >> |right shift|a >> b}}}}
 +
{{eztr|{{eztd| <nowiki>&=</nowiki> |and|<nowiki>a &= b --> a = a & b</nowiki>}}}}
 +
{{eztr|{{eztd| <nowiki>|=</nowiki> |or|<nowiki>a |= b --> a = a | b</nowiki>}}}}
 +
{{eztr|{{eztd| >>> |unsigned right shift|a >>> b}}}}
 +
}}
  
  <table width=95%  cellspacing=0 cellpadding=0>
+
==Assignment Operators==
    <tr>
+
The following assignment operators are used in KoLmafia (let a = left operand, b = right operand):
      <td><center><b>Relational operators</b></center></td>
+
{{
      <table width=100%  cellspacing=0 cellpadding=1>
+
eztable|
        <tr>
+
{{eztr|{{eztd| <nowiki>=</nowiki> |<nowiki>a = b</nowiki>}}}}
          <td><center><b> Operator </b></center></td>
+
{{eztr|{{eztd| <nowiki>+=</nowiki> |<nowiki>a = a + b</nowiki>}}}}
          <td><center><b> Operation </b></center></td>
+
{{eztr|{{eztd| <nowiki>-=</nowiki> |<nowiki>a = a - b</nowiki>}}}}
          <td><center><b> acceptable variable types </b></center></td>
+
{{eztr|{{eztd| <nowiki>*=</nowiki> |<nowiki>a = a * b</nowiki>}}}}
        </tr>
+
{{eztr|{{eztd| <nowiki>/=</nowiki> |<nowiki>a = a / b</nowiki>}}}}
        <tr>
+
{{eztr|{{eztd| <nowiki>%=</nowiki> |<nowiki>a = a % b</nowiki>}}}}
          <td><center> == </center></td>
+
{{eztr|{{eztd| <nowiki>**=</nowiki> |<nowiki>a = a ** b</nowiki>}}}}
          <td><center> equal to </center></td>
+
{{eztr|{{eztd| <nowiki>^=</nowiki> |<nowiki>a = a ^ b</nowiki>}}}}
          <td><center> any </center></td>
+
{{eztr|{{eztd| <nowiki>>>=</nowiki> |<nowiki>a = a >> b</nowiki>}}}}
        </tr>
+
{{eztr|{{eztd| <nowiki>>>>=</nowiki> |<nowiki>a = a >>> b</nowiki>}}}}
        <tr>
+
}}
          <td><center> != </center></td>
+
Of these, only += and = are usable for strings.  See [[Operators#Mathematical Operators|Mathematical Operators]] for information regarding the basic Mathematical Operators.
          <td><center> not equal to </center></td>
 
          <td><center> any </center></td>
 
        </tr>
 
        <tr>
 
          <td><center> < </center></td>
 
          <td><center> less than </center></td>
 
          <td><center> integer or float </center></td>
 
        </tr>
 
        <tr>
 
          <td><center> > </center></td>
 
          <td><center> greater than </center></td>
 
          <td><center> integer or float </center></td>
 
        </tr>
 
        <tr>
 
          <td><center> <= </center></td>
 
          <td><center> less than or equal to </center></td>
 
          <td><center> integer or float </center></td>
 
        </tr>
 
        <tr>
 
          <td><center> >= </center></td>
 
          <td><center> greater than or equal to </center></td>
 
          <td><center> integer or float </center></td>
 
        </tr>
 
      </table>
 
    </tr>
 
  </table>
 
  
The variable (or function results) on the right must be of the same type as is on the left. the exception to this is integer and float in which you can test an integer against a float. See [[(ASHRM) Datatype Conversions ]] for methods allowing cross type checking.
+
==Relational Operators==
  
<code>
+
To follow these examples, a basic understanding of the concepts found on [[Control Structures]] would be helpful.
  if(true == true)
 
    {
 
    print("this line gets printed");
 
    }
 
  if(false == true)
 
    {
 
    print("this line never gets printed");
 
    }
 
  if(1 == 1)
 
    {
 
    print("this line gets printed");
 
    }
 
  if(1 == 2)
 
    {
 
    print("this line never gets printed");
 
    }
 
</code>
 
  
we also need to understand Basic Boolean operators these only work with boolean:
+
In order to create more complex if statements, we need to understand the basic relational operators:
 +
{{
 +
eztable|
 +
{{eztr|{{eztd| <nowiki>==</nowiki> |equal to}}}}
 +
{{eztr|{{eztd| <nowiki>!=</nowiki> |not equal to}}}}
 +
{{eztr|{{eztd| <nowiki><</nowiki> |less than}}}}
 +
{{eztr|{{eztd| <nowiki>></nowiki> |greater than}}}}
 +
{{eztr|{{eztd| <nowiki><=</nowiki> |less than or equal to}}}}
 +
{{eztr|{{eztd| <nowiki>>=</nowiki> |greater than or equal to}}}}
 +
{{eztr|{{eztd| <nowiki>≈</nowiki> |approximately equal to}}}}
 +
}}
 +
Note that you cannot mix most datatypes within a comparison or KoLmafia will abort with an error, with the exception of mixing types int and float, where KoLmafia will do a transparent type conversion behind-the-scenes. If you need to compare different datatypes, use one or more of the [[Datatype Conversions|Datatype Conversion]] functions.
 +
{{
 +
CodeSample|
 +
code=
 +
<syntaxhighlight>
 +
if ( true == true )
 +
{
 +
  print( "This line DOES get printed." );
 +
}
 +
if ( true == false )
 +
{
 +
  print( "This line does NOT get printed." );
 +
}
 +
if ( 1 == 1.0 )
 +
{
 +
  print( "This line DOES get printed." );
 +
}
 +
if ( 1 == 2 )
 +
{
 +
  print( "This line does NOT get printed." );
 +
}
 +
if ( "Hello" == "hello" )
 +
{
 +
  print( "This line does NOT get printed." );
 +
}
 +
</syntaxhighlight>}}
  
  <table width=95%  cellspacing=0 cellpadding=0> 
+
As of [https://kolmafia.us/threads/16180-when-parsing-a-bounty-object-in-ash-make-case-insensitive-string-compariso.18981/ r16180], the equality (<code>==</code>) and inequality (<code>!=</code>) operators compare strings case-sensitively.
    <tr>
 
      <td><center><b>Boolean operators</b></center></td>
 
      <table width=100%  cellspacing=0 cellpadding=1>
 
        <tr>
 
          <td><center><b> Operator </b></center></td>
 
          <td><center><b> Operation </b></center></td>
 
        </tr>
 
        <tr>
 
          <td><center> && </center></td>
 
          <td><center> and </center></td>
 
        </tr>
 
        <tr>
 
          <td><center> || </center></td>
 
          <td><center> or </center></td>
 
        </tr>
 
        <tr>
 
          <td><center> ! </center></td>
 
          <td><center> not </center></td>
 
        </tr>
 
      </table>
 
    </tr>
 
  </table>
 
  
 +
The "approximately equal" operator (<code>≈</code>) was introduced in [https://kolmafia.us/threads/16284-add-an-ash-operator-to-perform-an-approximately-equal-comparison.19116/ r16284]. When comparing two strings, it compares them case-insensitively. When comparing other data types, it behaves like the equality operator (<code>==</code>).
  
<code>
+
{{CodeSample|
  if(true && true)
+
description=Another exception is with strings. If the '''first''' datatype is a string, and the second isn't, the latter will be silently converted into a string. Remember that strings are compared alphabetically (with the alphabet here being the characters' [https://www.asciitable.com/ ASCII value]), just like in a dictionary, in which "smaller" means "would come before".|
    {
+
code=
    print("this line gets printed because both possibilities proved true");
+
<syntaxhighlight>
    }
+
if ( "a" < "b" )
  if(false && true)
+
{
    {
+
  print( "This line DOES get printed." );
    print("this line never gets printed");
+
}
    }
+
if ( "apple" < "b" )
  if(false || true)
+
{
    {
+
  print( "This line DOES get printed." );
    print("This line gets printed because 1 of the possibilities was true");
+
}
    }
+
if ( "1" < 2 )
</code>
+
{
<Br/>
+
  print( "This line DOES get printed." );
We also need to understand operator precedence. Statements inside a () pair are always evaluated first, then from left to right.
+
}
 +
if ( "1487" < 2 )
 +
{
 +
  print( "This line DOES get printed." );
 +
}
 +
if ( "a" < 2 )
 +
{
 +
  print( "This line does NOT get printed." );
 +
}
  
<code>
+
if ( "3" == 3 )
  if(true || false && true)
+
{
    {
+
  print( "This line DOES get printed." );
    print("This line gets printed");
+
}
    //true or false is true
+
if ( "3.0" == 3 )
    //true(from true or false) and true equals true
+
{
    }
+
  print( "This line does NOT get printed." );
  if(true && (false && true))
+
}
    {
+
if ( 3 == "3" )
    print("this line never gets printed");
+
{
    //false && true is inside () so it's first and evaluates to false
+
  print( "This GENERATES AN ERROR!" );
    //true && false(from true && false) is false
+
}
    }
 
</code>
 
<Br/>
 
<Br/>
 
We also need to understand nesting if statements.
 
  
<code>
+
if ( "true" == true )
  if(true)
+
{
    {
+
  print( "This line DOES get printed." );
    if(true)
+
}
      {
+
</syntaxhighlight>|
      print("this line gets printed");
+
moreinfo=Take the habit of always converting your datatypes to avoid unexpected problems.}}
      }
+
 
      else
+
==Boolean Operators==
      {
+
{{
      print("this line never gets printed");  
+
eztable|
      }     
+
{{eztr|{{eztd| <nowiki>&&</nowiki> |and}}}}
    print("this line gets printed also");
+
{{eztr|{{eztd| <nowiki>||</nowiki> |or}}}}
    }
+
{{eztr|{{eztd| <nowiki>!</nowiki> |not}}}}
  if(false)
+
}}
    {
+
Note that the above operators only work with boolean values & datatypes. To make use of them with other datatypes, you will either need to first perform a [[Datatype Conversions|Datatype Conversion]], or you will need to nest your operations such that a boolean value is used with the boolean operators.
    if(true)
+
{{
      {
+
CodeSample|
      print("this line never gets printed");
+
code=
      //though inside an if(true) statement,
+
<syntaxhighlight>
      //the outer if(false) stops the code from ever getting here.
+
if ( true && true )
      }
+
{
      else
+
  print( "This line DOES get printed (both possibilities proved true)." );
      {
+
}
      print("this line never gets printed");  
+
if ( true && false )
      }
+
{
    print("this line never gets printed");
+
  print( "This line does NOT get printed (only one possibility proved true)." );
    }
+
}
</code>
+
if ( true || false )
<Br/>
+
{
<Br/>
+
  print( "This line DOES get printed (since at least one of the possibilities proved true)." );
Now you only need to put it all together as needed for your situation.
+
}
 +
if ( ! false )
 +
{
 +
   print( "This line DOES get printed (since the not operator converted false to true)." );
 +
}
 +
</syntaxhighlight>}}
 +
 
 +
====Notes====
 +
ASH uses [https://en.wikipedia.org/wiki/Short-circuit_evaluation Short-circuit_evaluation].<br>
 +
What this means is that in both of these examples, expensive_function() is not evaluated (i.e. is skipped):
 +
 
 +
{{
 +
CodeSample|
 +
code=
 +
<syntaxhighlight>
 +
if ( false && expensive_function() ) {
 +
  ...
 +
}
 +
</syntaxhighlight>}}
 +
{{
 +
CodeSample|
 +
code=
 +
<syntaxhighlight>
 +
if ( true || expensive_function() ) {
 +
  ...
 +
}
 +
</syntaxhighlight>}}
 +
 
 +
==Operator Precedence==
 +
 
 +
KoLmafia follows [http://download.oracle.com/javase/tutorial/java/nutsandbolts/operators.html Java's Operator Precedence rules] with a few exceptions.
 +
 
 +
(The exceptions being operators that exist in only one or the other; operators that exist in both have the same precedence in both.)
 +
 
 +
{{
 +
eztable|
 +
{{eztr|{{eztd|14| <nowiki>(reserved for postfix ++ and --)</nowiki> }}}}
 +
{{eztr|{{eztd|13| <nowiki>! ~ contains remove (reserved for prefix ++ and --)</nowiki> }}}}
 +
{{eztr|{{eztd|12| <nowiki>**</nowiki> }}}}
 +
{{eztr|{{eztd|11| <nowiki>* / %</nowiki> }}}}
 +
{{eztr|{{eztd|10| <nowiki>+ -</nowiki> }}}}
 +
{{eztr|{{eztd| 9| <nowiki><< >> >>></nowiki> }}}}
 +
{{eztr|{{eztd|8| <nowiki>< > <= >=</nowiki> }}}}
 +
{{eztr|{{eztd|7| <nowiki>== !=</nowiki> }}}}
 +
{{eztr|{{eztd|6| <nowiki>&</nowiki> }}}}
 +
{{eztr|{{eztd|5| <nowiki>^</nowiki> (xor) }}}}
 +
{{eztr|{{eztd|5| <nowiki>|</nowiki> }}}}
 +
{{eztr|{{eztd|3| <nowiki>&&</nowiki> }}}}
 +
{{eztr|{{eztd|2| <nowiki>||</nowiki> }}}}
 +
{{eztr|{{eztd|1|(reserved for <nowiki>?:</nowiki>(ternary conditional))}}}}
 +
{{eztr|{{eztd|0| (reserved for assignments)}}}}
 +
}}
 +
 
 +
Statements inside a () pair are always evaluated first, then in order of precedence as listed above (highest number precedence first), then left-to-right.
 +
{{
 +
CodeSample|
 +
code=
 +
<syntaxhighlight>
 +
if ( true || true && false )
 +
{
 +
  print( "This line DOES get printed." );
 +
  // && has highest precedence
 +
  // true or (true && false) returns true
 +
}
 +
if ( ( true && false ) && true )
 +
{
 +
  print( "This line does NOT get printed." );
 +
  // ( true && false ) is evaluated first since it is inside of parentheses
 +
  // so we end up evaluating ( false && true ) which returns false
 +
}
 +
if ( true && ! ( true && false ) )
 +
{
 +
  print( "This line DOES get printed." );
 +
  // ( true && false ) is evaluated first since it is inside of parentheses
 +
  // the ! operator converts the false from ( true && false ) to true
 +
  // ( true && true ) returns true
 +
}
 +
</syntaxhighlight>}}
 +
[[Category:Scripting]]

Latest revision as of 06:30, 28 July 2021

Mathematical Operators

The following mathematical operators are used in KoLmafia:

+ AdditionPerforms addition and string concatenation
- SubtractionPerforms subtraction
* MultiplicationPerforms multiplication
/ DivisionPerforms division
 % ModuloReturns the remainder after division
** ExponentPerforms exponentiation

Note that, with the exception of using "+" for string concatenation, these operators can only be used on int or float datatypes.

Bitwise Operators

The following mathematical operators are used for operating on the bits of integers. The logical operators (&, |, ^) work either with booleans or integers while the others operate upon integers only. If the operands are booleans, then result will also be a boolean.

& anda & b
| ora | b
^ XORa ^ b
~ not~a
<< left shifta << b
>> right shifta >> b
&= anda &= b --> a = a & b
|= ora |= b --> a = a | b
>>> unsigned right shifta >>> b


Assignment Operators

The following assignment operators are used in KoLmafia (let a = left operand, b = right operand):

= a = b
+= a = a + b
-= a = a - b
*= a = a * b
/= a = a / b
 %= a = a % b
**= a = a ** b
^= a = a ^ b
>>= a = a >> b
>>>= a = a >>> b

Of these, only += and = are usable for strings. See Mathematical Operators for information regarding the basic Mathematical Operators.

Relational Operators

To follow these examples, a basic understanding of the concepts found on Control Structures would be helpful.

In order to create more complex if statements, we need to understand the basic relational operators:

== equal to
 != not equal to
< less than
> greater than
<= less than or equal to
>= greater than or equal to
approximately equal to

Note that you cannot mix most datatypes within a comparison or KoLmafia will abort with an error, with the exception of mixing types int and float, where KoLmafia will do a transparent type conversion behind-the-scenes. If you need to compare different datatypes, use one or more of the Datatype Conversion functions.

if ( true == true )
{
   print( "This line DOES get printed." );
}
if ( true == false )
{
   print( "This line does NOT get printed." );
}
if ( 1 == 1.0 )
{
   print( "This line DOES get printed." );
}
if ( 1 == 2 )
{
   print( "This line does NOT get printed." );
}
if ( "Hello" == "hello" )
{
   print( "This line does NOT get printed." );
}


As of r16180, the equality (==) and inequality (!=) operators compare strings case-sensitively.

The "approximately equal" operator () was introduced in r16284. When comparing two strings, it compares them case-insensitively. When comparing other data types, it behaves like the equality operator (==).

Another exception is with strings. If the first datatype is a string, and the second isn't, the latter will be silently converted into a string. Remember that strings are compared alphabetically (with the alphabet here being the characters' ASCII value), just like in a dictionary, in which "smaller" means "would come before".

if ( "a" < "b" )
{
   print( "This line DOES get printed." );
}
if ( "apple" < "b" )
{
   print( "This line DOES get printed." );
}
if ( "1" < 2 )
{
   print( "This line DOES get printed." );
}
if ( "1487" < 2 )
{
   print( "This line DOES get printed." );
}
if ( "a" < 2 )
{
   print( "This line does NOT get printed." );
}

if ( "3" == 3 )
{
   print( "This line DOES get printed." );
}
if ( "3.0" == 3 )
{
   print( "This line does NOT get printed." );
}
if ( 3 == "3" )
{
   print( "This GENERATES AN ERROR!" );
}

if ( "true" == true )
{
   print( "This line DOES get printed." );
}

Take the habit of always converting your datatypes to avoid unexpected problems.


Boolean Operators

&& and
|| or
 ! not

Note that the above operators only work with boolean values & datatypes. To make use of them with other datatypes, you will either need to first perform a Datatype Conversion, or you will need to nest your operations such that a boolean value is used with the boolean operators.

if ( true && true )
{
   print( "This line DOES get printed (both possibilities proved true)." );
}
if ( true && false )
{
   print( "This line does NOT get printed (only one possibility proved true)." );
}
if ( true || false )
{
   print( "This line DOES get printed (since at least one of the possibilities proved true)." );
}
if ( ! false )
{
   print( "This line DOES get printed (since the not operator converted false to true)." );
}


Notes

ASH uses Short-circuit_evaluation.
What this means is that in both of these examples, expensive_function() is not evaluated (i.e. is skipped):


if ( false && expensive_function() ) {
   ...
}


if ( true || expensive_function() ) {
   ...
}


Operator Precedence

KoLmafia follows Java's Operator Precedence rules with a few exceptions.

(The exceptions being operators that exist in only one or the other; operators that exist in both have the same precedence in both.)

14 (reserved for postfix ++ and --)
13 ! ~ contains remove (reserved for prefix ++ and --)
12 **
11 * / %
10 + -
9 << >> >>>
8 < > <= >=
7 == !=
6 &
5 ^ (xor)
5 |
3 &&
2 ||
1(reserved for ?:(ternary conditional))
0 (reserved for assignments)


Statements inside a () pair are always evaluated first, then in order of precedence as listed above (highest number precedence first), then left-to-right.

if ( true || true && false )
{
   print( "This line DOES get printed." );
   // && has highest precedence
   // true or (true && false) returns true
}
if ( ( true && false ) && true )
{
   print( "This line does NOT get printed." );
   // ( true && false ) is evaluated first since it is inside of parentheses
   // so we end up evaluating ( false && true ) which returns false
}
if ( true && ! ( true && false ) )
{
   print( "This line DOES get printed." );
   // ( true && false ) is evaluated first since it is inside of parentheses
   // the ! operator converts the false from ( true && false ) to true
   // ( true && true ) returns true
}