Boolean expressions grammar - mouton5000/DiscreteEventApplicationEditor GitHub Wiki

This is how you should write the boolean expressions in each arc of the graph. The boolean expression of the arc is read and interpreted by the tokens in the input node at the current frame. The token goes through that arc if and only if the expression is interpreted as true (see the General overview page for more information).

The true-false value of the expression depends on what is true and what is false at the current frame. The "what" is called a property or an event (see the corresponding sections).

For example, if we know that I like pizza and you do not, then we have one property, pLikePizza, telling us who likes pizza. The following expressions should be interpreted this way :

  • pLikePizza('me') should be true
  • pLikePizza('me') and pLikePizza('you') should be false
  • pLikePizza('me') or pLikePizza('you') should be true

Warning : note that the keywords have no capital letter.

Evaluations

An expression can contain variables (in capital letters like X or VAR1). A variable can be evaluated, which means that we give a value to it. When an expression is false, it means that, regardless of the value of the variables of the expression, this expression is false. When the expression may be true, every evaluation of the variables that make the expression true is returned. (Then the token moves and, for each evaluation, applies some consequences like "Draw a circle here", "move that sprite there", "add a token in that part of the graph",... See the related page for more information).

If the expression is true but no variable was evaluated, an empty evaluation is returned. If the expression is false, no evaluation is returned and the token does not move through that arc.

Before the expression is interpreted, some variable may possibly have an evaluation. We denote this evaluation as the input evaluation. Usually, the input evaluation is empty. If the expression is true but no variable was evaluated, the input evaluation is returned.

For instance, if we consider the previous pizza example:

  • pLikePizza(X) should be true
  • X is 'me' and pLikePizza(X) should be true
  • pLikePizza(X) and pLikePizza(Y) and X != Y should be true if there exists two distinct people that like pizza.

true-false

In the expressions, you can use true and false directly. Obviously :

  • true is interpreted as true and the input evaluation is returned.
  • false is interpreted as false.

Boolean operators

You can also use classic boolean operators : and, or, not.

If E1 and E2 are two boolean expressions, then:

  • E1 or E2 is true if and only if E1 or E2 is true and the union of the evaluations returned by E1 and E2 is returned.
  • E1 and E2 is true if and only if
  1. E1 is true
  2. for each evaluation EVAL returned by E1, E2 is true when the input evaluation is EVAL. The returned evaluation is the list of evaluations returned by E2.
  • not E1 is true if and only if E1 is false, and the input evaluation is returned.

Arguments (Arithmetic expressions)

Some operators uses arguments. Those arguments may be constants, variables or mathematical expressions.

Constants arguments

Those arguments may be :

  • positive integers ; 0, 1, 49
  • positive floats : 0.1, 12.34
  • strings surounded by two simple quotes ; 'something' (containing anything but a single quote, no escaping is currently possible)
  • mathematical constants : pi or e

Variables

A variable is described by a name with capital letters, digits or an underscore. It has to begin with a capital letter. For example : X, Y23, ThisIsAVariable, THIS_IS_TOO

Generally a variable has a value depending on what is true and what is false at the current frame. See Properties and Events.

Global values

Three global values can be used in an arithmetic expression : the current fps, the width and the height of the screen.

  • globals('fps') equals the current number of fps
  • globals('screenWidth') equals the current width of the window
  • globals('screenHeight') equals the current height of the window

Mathematical operators

If A1 and A2 are expressions which value is a number, you can use the following operators :

  • addition : A1 + A2
  • substraction : A1 - A2 or -A1
  • multiply : A1 * A2
  • divide : A1 / A2
  • divide integer : A1 // A2
  • modulo : A1 % A2
  • power : A1 ** A2
  • mathematical number functions : cos(A1), sin(A1), tan(A1), exp(A1), log(A1), abs(A1), sign(A1), floor(A1), ceil(A1), round(A1), acos(A1), asin(A1), atan(A1), sh(A1), ch(A1), th(A1), ash(A1), ach(A1), ath(A1), rand(A1) and randint(A1)

If A1 and A2 are expressions which value is a string, you can use the following operators :

  • concatenation : A1 + A2
  • length : len(A1)

The concatenation works also if A1 is a string and A2 is a number, and conversely.

Parenthesis

You can surround any argument by two parenthesis to evaluate this argument before others, overriding the operator priority. For example : (A1 + A2) * A3 is equivalent as A1 * A3 + A2 * A3

Comparison operators

If A1 and A2 are two arithmethical expressions (possibly strings expressions) then one can use the following operators :

  • A1 >= A2.
  • A1 > A2.
  • A1 <= A2.
  • A1 < A2.
  • A1 == A2.
  • A1 != A2 (test if A1 and A2 are not equals, similar to not(A1 == A2)).

Properties and events

What can be called the truth database contains the list of true properties and events and is stored somewhere (which is not really important). A property or an event that is not in the truth database is false, an conversely.

At then end of each frame, each event is deleted from the database. On the contrary, a property is true until it is removed from the database.

A property or an event is described by a name, some arguments and some keyword arguments. Usually, a property remains true during many frames whereas an event is true only during one frame.

The boolean expression of an arc can test if a property or an event is true.

Properties and events expressions grammar

To distinguish the properties and the events, a property name starts with 'p' and an event name starts with 'e'. Then the name contains one capital letter, and then any number (including 0) of alpha numerical character. For example pIsTall, pIsGreaterThan, eMouse2Click, ... Then a property or an event contains a list of arguments and keyword arguments.

  • pNameOfTheProperty(A1, A2, ..., An, B1 = C1, B2 = C2, ..., Bm = Cm), where Bi are arithmetic expressions and where Ai and Ci are unevaluated variables or arithmetic expressions, is interpreted as "Is there one or more properties in the truth database with name NameOfTheProperty, with n arguments such that either Ai is an arithmetic expression and the i-th argument is the value of the Ai or Ai is an unevaluated variable that is evaluated with the i-th argument, and such that, for each 1<=j<=m, the property contains a keyword argument such that the key is the value pf Bj and either Cj is an arithmetic expression and the argument is the value of Cj or Cj is an unevaluated variable that is evaluated with the argument?". For each possible evaluation of the unevaluated variables, the union of that evaluation and the input evaluation is returned.
  • eNameOfTheProperty(A1, A2, ..., An, B1 = C1, B2 = C2, ..., Bm = Cm) is interpreted the same for events instead of properties.

Note that the expression must contain the same number of arguments (here n arguments) than the property/event it is testing but the number of keyword arguments (here m keyword arguements) can be lower than the number of keyword arguments of the property/event. We also point out that, although it does not seem useful, one can check the same keyword argument multiple times.

Example : Check if a property with arguments is true

Assuming the database contains a property storing the name and the level of a hero (check the consequences grammar to know how to store and delete a property from the database). Let say that the property is named 'Hero' and that the two arguments are successively the name and the number of the level of the hero.

For example, if the hero called 'Kolji' is level 2 and the hero called 'Nima' is level 5 then

  • pHero('Kolji', 2) is true. The input evaluation is returned.
  • pHero('Kolji', 1+1) is true. The input evaluation is returned.
  • pHero('Kolji', 5) is false.
  • pHero('Kolji', 2) and pHero('Nima', 2+3) is true. The input evaluation is returned.
  • pHero('Kolji', 'Nima') is false.

Note that the arguments must be in the right order :

  • pHero(5, 'Nima') is false.

Note that if an argument is missing , the expression is false :

  • pHero('Kolji') is false.

Check if a property with keyword arguments is true

For example, assuming the database contains the statistics of a hero. Let say that the property is named 'Stat' and that it contains one argument, the name of the hero, and 4 keyword arguments, the attack with keyword 'ATK', the defense with keyword 'DEF', the agility with keyword 'AGI' and the luck with keyword 'LCK'.

If the hero is named Kolji and if its 4 statistics are respectively 10, 4, 8 and 3 then:

  • pStat('Kolji', 'ATK'=10, 'DEF'=4, 'AGI'=8, 'LCK'=3) is true. The input evaluation is returned.
  • pStat('Kolji', 'AT'+'K'=10, 'DEF'=2+2, 'AGI'=4*2, 'LCK'=3) is true. The input evaluation is returned.
  • pStat('Kolji', 10, 4, 8, 3) is false, because the property contains 1 argument and 4 keyword arguments and this expression check the existence of a property with 5 arguments.
  • pStat('Kolji', 'ATK'=8, 'DEF'=4, 'AGI'=8, 'LCK'=3) is false.
  • pStat('Kolji', 'ATK'='10', 'DEF'=4, 'AGI'=8, 'LCK'=3) is false.

Note that the keyword arguments can be in any order:

  • pStat('Kolji', 'LCK'=3, 'AGI'=8, 'ATK'=10, 'DEF'=4) is true. The input evaluation is returned.

Note that a keyword argument can be missing, contrary to the other arguments:

  • pStat('Kolji', 'AGI'=8, 'LCK'=3) is true. The input evaluation is returned.
  • pStat('Kolji') is true. The input evaluation is returned.
  • pStat('AGI'=8, 'LCK'=3) is false.

Note that a keyword argument can be checked multiple times:

  • pStat('Kolji', 'AGI'=8, 'AGI'=5+3) is true. The input evaluation is returned.

Harder example : using variables

We assume the input evaluation is empty.

Assuming now you have a property 'Level' storing the level of the main character. You want to check if it is less or equal to 3, you could use the following expression :

  • pLevel(1) or pLevel(2) or pLevel(3).

This is acceptable, but what if you want to check if the level is less than 50? You should use a variable as in the following example

  • pLevel(X) and X <= 50.

The system checks if at least one property in the database is named "Level". Then, it checks if, among the "Level" properties, at least one contains one argument. For each of those properties, X is evaluated with that argument (it has the same value) and X <= 50 is tested. If X is an integer and less than 50 for at least one of its values, the expression is true and the evaluation of X is returned (thus more than one evaluation can be returned). It works as in the Prolog language.

For example, if pLevel(1), pLevel(37) and pLevel(54) are true, then

  • pLevel(X) and X <= 50 is true and two evaluations of X are returned : X = 1 and X = 37.
  • pLevel(X) and X <= 28 is true and one evaluation of X is returned : X = 1.
  • pLevel(X) and X <= -1 is false.

A variable can be used in an arithmetic expression if and only if it was previously evaluated with an argument of a property or an event.

If the database stores, for each city in the world, the GPS coordinates as in the following example : pCoord('Paris',48,2). You want to check if there is at least one city for which the latitude equals the longitude divided by 2.

  • pCoord(C,Lat,2*Lat) returns true if such a city exists. For each of those cities, C is evaluated with the name of that city and Lat is evaluated with the latitude. Each evaluation of C and Lat is then returned.

You cannot use an arithmetic expression containing a variable if that variable is not evaluated : pCoord(C,Long/2,Long) is false as Long has no value when Long/2 is evaluated.

It would also be possible to use the following expression:

  • pCoord(C,Lat,Long) and Long == 2 * Lat.

The unnamed argument : ignore an argument

You can use the unnamed argument _ to ignore an argument or a keyword argument. This means 'whatever is this value, the property/event is true'.

We assume the database stores a list of atoms with a property named "Atom", with one argument, the name of the atom, and two keyword arguments, its atomic number with keyword 'atnb' and its molar mass with keyword 'mm'. For example, it contains pAtom('Carbon 12', 'atnb' = 6, 'mm' = 12).

  • pAtom(_, 'atnb' = 18, 'mm' = 40) is true and returns the input evaluation if there is an atom with atomic number 18 and molar mass 40, whatever its name is.

Even if this is not necessary, this unnamed argument can also be used for keyword arguments.

  • pAtom(NAME, 'atnb' = _, 'mm'=1), which is true and returns the evaluation (NAME = 'Hydrogen1').

This is equivalent to

  • pAtom(NAME, 'mm'=1).

You cannot use the unnamed argument as the key of a keyword argument.

  • pAtom(NAME, _ = 6) is not a valid expression.

Copy of the same evaluation

The unnamed argument and the keyword arguments may cause an evaluation to be returned twice.

For example, if the input evaluation is empty and if the database contains the properties pNeighbors('Paul', 'Math') and pNeighbors('Paul', 'Jack'):

  • pNeighbors(X, _) is true and returns twice the same evaluation : (X = 'Paul') and (X = 'Paul').

If the input evaluation is empty and if the database contains the properties pAge('Name' = 'Paul', 'Age' = 20) and pAge('Name' = 'Jack', 'Age' = 20):

  • pAge('Age' = 20) is true and returns twice the empty input evaluation.
  • pAge('Age' = X) is true and returns twice the same evaluation (X = 20) and (X = 20).

The id keyword

Each property or event is associated with a unique identifier that can be used to quickly identify, edit and remove it later (see also the Consequences Grammar page). This id can be obtained by identifying a variable with the id keyword argument of the property or the event as in the following example.

  • pAge('Age' = X, id = ID)

Note that the id key is not surroundded by two quotes.

Graphics properties

Those properties works the same as the events and classic properties, except that those properties refer to the graphics elements : sprites, lines, ellipses, rectangles, polygons and texts.

Those properties have some exclusive keywords that can be used to check the property of the graphics elements associated with. It is also possible to use the id keyword argument with those properties.

Sprites

A sprite property name starts with 'gs' and is associated with a sprite drawn on the screen. Then, as for the events and the properties the name contains one capital letter, and then any number (including 0) of alpha numerical character. For example gsHero, gsTREE, ... Finally, it contains also a list of arguments and keyword arguments.

The exclusive keywords of the sprite properties are:

  • filename for the name of the file of the sprite.
  • x for the abscissa.
  • y for the ordinate.
  • z for the z-index.
  • rotate for the rotation angle of the sprite.
  • scale for the scaling parameter of the sprite. There is no quotes surrounding those keywords.

For example,

  • gsHero(22, 'Level' = 12, x = X, y = Y) is true if there is a sprite on the screen named Hero with 1 argument of value 22 and one keyword argument of key 'Level' and value 12. The evaluation then associates X and Y respectively with the abscissa and the ordinate of the sprite.

Lines

A line property name starts with 'gl' and is associated with a line drawn on the screen. Then the name contains one capital letter, and then any number (including 0) of alpha numerical character. For example glWall, glSeparator, ... Finally, it contains also a list of arguments and keyword arguments.

The exclusive keywords of the line properties are:

  • x1 for the abscissa of the first point.
  • y1 for the ordinate of the first point.
  • x2 for the abscissa of the second point.
  • y2 for the ordinate of the second point.
  • z for the z-index of the line.
  • width for the width of the line.
  • color for the color of the line. There is no quotes surrounding those keywords.

Oval

An oval property name starts with 'go' and is associated with an oval or a circle drawn on the screen. Then the name contains one capital letter, and then any number (including 0) of alpha numerical character. For example goSun, goHead, ... Finally, it contains also a list of arguments and keyword arguments.

The exclusive keywords of the oval properties are:

  • x for the abscissa of the center.
  • y for the ordinate of the center.
  • w for the width of the oval.
  • h for the height of the oval.
  • z for the z-index of the oval.
  • width for the width of the oval.
  • color for the color of the oval. There is no quotes surrounding those keywords.

Rectangles

A rectangle property name starts with 'gr' and is associated with a rectangle drawn on the screen. Then the name contains one capital letter, and then any number (including 0) of alpha numerical character. For example grHouse, grBox, ... Finally, it contains also a list of arguments and keyword arguments.

The exclusive keywords of the rectangle properties are:

  • x for the abscissa of the upperleft corner.
  • y for the ordinate of the upperleft corner.
  • w for the width of the rectangle.
  • h for the height of the rectangle.
  • z for the z-index of the rectangle.
  • width for the width of the rectangle.
  • color for the color of the rectangle. There is no quotes surrounding those keywords.

Polygons

A polygon property name starts with 'gp' and is associated with a polygon drawn on the screen. Then the name contains one capital letter, and then any number (including 0) of alpha numerical character. For example gpTemple, gpRock, ... Finally, it contains also a list of arguments and keyword arguments.

The exclusive keywords of the polygon properties are:

  • xi, where i is an integer, for the abscissa of the i-th point of the polygon.
  • yi, where i is an integer, for the ordinate of the i-th point of the polygon.
  • z for the z-index of the polygon.
  • width for the width of the polygon.
  • color for the color of the polygon.

There is no quotes surrounding those keywords.

Texts

A text property name starts with 'gt' and is associated with a text drawn on the screen. Then the name contains one capital letter, and then any number (including 0) of alpha numerical character. For example gtScore, gtName, ... Finally, it contains also a list of arguments and keyword arguments.

The exclusive keywords of the text properties are:

  • text for the text that is currently displayed on the screen.
  • x for the abscissa of the text.
  • y for the ordinate of the text.
  • z for the z-index of the text.
  • color for the color of the text.
  • fontName for the name of the font of the text.
  • fontSize for the size of the font of the text.

There is no quotes surrounding those keywords.

The is operator : manually evaluate a variable

If X is a variable and A is an arithmetic expression, then

  • X is A is interpreted as true and an evaluation where X is evaluated with the value of A is returned.

If you need/want to evaluate a variable, you can do it manually with the ˋisˋ operator :

  • X is 23 is true and an evaluation where X is evaluated with 23 is returned.
  • pLevel(X) and Y is X + 1 is true if pLevel(X) is true and, for each evaluation V of X, an evaluation where X is evaluated with V and Y with V+1 is returned.
  • Z is 'Bob'+1 is true and X is evaluated with 'Bob1'.

The ˋisˋ operator erases the previous evaluation of a variable if it exists.

  • ˋX is 2 and X is 3ˋ is true and X is evaluated with 3.

** Do not use = to evaluate a variable with a value**

The del operator : unevaluate a variable

The del operator lets you undo the evaluation of a variable. This variable can then be evaluated with an other value. For instance, if pTomatoes(3) and pPotatoes(4) are true, then

  • pTomatoes(X) and pPotatoes(X) is false
  • pTomatoes(X) and del X and pPotatoes(X) is true and X is evaluated with 4.

The timer operator : wait

Each token has a counter. At each frame, the token tries to move to another node through an arc. If it does, the counter is reset to 0. Otherwise, at the end of the frame, the counter is increased by one.

You can use the timer operator to wait during some frames before the expression becomes true.

  • timer(A), where A is an arithmetic expression, is interpreted as true if the token trying to go through the arc has tried a number of times which equals the value of A. The input evaluation is returned.

The evaluation operators

Some operators, anyEval, randomEval, uniqueEval, minEval, maxEval, take an expression as an argument and modify the evaluation returned by the interpretation of that expression.

For example, in a pokemon like game, when two bad guys see the hero, only one of them attacks (the second one attacks after the first battle ends). Lets say that a property named BadGuy with three arguments, the ID of the ennemy and its coordinates, is true if the bad guy with that ID located at those coordinates sees the hero, and that pBadGuy(1,10, 10), pBadGuy(2,20, 20) and pBadGuy(3,20, 5) are true:

  • pBadGuy(_, X, Y) returns true and three evaluations are returned : (X = 10, Y = 10), (X = 20, Y = 20) and (X = 20, Y = 5).

We use this example for each of the operators.

The any evaluation

The anyEval operator is useful when you need only one evaluation, any evaluation.

If E is a boolean expression then

  • anyEval(E) is true if E is true and the first evaluation returned by E is returned.

For example

  • anyEval(pBadGuy(_, X, Y)) returns true and one evaluation is returned : (X = 10, Y = 10).

The random evaluation

If E is a boolean expression then

  • randomEval(E) is true if E is true and a random evaluation returned by E is returned.

For example

  • randomEval(pBadGuy(_, X, Y)) returns true and one of those evaluations is choosen and returned with probability 1/3 : (X = 10, Y = 10), (X = 20, Y = 20) or (X = 20, Y = 5).

The unique evaluation

The interpretation of an expression may returns multiple times the same evaluation due to the unnamed argument and keyword arguments. The unique evaluation removes every dupplicates.

If E is a boolean expression then

  • uniqueEval(E) is true if E is true and the list of every distinct evaluation returned by E is returned.

For example

  • pBadGuy(_, X, _) returns true and three evaluations are returned : (X = 10), (X = 20) and (X = 20).
  • uniqueEval(pBadGuy(_, X, _)) returns true and two evaluations are returned : (X = 10) and (X = 20).

The minimum and the maximum evaluation

If E is a boolean expression and A is an arithmetic expression then

  • minEval[A](E) is true if E is true and the first evaluation returned by E minimizing the value of A is returned.
  • maxEval[A](E) is true if E is true and the first evaluation returned by E maximizing the value of A is returned.

For example

  • minEval[Y](pBadGuy(_, X, Y)) returns true and one evaluations are returned : (X = 20, Y = 5).
  • maxEval[Y](pBadGuy(_, X, Y)) returns true and one evaluations are returned : (X = 20, Y = 20).
  • minEval[ID * Y](pBadGuy(ID, X, Y)) returns true and one evaluations are returned : (ID = 1, X = 10, Y = 10).

Comments

There are two categories of comments.

  • the python like comments starting with # and ending at the end of the line
  • the C like comments starting with /* and ending with */.

You cannot put a comment in the middle of a string.