echo
Theecho
filter lets you look for positions that have a specified relation to the current position. The normal use of the echo
filter has the following syntax:
echo (source_var target_var) body_filter
Here source_var and target_var are variable names, and body_filter is a filter.
The operation of echo
is as follows:
- The variable source_var is set to the current position. This is called the source position
- For each position P other the source position in the game:
- the current position is set to P, the target position
- target_var is set to the current position
- body_filter is evaluated
The echo filter matches the current position (which is the source position) if body_filter was true for some target position.
After completion, of course, the current position is restored to its original value, and source_var and target_var are reset.
including the source position as a target
If theecho
filter includes the keywords in all
just before the body filter, then the target position will be set to the source position as well as to the other positions
echo quiet
If they keywordecho
is immediately followed by the keyword quiet
then comments automatically generated by the echo
filter are suppressed.
numeric value of echo
If body_filter is a numeric filter then theecho
is also a numeric filter whose value at a position is the maximum value of body_filter attains over all target positions at which it is evaluated.
You can use sort with echo
just like with any other filter, so long as body_filter is a numeric filter, with one limitation: the sort must be in the max direction (the default). sort min
is not supported with echo
.
Therefore, when sort
is used with echo
, the sort
filter finds the positions source and target that maximize the value of the body_filter . The default echo
and sort
generated PGN comments should indicate which source/target position pair attained this maximum. Example of this usage include zugzwang2.cql, fatamorgana.cql, movedblackpieceecho.cql, and underpromotionecho.cql .
comments in echo
echo
will generate automatic comments indicating each matched source position and target position. echo
will also generate a comment indicating the lca of the source position and target position whenever the LCA
is different from each of these. These automatically generated comments can be removed by specifying the quiet option in the CQL header.
echo
comments can quickly become unwieldy. It is often useful to sort an echo
, since a sort only generates comments associated with its maximum value.
Useful filters in echo
You can use any filter you want in an echo, but some tend to be particularly useful:- : operator
- consecutivemoves
- ∩ with position filter arguments
- sidetomove
- lca
- distance
- comparison of positions using relation operators
Examples
Theecho
filter is used in castleecho.cql, chameleon.cql, enpassantecho.cql, fatamorgana.cql, flipverticalecho.cql, knightpawnforkecho.cql, movedblackpieceecho.cql, platzwechselecho.cql, queenpawnpinecho.cql, underpromotionecho.cql, wcct7.cql, zugzwang1.cql, and zugzwang2.cql.
We now will go through in a little detail how CQL finds some studies using the echo
filter. First, we look at a simple zugzwang script.
A simple zugzwang example from Korolkov
For the simplest example, let's go through zugzwang1.cql.Let's go through the CQL code in zugzwang1.cql, and specifically what happens when the CQL file reaches the study Korolkov 1972, USSR team champ. VIII, 1/2 p..
The CQL file begins with the list of CQL parameters which here importantly tell CQL to look in the variations:
cql(variations)
The next few filters limit our consideration to win studies and the current position to be in the mainline that are black to move:
result 1-0 mainline btm
At this point, the current position is a black to move mainline position in a win study.
In particular, the current position will match the filters so far at the position after move 4.Ka1
:
This will be a zugzwang position of the kind we are looking for if the same position recurs in the variations with white to move. That is what the echo
filter looks for:
echo(source target){ wtm try source∩target==▦}
The echo(source target)
sets the user variable source
to the current position, which is our mainline black to move position, that is, the diagrammed position above.
The echo
filter then runs through all the other positions in the study, setting target
to each of them, and setting the current position to target
. For each such position, the filter checks if the
target
is a position that is wtm try
that is if it is a white-to-move position in a try. The try
means that in a correct study without duals, White should not win from this position.
Since target
equals the current position, a filter like wtm
is true of the current position (i.e., is true) if it is true of target
.
Now for the key part of the echo
body, we compare the positions source
and target
:
source∩target==▦
This checks that the board positions are the same.
Note that by default the echo
filter outputs several automatic comments.
The matching source position, here named source
occurs after move 4.Ka1
in the mainline:
4.Ka1! source <-- move 5(wtm)[47] CQL
The CQL
at the end is the default comment output
by CQL when the body of the CQL file matches a
position. The word source
is taken from the
first argument, source
, to the echo
filter,
and indicates that the echo
body matched a
position when the source
equalled this
value. The move 5(wtm)[47]
represents the
position using the standard textual representation of a position. Here,
it means the position with positionid equal to
47, which occurs in a white to move position at
move 5. At that position, a corresponding comment
is seen:
4...Ka8! target <-- move 4(btm) id:47The
id:47
means that the positionid of that
position (the position after 4...Ka8
) is
47
. The target
means that this position
matches a value of target
in the echo
filter. The word target
is taken from the
variable that is the second argument to echo
, in
echo(source target)
. The move 4(btm)
indicates
the corresponding source
position, namely the
btm
mainline position after move 4. (It must be
a mainline position because there is no bracketed
number following it, unlike for the source
position's comment.
One final comment is worth mentioning. The mainline position after 1...Rd4
,
(found from CQL file: zugzwang1.cql)
is annotated with the comment LCA
. This simply means that this position is the lca or "critical position". If white plays 2. d:c4!
here, then white wins, reaching the source
position above with black to move. But if white instead plays 2. a7+
then black avoids loss, as he can in some variation reach the target
position above, with white to move.
A logical study by Salai
Now we look at a slightly more complex example. We are looking for games such that there isa mainline positionsource
and a variation target
which only differ in that white has an extra piece in the target
. Normally, the extra piece would help white, but here, because it occurs only in the variation, we expect it to hurt white.
We also want the game to illustrate why the missing piece hurts white by a sequence of moves that fails only in the variation. What this means will be clearer a bit later.
The following study by Salai is an example:
(found from CQL file: missingwhitepiece.cql)
In this position, the natural 1.Kd7?
turns out to lose, after the sequence of moves given in the variation.
The winning move is 1.f4!
. After 1...B:f4
only now does white play Kd7
. So the natural question: why does inserting the moves 1.f4 B:f4
turn the drawing 1.Kd7
into the winning 2.Kd7
?
The answer lies in the position near the end of the mainline:
(found from CQL file: missingwhitepiece.cql)
The above position is reached after 1.f4! B:f4 2. Kd7 .... 10...Kh5
. White now wins after 11. f3!
. But 11. f3!
is possible only because 1.f4
vacated the f3
square.
If white had instead of 1. f4
played the immediate 1.Kd7
and tried the same plan, the following position would have been reached.
(found from CQL file: missingwhitepiece.cql)
In this position, white cannot save a tempo with f3
, since there is now a pawn on f3
, so white only draws.
The CQL that finds this position (and positions like it) is in the file missingwhitepiece.cql.
It begins with some boilerplate
cql(result 1-0 variations matchstring "")This limits the result to white wins, searches in variations, and inhibits printing of
CQL
at each match, which clutters up the output somewhat.
Now, we want include and echo
filter. We want the echo filter to match when source
equals
the winning mainline position above after 10...Kh5
, and target
equals the drawing variation after 9...Kh5
.
The mainline
. The
sort "number of identical consecutive moves" echo (source target){ tryindicates that the games are to be sorted by the value of the
echo
filter. Here, the body of the echo
is a compound filter which ends with
consecutivemoves 15 100 (source target)
Now, let us assume in the following that the variable source
has value equal to the mainline the position after 10...Kh5
, and the variable target
has value equal to the variation position after 9...Kh5
.
Next, the remainder of the echo
body just checks that source
and target
are the same except for some extra pieces in target
, which is the current position inside the echo
body.
As in the zugzwang example earlier, we first check that the sidetomove is the same
in source
and target
:
sidetomove==source:sidetomove
Next, we set the variable mismatches
to the set of squares in which the positions source
and target
differ, and check that this is nonempty:
mismatches= ~(source&target) mismatches>0
In this case, mismatches
has the value f3
, since that that is the only square
on which source
and target
have different contents. In the source
, the mainline, the square f3
is empty; but in the target
the square f3
has a white pawn on it.
The next line actually checks that the only difference between source
and target
is that target
has some extra white pieces:
mismatches== △∩source:□
Here, △
is the set of squares on which there is a white piece in
the current position, that is on target
. source:□
the set of
empty squares in source
. The ∩ takes the intersection of
these two sets. The only square in both sets is f3
: there is a white
piece on f3
in target
, but f3
is empty in source
.
Hence, the right hand side of the ==
above is simply f3
, which is also the value of the left side, mismatches
.
Finally, the consecutivemoves filter has value equal to the
length of the longest sequence of consecutive moves between the LCA and source
and the LCA and target
. Here, for example, this length is 16: the 16 moves that are annotated source-move[1]
through source-move[16]
(or target-move[1]
through target-move[16]
). The LCA of source
and target
in this case is simply the initial position: white can choose to go into the mainline with 1.f4!
or the variation with 1.Kd7?
.
Therefore, the filter matches.