Variables
Variables are sometimes useful for expressing certain complex ideas in a clearer or more succinct manner.
A user-defined variable, like x
, $foo
, or Pawn
has a name and a value.
Variable names
A variable name is a sequence of allowed characters. An allowed character is an alphabetic character a-z or A-Z, a digit,
or the characters $
or _
. Variable names are case-sensitive: yes
is different from Yes
.
A (user-defined) variable name cannot be the same as a CQL keyword. The CQL keywords are listed in the index. In addition, a user-defined variable
name cannot by the name of a piece specifier, like R
, _
, Ba3
, ab3
, _c1
and so on.
Examples of legal variable names are:
rook Rook bishop Bishop ... x y z // but not a or b $R $foo RR foo Foo this_is_a_legal_variable_nameVariable names beginning with the characters
__CQLare reserved by CQL.
Variable values
There are five types of variables: numeric variables, set variables, piece variables, string variables and position variables. Once assigned, a variable cannot change its type.In addition, numeric, string, and set variables can be either persistent@ or normal: persistent values retain their value between games.
A variable must have been assigned a value before the variable is used, and (except for persistent variables) the value of a variable is unassigned before CQL begins parsing of a new game.
A variable is assigned using the =
filter:
x = 3 //numeric assignment y = find check //position assignment z = . attackedby k //set assignment piece zz = N // piece assignment
Numeric variables
A numeric variable holds an integer. The absolute value of this integer may not exceed a billion.A numeric variable is defined by assigning it to a numeric filter using "=":
x = #R
The variable x
will hold the integer number of squares that have a white rook on them, that is, the number of white rooks in the current position.
A numeric variable is a numeric filter. Numeric variable can be compared using standard expressions.
x+y<power R 2*NumberRooks == NumberPawns
A numeric variable can be modified by using the operator assignments: +=
, -=
, /=
, *=
, and %=
.
These modify the variable on the left according to the operator. For example,
x += 1
Is the same as
x = x+1
The other operators work the same way (the '%' operator is the modulus operator).
If var is a numeric variable and value is a countable filter, then the assignmet
var = valuematches the current position only if value matches the current position. If the value matches the current position, then the value of var is set to the value of value. Otherwise, var is not modified.
Similar rules apply to operator assignments, which match the current position, and which modify the variable on their left hand side, only when their right hand side matches the current position.
A numeric variable always matches the current position, but CQL will signal an error if a numeric is used in a context where it is being tested only for whether it matches:
x=3 if x then y=4 // error: no reason to test if x matches
Set variables
A set variable holds a set of squares and is a set filter. A set variable can be introduced in one of two ways: A set variable introduced by thesquare
filter is just an ordinary set variable which happens to hold a set of cardinality 1:
square x in A x attacks k
In the above, x
at any time holds a single square on which there is a white piece (and loops through all possible such squares).
If S is a set filter, then x = S
assigns the set of squares represented by S in the current position to the variable x
. For example:
x= . attackedby R y= move to _ legal z=x | y z=x&y
When var is a set variable, then
var = valuealways matches the current position and always assigns to var the value of value, even if that value is empty. However,
var =? valuewill only match the current position (and will only change the value of the set variable var) when value is nonempty. This is how numeric and position assignments work, and is sometimes convenient.
String variables
A string variable holds the value of a string. String variables can be assigned in three ways:- by using
=
; - by using
+=
(which concatenates its right-hand side to the variable on its left); - by using subscript assignment
X="zug" X=="zug" // X holds "zug" X+="zwang" X=="zugzwang" X[1:3]=Z // X holds "zZzwang"
Position variables
Position variables hold the identity of a particular position, which is a location in the game tree. Position variables are created by an assignment statement in which the right side is a position filter, of which the most common iscurrentposition
:
z=currentpositionAs with the other variable assignment statements, if the right side of the assignment expression does not match the current position, then neither does the assignment, and the variable is unchanged.
Piece variables
The most complex of the variable types is the piece variable. A piece variable holds the identity of a particular piece. Each individual piece on the chessboard is given a unique integer at the start of the game, called its piece id. The piece id of a piece does not change as the piece moves or promotes.A piece variable however is a set filter. The piece variable is associated with a particular set of squares in any position as follows. Suppose the piece variable var holds a piece id of id. Then:
- If the piece with piece id of id exists in the current position, then the value of var is the square on which that piece stands.
- Otherwise, the value of var is the empty set.
Piece variables are introduced in one of two ways:
- using the piece filter, like
piece x in A ...
; - using the piece assignment filter.
The piece assignment filter consists of the word piece
, followed by the name of a variable, then an =
sign, then a set filter, e.g.:
piece x=N piece y=move from Ror in general
piece var = valueIf value consists of exactly square, and that square is occupied by a piece, then var is set to hold the piece id of the piece occupying that square. Otherwise, var is unchanged and the piece assignment expression does not match the current position.
Piece variables are normally converted to their values as sets when they appear. For example, if x
is a piece variable, then
N==xmatches the current position only if either there are no white knights in the position and the piece represented by
x
is not in the position; or if the piece represented by x
in the current position is the only white knight in the position.
Piece variables can appear in two other contexts (other then in a piece filter or a piece assignment filter) and not be converted into their corresponding sets.
First, if a piece variable is passed to a comment
filter, then the comment outputs its color and type, in addition to the square its on:
piece x=K comment ("The king is " x)will output the comment
The king is Kd4
(assuming the king is on d4
).
by contrast, the code
x=K // x is a set variable, not a piece variable comment ("The king is " x)would output the comment
The king is d4
.
Second, like all variables, when a piece variable is an argument to a user-defined function, it is not converted to a set.
Persistent variables
Persistent variables are initialized to 0, the empty string, or the empty set as appropriate.Persistent variables cannot be used when multithreading is enabled. (This is because the value of a persistent variable depends upon the value of that variable in previously parsed games, and in multithreaded mode CQL parses different games simultaneously.) CQL automatically runs in single-threaded mode if any persistent variables are used in the CQL file).
An example of using persistent variables is in the example file persistent.cql.
Scoping
The value of a variable cannot be accessed before it is defined. Once defined, the variable retains its type, but not necessarily its value, as the program progresses. You can use isbound and isunbound to check if a variable is defined.