dictionaryA dictionary associates keys to values.
By default, dictionaries are persistent, retaining their values across games.
Dictionary entriesFormally, a dictionary is a collection of dictionary entries, each of which is a pair of permitted values. A permitted value is either a string, a number, position, or a set of squares. The first element in each dictionary entry is called the key of that entry. The second element in each dictionary entry is called the value of that entry. No two entries in the dictionary share a key.
A dictionary can have only a single type of key and only a single type of value, although the types of keys and value can be different.
A dictionary is defined
by preceding its name, which is a variable, with the keyword
persistence of dictionariesA dictionary is persistent by default retaining its value across games, and so any use of such a dictionary will force CQL to be single-threaded.
local (non-persistent) dictionariesIf the first use of the dictionary is preceded by the keyword
localthe dictionary is local. A local dictionary is not persistent: it is cleared before each new game is read.
local dictionary DThe example file followpath.cql illustrates the use of local dictionaries.
Only local dictionaries can have keys or values that are positions. If you want to store positions in a persistent dictionary, use the FEN of the dictionary or some other characteristic of the position.
Dis a dictionary. The value of the entry in
dictionary D D["hello"]="goodbye" D["up"]="down" "goodbye" == D["hello"] "down" == D ["up"] D["fail"] // this filter will fail to match
D has no entry with key
D[_key_] will fail to match; otherwise the expression will match.
Dictionary values can be assigned using the syntax in the example above.
Dictionaries cannot currently be used as the actual argument to a function or returned as the value of a filter. Thus, whenever a
dictionary is used, its actual name, as a variable, must be used.
counting elements of a dictionaryIf
Dis the name of a dictionary, then
#Dis the number of entries in the dictionary:
dictionary Dict #Dict==0 Dict[a3]="knight" #Dict==1
iterating through a dictionarySimple looping through the keys of a dictionary can be done using this syntax:
key ∊ dictionary bodywhere key is a variable; dictionary is the name of a dictionary; and body is any filter:
dictionary E["1"]=="2" dictionary E["No"]=="yes" K∊E message ("E[K]: " E[K])
This syntax works with any allowed type:
dictionary F[ a2 ]= 45 F[ b1-8 ] = 4 R∊F message ("F[R]: " F[R])
Note that the
a2 is surrounded by spaces when enclosed in brackets. This is because the symbol
[a2]is interpreted as a piece designator representing the square
a2rather than an index into a dictionary. (Likewise,
[x]is interpreted as
×, so be careful when using a variable named
xas an index into a dictionary.)
clearing entries in a dictionaryTo delete an entry with key
keyin a dictionary
D, use this syntax:
This form of
unbind always matches the position unless the
key filter fails to match the position.
To delete all entries in a dictionary
unbind DThis form of
unbindalways matches the current position.
dictionary D D["check"]="mate" D["back"]="rank" #D==2 unbind D["check"] not D["check"] #D==1 unbind D #D==0
Examples of use of dictionarySuppose we want to find pairs of games sharing the same initial position:
cql(input "hhdbvi.pgn") dictionary InitialD initial if InitialD[fen]~~"gamenumber: (\d+)" comment ("Position already seen at game number: " \1) else InitialD[fen]=str("gamenumber: " gamenumber)
More sophisticated matching can also be done, like searching to see if any position in the current study occurred earlier, and so on.
Dictionaries are often useful with
Typically, a file will be written encoding information about fens of games, and then fed into a dictionary with
summarizing dictionary contents at the end of processingNote: CQL currently lacks a good way to iterate through a dictionary in the last position of the last game, which is sometimes useful if the dictionary is summarizing some computation.
One way to do this, although cumbersome is as follows.
terminal // if variations not set not position (positionid + 1) // if variations set
But there is no way to check if the current game is last game in the current pgn file in CQL; you must manually find it. CQL always outputs the total number of games in a file, so cql must be run once to get the last game number, e.g. using
cql -i filename.pgn -cql false
Suppose there are 93839 games. Then, if variations is not set, use
cql (input filename.pgn) dictionary D ... if terminal and gamenumber==93839 message ("Number of entries in D: " #D)Technically one can use ~~ together with readfile to parse the input pgn file and count the games, for instance by counting the occurrence of the regex
\[Whiteand also the name of the input
.pgnfile as an argument using -assign, but that would likely not be any easier).