dictionary

A dictionary associates keys to values.

Formally, a dictionary is a collection of dictionary entries, each of which is a pair of strings. The first string in each dictionary entry is called the key of that entry. The second string in each dictionary entry is called the value of that entry. No two entries in the dictionary share a key.

A dictionary is defined by preceding its name, which is a variable, with the keyword dictionary.

Suppose D is a dictionary. The value of the entry in D with key key is D[key].

      dictionary D
      D["hello"]="goodbye"
      D["up"]="down"
      "goodbye" == D["hello"]
      "down" == D ["up"]
      D["fail"] // this filter will fail to match

If dictionary D has no entry with key key then 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.

persistence of dictionaries

Any dictionary is persistent, retaining its value across games, and so any use of a dictionary will force CQL to be single-threaded.

counting elements of a dictionary

If D is the name of a dictionary, then #D is the number of entries in the dictionary:
  dictionary Dict
  #Dict==0
  Dict["pin"]="knight"
  #Dict==1

iterating through a dictionary

Simple looping through the keys of a dictionary can be done using this syntax:
      string key in dictionary body
where key is a string variable; dictionary is the name of a dictionary; and body is any filter:
      dictionary E["1"]=="2"
      dictionary E["No"]=="yes"
      string Key in E
        message
        ("Value of E at: " Key " is: " E[Key])

clearing entries in a dictionary

To delete an entry with key key in a dictionary D, use this syntax:
      unbind D[key]

This form of unbind always matches the position unless the key filter fails to match the position. To delete all entries in a dictionary D, use

      unbind D
This form of unbind always 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 dictionary

Suppose 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 most useful with readfile and writefile. Typically, a file will be written encoding information about fens of games, and then fed into a dictionary with readfile.

summarizing dictionary contents at the end of processing

Note: 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.

First, note that to check if the current position is the last position evaluated in the current game, use either terminal or position

      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 \[White and also the name of the input .pgn file as an argumnet using -assign, but that would likely not be any easier).