Sidonia Chess Programs  Online Documentation Incomplete First Draft
Chess Engine, Chess Interpreter, Game recorder, Game analysis


Sidonia_Interpreter (©) is a TCL based chess script interpreter written by Ivan Urwin.

Why write a script interpreter for chess?

I found I was writing Windows batch file scripts (*.BAT) or TCL scripts, to do various operations for example to create chess opening books for different openings: Sicilian, King's Gambit, etc. I also found I was creating scripts for automated testing, eg to run the chess software on various (enhanced) positional databases (EPD files) in order to verify the integrity of some software changes.

An example would be after changing some checkmate detection software to verify that search depth 1 would find mate in 1, search depth 3 would find mate in 2, depth 5 mate in 3, etc.

Another example would be after changing move generation, to verify various performance test (perft) values.

1 perft [startpos] 2

should evaluate to 400. Deeper tests from more complicated positions are more thorough.

TCL seems to be a better design that windows batch files, and I soon came to the conclusion that incorporating some of my own commands inside a TCL interpreter was more powerful and aesthetic than adding command line switches to various ad-hoc programs.

Getting Started

Running the interpreter

There are two common ways to run an interpreter.

  • interactively
  • scripting

If the executable is handy, you could click on it to start it running and type commands. If the interpreter is configured to run script files, you could create a small file and click on that to run the script in the file. If you run a script from a file, beware that you might not see the programs output, as the output window is likely to disappear when the script finishes. You can work around this problem when getting started by makeing the script wait for user input when it is about to terminate.

A first command

This should start up the windows program notepad.

1 exec notepad

If that works, congratulations, you have a working script interpreter.

A Chess command

Now lets do something chess specific.

1 startpos
2 exec notepad

you should have output like this

rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1

From now on, let's assume the interpreter is run interactively, or that you add something yourself (like the exec notepad command,) to pause when script execution is complete if you need to read some displayed output before it disappears.

Create a small EPD file

1 set epd(position) [startpos]
2 set epd(pm) e4
3 set text [epdtext epd]
4 addtext $text new.epd

new.epd will now contain

rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - pm e4;

that is to say, a proposed move of e4 for the start position.

Create some opening books

1 book new.epd opening_book.gob
2 book new.epd opening_book.pob
3 book new.epd opening_book.sob

We have now created some small opening books in Glass, Polyglot and Sidonia formats.

Interpreter Commands

The list below gives a limited selection of Sidonia Interpreter commands. The list is in the process of being expanded. It is manually ordered alphabetically, so some entries might be misplaced from time to time if a similar existing entry is copied and modified to create a new one and the new entry hasn't yet found its proper place.


addtext text filename

For example

1 addtext {hello world} hello.txt

puts the string "hello world" into the file hello.txt.



This should only be used after a search. It returns the best move found by the search.

For example

1 searchmode depth 5
2 search [startpos]
3 puts [bestmove]

prints the best move found after searching the starting position to depth 5.



Calculate a bitboard value from a list of squares.

For example

1 bitboard {a1 a3}

gives a value of 5. (*) Note: This command assumes a specific bitboard layout. Other chess programs do use different layouts. Therefore this command is Sidonia specific.


boysname number

Looks up a forename in an internal list of 512 names. The index should be in the range 0-511.

For example

1 boysname 7




chebyshev sqA sqB

Determine the distance from square sqA to square sqB. This is the number of king moves. I think of it as the distance a crow flies, though that is not strictly corrct. However it does give the idea that one can move diagonally. It is the maximum of the rank and file distances.

The synonym crow may be used. It might be easier to remember than the name of the mathematician.

See also manhaattan (and its synonym, taxi).


checkmate position

Is the position checkmate?

Two examples

1 checkmate [startpos]
2 checkmate {7r/pR2b2p/4r3/kQ4p1/8/8/1P1P1PPP/2BK3R b - - 2 28}

gives respective results



createbook infile outfile ?movepriority?

Create an opening book from an EPD file. For example, if Sicilian.epd contains

1 foreach_position {position move} {e4 c5} [startpos] \
2 {
3  set epd(position) $position
4  set epd(pm) $move
5  ensure [epdtext epd] Sicilian.epd
6 }
7 createbook Sicilian.epd Sicilian.pob
8 createbook Sicilian.epd Sicilian.gob Tournament
9 createbook Sicilian.epd Sicilian.sob Good

creates an EPD Sicilian.epd file containing

rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - pm e4;
rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 pm c5;

and then uses this file to create three opening books, in Polyglot, Glass and Sidonia format. In the Glass opening book, the moves are marked as tournament standard. In the Sidonia opening book, they are just marked as good moves.


DNA name

Finds a number associated with a name. This is in some sense the inverse of person which converts a number to a name. Its intended use is with genetic algorithms, where two numbers representing parents genetic material are combined to produce another number representing a possible offspring.

There are three forms of the command.

2 DNA name
3 DNA name variable

The first returns a number associated with current options, eg is an opening book in use. I think of this as retrieving Sidonia's DNA. The second form returns the DNA of a name where we expect the command to succeed. The third command form can be used if we think the name might not be recognised.

1 set Sidonias_dna [DNA]
2 set Joes_dna [DNA Joe]
3 set some_name {Lee Harvey}
4 if [DNA $some_name their_dna] \
5 then {puts "${some_name}'s DNA is $their_dna"} \
6 else {puts "$some_name failed the DNA test."}


epdtext epd_associative_array_name

Assuming the array is called epd, then epd(position) should contain a valid FEN.

1 array set me "position {[startpos]}"
2 puts [epdtext me]
4 set me(Zob) 1
5 puts [epdtext me]


rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq -
rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - Zob 463B96181691FC9C;

Note that if there is a Zob field in the epd array then the correct Polyglot hash code for the position is put into the EPD text, and not the value of the marker that indicated you wanted it.


evaluate position

Accesssing the evaluation function ... Depending on the software version, maybe tablebases counld interfere with evaluation, and so it might be best to turn them off first.

Depending on what you want to see, it might be an idea to set the piece square tables to zero.

1 uci {setoption name Use Tablebases value false}
3 # uci {setoption name Piece Square Tables value Tomasz Michniewski}
4 uci {setoption name Piece Square Tables value All Zeros}
6 puts "The starting position is worth [evaluate [startpos]] centipawns."


The starting position is worth 11 centipawns.


finalgen position summaryvariable

You may try to use FinalGen as follows

1 uci {setoption name Use FinalGen value true}
2 set fen {8/8/1k6/p7/1P5p/3K3P/8/8 b - - 0 1}
4 set score [finalgen $fen summary]
5 puts "$fen : $score : $summary"
7 set score [FinalGen $fen summary]
8 puts "FinalGen $fen : $score : $summary"

The chances are you will get messages like these

8/QPPP4/8/8/8/8/7k/K7 w - - 0 1 : -32768 : NOT_AVAILABLE Final Gen DLL not activated yet!
8/2Kp2k1/3P4/2P5/2N3b1/8/8/8 w - - 0 1 : -32768 : NOT_AVAILABLE Final Gen DLL not activated yet!
finalgen 8/8/1k6/p7/1P5p/3K3P/8/8 b - - 0 1 : -32768 : NOT_AVAILABLE Final Gen DLL not activated yet!
FinalGen 8/8/1k6/p7/1P5p/3K3P/8/8 b - - 0 1 : 0 : NOT_AVAILABLE Final Gen DLL not activated yet!

or other error messages

8/QPPP4/8/8/8/8/7k/K7 w - - 0 1 : -32768 : NOT_AVAILABLE Too many pieces for Final Gen
8/2Kp2k1/3P4/2P5/2N3b1/8/8/8 w - - 0 1 : -32768 : NOT_AVAILABLE Too many pieces for Final Gen
finalgen 8/8/1k6/p7/1P5p/3K3P/8/8 b - - 0 1 : -32768 : NOT_AVAILABLE Too many pieces for Final Gen
FinalGen 8/8/1k6/p7/1P5p/3K3P/8/8 b - - 0 1 : 0 : NOT_AVAILABLE Too many pieces for FG tablebase

If you have run FinalGen on the position earlier, if FinalGen is available in this version of the interpreter, if it is enabled by default, or you remembered to try to turn it on with the UCI command, and if you not only have the FinalGen DLL, but you put it where the interpreter can find it so a result can be found, you might be lucky and get ...

finalgen 8/8/1k6/p7/1P5p/3K3P/8/8 b - - 0 1 : 29874 : Win. Promotion in 13
FinalGen 8/8/1k6/p7/1P5p/3K3P/8/8 b - - 0 1 : 32654 : Win. Promotion in 13

Note that the scoring is different dedending in the capitalisation. That is something to be clarified and probably cleared up in the software. The issue is different scoring systems in different peoples software.


foreachgame {tag moves ?result?} filename code

This is like the foreach command, except instead of reading values for a variable from a list, it reads chess games from a PGN file. The games are read one at a time, stored in the variables (denoted here as tag and moves) and then processed by code.

The variable storing the PGN tags is an associative array. Its elements are determined by the tag pairs in the PGN file. The variable storing the moves will contain them as a list.

tag and moves represent the names of the variables. For example you might want to read the tag pairs and moves for some incomplete games as follows ....

1 foreachgame {pairs opening} games.pgn $code

In the example above, the tag pairs are stored in the array pairs and the moves are stored in a list called opening.

To repeat what was described earlier in the introduction to the interpreter, the Sidonia script interpreter can handle the PGN file format with a special looping command: foreachgame.

1 foreachgame {tag moves} games.pgn $code

will read successive games from the file games.pgn, and for each game it will execute $code. The code may contain break or continue statements to leave the loop or go on to the next game. Each game is stored in variables, eg tag and moves in the example above, where tag is an associative array containing the tag pairs from the game header and moves is a list containing the moves from the game body. For example if Bobby Fischer won a Fool's Mate game,

1 tag(Black)

might contain "Fischer, Robert", and

1 moves

might contain "f2f3 e7e5 g2g4 d8h4".

Use of the foreachgame command is illustrated in the interpreter examples, given after the interpreter command desriptions.


gameover position

Is the position checkmate or stalemate?

Two examples

1 gameover [startpos]
2 gameover {7r/pR2b2p/4r3/kQ4p1/8/8/1P1P1PPP/2BK3R b - - 2 28}

gives respective results



generate position

Invoke the move generator

For example

1 generate [startpos]

gives a result of

a2a3 a2a4 b1c3 b1a3 b2b3 b2b4 c2c3 c2c4 d2d3 d2d4 e2e3 e2e4 f2f3 f2f4 g1h3 g1f3 g2g3 g2g4 h2h3 h2h4

gtb (Gaviota Tablebase)

gtb position

Lookup a position in a Gaviota Tablebase. Gaviota tablebases are endgame tablebases, tables which allow a chess program to play perfectly once the position is simple enough, for example only 5 pieces left of the board. For the command to be useful, the interpreter first needs to know the location of the tablebases, and GTB usage must be switched on.

These are set using the uci setoption command.

1 uci {setoption name Tablebase Path value C:\gtb}
2 uci {setoption name Use Tablebases value true}
3 gtb {8/8/8/8/8/8/8/k2K2Q w - - 5 5}

gives a result of


Here we can see from the high score that white is going to win by checkmate. The numerical scoring system used is Sidonia's. Scores can be made more meaningful using the scoretext command.

Note that in order to be able to use tablebases, a chess engine must know where they reside on the computer. See the uci command for more details on chess engine configuration.


manhattan sqA sqB

Determine the distance from square sqA to square sqB. This is the number of king moves along rook paths It is also called the taxi distance. It is the sum of the rank and file distances.

The synonym taxi may be used.

See also chebyshev.


This function counts pieces on the board and returns them in a form suitable for storing in an associative array, ie pairs like


all in one long list.

There are two versions of this, with a small and with a capital M. The version with the capital is less pretty but more useful, as it provides information for several pieces with the arithmetic already performed for you, eg slider refers to rooks, bishops and queens all in one go.

material position ?colour?

Refers only to specific pieces.

Material position ?colour?

Has extra information, eg slider.

1 puts [material [startpos]]
2 puts [material [startpos] White]
3 puts [Material [make {e4 d5 ed}] Black]
5 array set blackstuff [Material [make {e4 d5 ed}] Black]
6 puts "There are $blackstuff(slider) black sliders"


KING 1 QUEEN 1 ROOK 2 BISHOP 2 KNIGHT 2 PAWN 7 minor 4 major 3 slider 5 diagonal 3 LightBISHOP 1 DarkBISHOP 1 total 15 White 16 Black 15
There are 5 black sliders

Notice that using a capital letter produces some useful but cluttering extra information. Use a capital or small M to generate the information you want, store it in an associate array, and then use the specified information you want.

Note that the White and Black counts are not dependent on the colour selection. The total and the other counts are only for the selected colour.

Maybe it would be better to have selected 15 and total 31 in the example above.

This part of the script interpreter is designed to be useful for selecting postions with certain properties, and until it is used in anger, I don't know quite what features would make it most useful.

An idea for the future is to add a grid term to the Material data. It would be a rook and queen count.


nodes type

Retrieve a count of the number of nodes searched.

There are several counters updated during a search, and the type field can be used to control which counter is read. The possibilities are listed below.

1 nodes quiesced
2 nodes leaves
3 nodes evaluated
4 nodes searched

oob (Out of Book)

oob plycountvariable colour moves

The actual command to determine whether we are taken out of book is oob. The opening book is assumed implicitly from the chess engine's configuration. With that in mind, it is a good to specify the opening book to be used.

uci {setoption name Opening Book File value F:\book_Sidonia.bin}

before running oob, eg as in the following example which looks at up to 100 games from a PGN file and counts how often White stays in book (ie plays as he should), plays out of book (chooses a move that wasn't planned), or gets taken out of book by the opponent (who has played an unexpected move, eg a novelty).

1 set games 0
2 set taken_out_of_book 0
3 set play_out_of_book 0
4 set stay_in_book 0
6 foreachgame {tag moves} games.pgn \
7 {
8  incr games
9  set oob [oob plycount White $moves]
10  if {$oob eq {Taken Out Of Book}} {incr taken_out_of_book}
11  if {$oob eq {Play Out Of Book}} {incr play_out_of_book}
12  if {$oob eq {Stay In Book}} {incr stay_in_book}
13  if {$games == 100} break
14 }
16 puts "Games $games"
17 puts "Taken Out Of Book $taken_out_of_book"
18 puts "Play Out Of Book $play_out_of_book"
19 puts "Stay In Book $stay_in_book"

The out of book command oob was written to help improve Sidonia's opening book. If a game is played elsewhere and it is found that the game takes Sidonia out of her opening book, then the position can be analysed for subsequent inclusion in the opening book. It is perhaps particularly important for a chess engine to add new moves for lost games as it helps prevent opponents from "using the same trick twice",

  • It gives us a time advantage next time the position occurs.
  • It gives us a performance advantage, if the postion is analysed deeper and a better move chosen.

There, I have given away one of the secrets to the strength of Sidonia's opening book: repeated inclusion of positions that take her out of book. However I can think of two more secrets!


perft position depth

move generator performance test

For example

1 perft [startpos] 2

gives a result of



PieceOn position square

Determine what piece is on a particular square of a chess board.

For example

1 PieceOn [startpos] e1
2 PieceOn [startpos] e3

gives a results of

White King

I developed this after a conversation with Pablo Lopez about recapturing a bishop on g6 with either the F pawn or the H pawn. The command was then used in a chess game filter like this ...

1 if {![string equal [PieceOn $position g8] {Black King}]} continue
2 if {![string equal [PieceOn $position f7] {Black Pawn}]} continue

and also with a progress marker (pm) like this

1 set piece [PieceOn $position g6]
2 switch $pm \
3  ...
4  1 {if {[string equal $piece {White Bishop}]} {set pm 2} else {set pm 0}} \
5  2 {if {[string equal $piece {Black Pawn}]} \
6  ...


polyglothash position

1 puts "polyglothash {8/7p/7K/8/3B4/8/kQ6/8 b - - 10 54} = [polyglothash {8/7p/7K/8/3B4/8/kQ6/8 b - - 10 54}]"
2 puts "polyglothash {4k3/8/8/8/8/8/8/4K3 b - - 10 1} = [polyglothash {4k3/8/8/8/8/8/8/4K3 b - - 10 1}]"


polyglothash {8/7p/7K/8/3B4/8/kQ6/8 b - - 10 54} = 6782F518C48D7475
polyglothash {4k3/8/8/8/8/8/8/4K3 b - - 10 1} = A6536BD038CC91CF


quiesce position

returns the score obtained when a position is quiesced, ie what the position appears to be worth when certain checks, captures, promotions, etc are taken into account. Exactly what is considered will depend on the implementation at the time.


reset something

To compare two search routines, we might do one search, see how many nodes were searched, then search again with the other routine and compare the counts. The test would be invalid if the second search were instantaneous because it just used the result of the first search by reading the transposition tables.

The reset command allows various parts of the search data to be cleared prior to another search.

The recognised options are listed below.

1 reset counters
2 reset TTs
3 reset killers
4 reset all


scoretext score ?position?

Returns a more human form of the score.

1 set position {4k3/8/8/8/8/8/8/3QK3 b - - 1 100}
2 set score [gtb $position]
3 puts [scoretext $score $position]


Black mated on move 108: mated in 8


search position

perform a search of the position, for example

1 searchmode clear
2 searchmode depth 4
3 search [startpos]
4 puts "[bestmove] [score]"
5 puts "[SAN [pv] [startpos]]"

results in

b1c3 18
Nc3 Nc6 Nf3 Nf6



searchmode on its own prepares for a search with no limits: an infinite search.

Various search limits can be defined as in the examples shown

1 searchmode
2 searchmode clear
3 searchmode depth 3
4 searchmode time 10
5 searchmode nodes 1000000

depth, time and nodes limits may be active simultaneously but need to be set by multiple calls to searchmode. The values are remembered and used for subsequent searches until changed.

1 searchmode clear

eradicates depth, time and nodes limits so that a search becomes infinite again, and is equivalent to

1 searchmode

but is perhaps easier to understand when read.

SEE (Static Exchange Evaluation)

SEE position square ?colour?

Calculate a static exchange evaluation score for piece swapping on a particluar square.

Static exchange evaluation is the calculation of the net effect of exchanging pieces on one square of the board without consideration of whether there are better moves available elsewhere. SEE has applications in move ordering as well as extension or pruning algorithms. It gives a first guess at whether a piece is attacked or sufficiently defended. It is only a first guess, as SEE ignores what is happening elsewhere on the board.

If no colour value is specified, then the side to move is assumed.

SEF (Simple Evaluation Function)

SEF position

Calculate the Tomasz Michniewski simplified evaluation function score for the position.

1 SEF [startpos]
2 SEF [make {e4 d5 ed}]

The commands above give ...




This function returns the string "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1". The quotes are not part of the string. It is the starting position of a game of chess. The function is provided as a convenience, since typing the whole string is error prone, but the string is useful for testing simple scripts.

For example, we can test the move generator, standard algebraic notation function and evaluation functions as follows.

1 puts "The starting position is [startpos]"
2 set moves [generate [startpos]]
3 puts "Legal moves are $moves"
4 puts "In Standard Algebraic Notation that is [SAN -- $moves [startpos]]"
5 puts "White's opening advantage in centipawns is [evaluate [startpos]]"


The starting position is rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1
Legal moves are a2a3 a2a4 b1c3 b1a3 b2b3 b2b4 c2c3 c2c4 d2d3 d2d4 e2e3 e2e4 f2f3 f2f4 g1h3 g1f3 g2g3 g2g4 h2h3 h2h4
In Standard Algebraic Notation that is a3 a4 Nc3 Na3 b3 b4 c3 c4 d3 d4 e3 e4 f3 f4 Nh3 Nf3 g3 g4 h3 h4
White's opening advantage in centipawns is 11

stm (Side to move)

stm position

Side to move

For example

1 stm [startpos]

gives a result of



uci ucicommand

Universal Chess Interface

This command passes a string to Sidonia's UCI protocol interpreter. It has the same effect (because it uses the same software) as entering a command to the Sidonia chess engine, when the chess engine is running in UCI mode.

For a list of UCI commands, see the UCI specification.

One of UCI's main purposes is playing chess. Another is setting a chess engine's configurable options. Sidonia's options should be documented in the chess engine section, but a way to find out the options of any UCI chess engine is start the engine, enter the "uci" command, and see what options it prints.

1 uci uci

gives a result of

option name UCI_ShowCurrLine type check default false
option name Sidonia 0090 by Ivan Urwin type button
option name Transposition Table type spin default 199 min 1 max 1024
option name Ponder type check default true
option name OwnBook type check default true
option name Opening Book File type string default f:\Book_large.bin
option name Use Tablebases type check default true
option name Tablebase Path type string default C:\gtb
option name Use FinalGen type check default true
option name FinalGen Path type string default c:\FinalGen
option name Write Permission type check default false
option name Sidonia Path type string default C:\garbage
option name Debug Display Position type button
option name Debug Display Possible Moves type button
option name Debug Display Engine State type button
option name Debug Display Search State type button
option name Debug Display Table Usage type button
option name Activation Code type string default 12345678
option name Resign when losing by n pawns type spin default 20 min 1 max 20
option name Book Strategy type combo default Random var First var Random
option name Book Priority type combo default Tournament Move var Normal Move var Good Move var Priority Move var Tournament Move
option name Openings type combo default Kings Pawn var Kings Pawn var Queens Pawn var Sicilian/English var Knights var Irregular var Soft Pawn
option name Subsequent games type combo default Repeat Games var Repeat Games var Varied Games var Varied Moves
option name Node Counter type combo default Evaluated var Evaluated var Leaf var Quiessed var Searched
option name Search Depth type spin default 5 min 1 max 10
option name Piece Square Tables type combo default Sidonia var Sidonia var Experimental var All Zeros var Tomasz Michniewski var Lucas Braesch
option name Search Routine type combo default AlphaBeta TT MO var Negamax Zero Window var Search Routine 2 var Scoreless Ordering var Simplest Search var Vanilla Alpha Beta var AlphaBeta MoveOrder var Alpha Beta TT var AlphaBeta TT MO var Book Search var MTDf var AB TT Store & Test var Verified Null Move var Development var Random var Kill var Turing's Turochamp var Merlin's Search var Fat Sausage var Spare Search 2 var Spare Search 3 var Spare Search 4
option name Analyze type combo default Normally var Normally var Using Perft
option name Learn type check default false
option name Experience type check default true
option name Non-ideal Mates type check default true
option name CutOff Table type check default true
option name Hash Scheme type combo default Sidonia Symmetric var Polyglot var Sidonia Random var Sidonia Symmetric

so useful uci commands might be (one of)

1 uci {setoption name Use Tablebases value false}
2 uci {setoption name Tablebase Path value D:\chess\tablebases\gtb}

to turn table base use off or configure where the tablebases reside on a particular computer.

There are too many possible commands for it to be worth listing them here, but another usefule UCI command for testing is to specify the search routine as follows.

1 uci {setoption name Search Routine value Development}


verdict moves

1 verdict {e4 e5 Nf3}
2 verdict {Nf3 Nc6 Ng1 Nb8 Nf3 Nc6 Ng1 Nb8 Nf3}


3 fold

The possible return values are

"50 move",
"3 fold",

Some of the other commands

There are other Sidonia Interpreter commands not yet documented. These include

foreach_epd epdtext