Stockfish eval output

Discussion of anything and everything relating to chess playing software and machines.

Moderators: hgm, Rebel, chrisw

Ferdy
Posts: 4833
Joined: Sun Aug 10, 2008 3:15 pm
Location: Philippines

Re: Stockfish eval output

Post by Ferdy »

zenpawn wrote:On the topic of static evals, is there a way/program to run through a PGN to get the evaluations of the positions along the way without the engine doing any search? I came close by setting Fritz 15 to perform its blunder check with depth 1 and margin (to consider a move a blunder) of 0.
Created one using python-chess lib.
Read the upper part of the code, sections E, F and H for instructions. Note this will only work with stockfish, utilizing the eval command after position setup.

sf_staticeval.py

Code: Select all

"""
A. Program name
Stockfish static eval

B. Program description
Read pgn and annotate the game with Stockfish static eval.

C. License notice

This program is free software, you can redistribute it and/or modify
it under the terms of the GPLv3 License as published by the
Free Software Foundation.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY. See the GNU General Public License
for more details.

You should have received a copy of the GNU General Public License (LICENSE)
along with this program, if not visit https://www.gnu.org/licenses/gpl.html

D. Program version development log
version 1
1. Annotate a pgn file with Stockfish static eval

E. Dependent modules and/or programs
1. python-chess
https://pypi.python.org/pypi/python-chess

F. Programming language
1. Python v2.7.11
https://www.python.org/

G. Program other info
1. filename: sf_staticeval.py
2. version: 1
3. author: ferdy
4. created: Oct 3, 2016

H. Tests and Guide
1. This is tested under Windows 7 OS, python 2.7.11
   and python-chess 0.14.1.
2. You need to install python 2.7 version (or later but not tested)
   on your computer.
3. You need to install python-chess on your computer, see section E.
4. Rename your input pgn file to src.pgn.
5. Rename your engine to stockfish.exe.
6. The output filename is out_src.pgn, this is overwrite mode.

"""

import subprocess
import os
import sys
import chess
from chess import pgn
    
def DeleteFile(fn):
    """ Delete fn file """
    if os.path.isfile(fn):
        os.remove(fn)

def GetEngineIdName(engine):
    """ Returns the engine id name """
    engineIdName = engine[0:-4]

    # Run the engine
    p = subprocess.Popen(engine, stdin=subprocess.PIPE,
                         stdout=subprocess.PIPE,
                         stderr=subprocess.STDOUT)

    # Send command
    p.stdin.write("uci\n")
    for eline in iter(p.stdout.readline, ''):
        line = eline.strip()

        # Print engine output after uci command
        print(line)

        # Save id name
        if 'id name ' in line:
            idName = line.split()
            engineIdName = ' '.join(idName[2:])            
        if "uciok" in line:           
            break
    p.stdin.write('quit\n')
    p.communicate()
    return engineIdName    

def EvaluatePosition(engine, pos):
    """ Run stockfish, setup position pos and send
        eval command to get its static eval score
    """
    score = -32000.0

    # Run the engine
    p = subprocess.Popen(engine, stdin=subprocess.PIPE,
                         stdout=subprocess.PIPE,
                         stderr=subprocess.STDOUT)

    # Send commands to engine
    p.stdin.write("uci\n")

    # Parse engine replies
    for eline in iter(p.stdout.readline, ''):
        line = eline.strip()
        if "uciok" in line:
            break
    p.stdin.write("isready\n")
    for eline in iter(p.stdout.readline, ''):
        line = eline.strip()
        if "readyok" in line:
            break
    p.stdin.write("ucinewgame\n")
    p.stdin.write("position fen " + pos + "\n")
    p.stdin.write("eval\n")

    # Parse the output and extract the score
    for eline in iter(p.stdout.readline, ''):        
        line = eline.strip()
        if 'Total Evaluation: ' in line:
            first = line.split('(')[0]
            score = float(first.split()[2])
            break
    p.stdin.write('quit\n')
    p.communicate()
    assert score != -32000.0, 'Something is wrong in the eval'
    return score    

def main(argv):
    """ start """
    inputFile = 'src.pgn'
    outputFile = 'out_src.pgn'
    engineName = 'stockfish.exe'

    # Delete existing 'out-src.pgn'
    DeleteFile(outputFile)

    # Get engine id name for the Annotator tag
    engIdName = GetEngineIdName(engineName)

    # Open the input pgn file
    pgnHandle = open(inputFile, 'r')

    # Read the input pgn file
    game = chess.pgn.read_game(pgnHandle)
    game_cnt = 0

    # Loop thru the games
    while game:
        game_cnt += 1
        print('Annotating game %d...' %(game_cnt))       

        # Save the tag section of the game
        for key, value in game.headers.items():
            with open(outputFile, 'a+') as f:
                f.write('[%s "%s"]\n' %(key, value))

        # Write the annotator tag
        with open(outputFile, 'a+') as f:
            f.write('[Annotator "%s"]\n\n' %(engIdName))

        # Save result to be written later at end of game of every game
        res = game.headers['Result']

        # Loop thru the moves
        gameNode = game        
        while gameNode.variations:
            side = gameNode.board().turn
            fen = gameNode.board().fen()
            fmvn = gameNode.board().fullmove_number             
            nextNode = gameNode.variation(0)                      
            sanMove = nextNode.san()

            # Get Stockfish static eval
            staticEval = EvaluatePosition(engineName, fen)

            # Write the move and score as comment
            with open(outputFile, 'a+') as f:
                if side:
                    f.write('%d. %s {%+0.2f} ' %(fmvn, sanMove, staticEval))
                else:
                    f.write(' %s {%+0.2f} ' %(sanMove, staticEval))

                    # Don't write in one long line
                    if fmvn % 3 == 0:
                        f.write('\n')

            # Read the next position
            gameNode = nextNode

        # Write the result and a space between games
        with open(outputFile, 'a') as f:
            f.write(' %s\n\n' %(res))

        # Read the next game 
        game = chess.pgn.read_game(pgnHandle)

    # Close the file handle
    pgnHandle.close()  

    print('Done!!\n')    

if __name__ == "__main__":
    main(sys.argv[1:])



Sample output.

Code: Select all

[Event "4th Sinquefield Cup 2016"]
[Site "Saint Louis USA"]
[Date "2016.08.05"]
[Round "1.1"]
[White "Giri, Anish"]
[Black "Vachier-Lagrave, Maxime"]
[Result "1/2-1/2"]
[WhiteTitle "GM"]
[BlackTitle "GM"]
[WhiteElo "2769"]
[BlackElo "2819"]
[ECO "B90"]
[Opening "Sicilian"]
[Variation "Najdorf"]
[WhiteFideId "24116068"]
[BlackFideId "623539"]
[EventDate "2016.08.05"]
[Annotator "Stockfish 7 64 POPCNT"]

1. e4 {+0.08}  c5 {+0.74} 2. Nf3 {+0.65}  d6 {+0.95} 3. d4 {+0.39}  cxd4 {+1.12} 
4. Nxd4 {+0.35}  Nf6 {+1.17} 5. Nc3 {+0.54}  a6 {+1.06} 6. Be3 {+0.98}  Ng4 {+1.11} 
7. Bc1 {+1.14}  Nf6 {+0.85} 8. f3 {+0.98}  e5 {+0.90} 9. Nb3 {+0.27}  Be6 {+0.62} 
10. Be3 {+0.30}  Be7 {+0.58} 11. Qd2 {+0.52}  O-O {+0.46} 12. O-O-O {-0.18}  Nbd7 {+0.12} 
13. g4 {-0.21}  b5 {-0.25} 14. g5 {-0.26}  b4 {+0.16} 15. gxf6 {-0.14}  bxc3 {+3.36} 
16. Qxc3 {-0.52}  Nxf6 {+1.16} 17. Na5 {-0.34}  Rc8 {-0.47} 18. Nc6 {-0.47}  Qe8 {+0.22} 
19. Nxe7+ {+0.21}  Qxe7 {+3.73} 20. Qa5 {-0.14}  Rc6 {-0.36} 21. Kb1 {-0.37}  Rfc8 {-0.05} 
22. Rd2 {-0.54}  Nh5 {-0.41} 23. Rg1 {-0.20}  Qh4 {-0.02} 24. Be2 {-0.53}  Nf4 {+0.05} 
25. Bd1 {-0.25}  f5 {-0.41} 26. exf5 {-0.19}  Bxf5 {+0.34} 27. Ka1 {-0.51}  d5 {-0.55} 
28. c3 {-0.83}  Rg6 {-0.71} 29. Rxg6 {-0.64}  hxg6 {+3.83} 30. Bxf4 {+0.31}  Qxf4 {+3.97} 
31. Qxd5+ {-0.26}  Kh7 {+1.24} 32. Bb3 {+1.40}  a5 {+1.57} 33. a4 {+1.69}  Re8 {+1.52} 
34. Ka2 {+1.79}  Be6 {+1.68} 35. Qc6 {+1.64}  Bxb3+ {+1.05} 36. Kxb3 {-2.23}  Rb8+ {+0.90} 
37. Kc2 {+0.95}  Rxb2+ {+0.38} 38. Kxb2 {-0.44}  Qxd2+ {+5.69} 39. Kb3 {+0.30}  Qxh2 {+0.06} 
40. Qd5 {-0.03}  Qe2 {+0.07} 41. Qxa5 {+0.03}  Qd1+ {+0.16} 42. Kb2 {+0.73}  Qd2+ {+0.06} 
43. Kb3 {+0.66}  Qd1+ {+0.44} 44. Kb2 {+0.73}  Qd2+ {+0.06} 45. Ka3 {+0.66}  Qc1+ {+0.24} 
46. Kb4 {+0.72}  Qb1+ {+0.48} 47. Ka3 {+1.17}  1/2-1/2

[Event "4th Sinquefield Cup 2016"]
[Site "Saint Louis USA"]
[Date "2016.08.05"]
[Round "1.2"]
[White "Anand, Viswanathan"]
[Black "Caruana, Fabiano"]
[Result "1/2-1/2"]
[WhiteTitle "GM"]
[BlackTitle "GM"]
[WhiteElo "2770"]
[BlackElo "2807"]
[ECO "C15"]
[Opening "French"]
[Variation "Winawer (Nimzovich) variation"]
[WhiteFideId "5000017"]
[BlackFideId "2020009"]
[EventDate "2016.08.05"]
[Annotator "Stockfish 7 64 POPCNT"]

1. e4 {+0.08}  e6 {+0.74} 2. d4 {+0.13}  d5 {+0.91} 3. Nc3 {+0.31}  Bb4 {+0.77} 
4. exd5 {+0.17}  exd5 {+0.75} 5. Bd3 {-0.07}  Nf6 {+0.02} 6. Ne2 {-0.34}  O-O {-0.12} 
7. O-O {-0.75}  c6 {+0.21} 8. Bg5 {+0.04}  h6 {+0.28} 9. Bh4 {-0.20}  Re8 {-0.20} 
10. f3 {-0.46}  Nbd7 {-0.35} 11. Qd2 {-0.34}  Nf8 {-0.46} 12. Rae1 {-0.33}  Bd7 {-0.22} 
13. a3 {-0.30}  Be7 {+0.20} 14. Bf2 {+0.21}  Ng6 {+0.17} 15. Bg3 {+0.25}  Nh5 {+0.26} 
16. Bxg6 {+0.33}  fxg6 {+3.64} 17. Be5 {+0.17}  Bh4 {+0.27} 18. Rd1 {+0.04}  Bg5 {+0.03} 
19. f4 {-0.00}  Be7 {+0.34} 20. h3 {+0.07}  Be6 {+0.00} 21. Kh2 {+0.12}  Nf6 {-0.47} 
22. Nc1 {-0.13}  h5 {-0.59} 23. Nd3 {-0.22}  Bf5 {+0.14} 24. Ne2 {-0.15}  Ne4 {-0.37} 
25. Qe3 {-0.92}  h4 {-0.93} 26. Rc1 {-0.76}  Rc8 {-0.98} 27. c3 {-0.83}  Qb6 {-0.82} 
28. b4 {-0.69}  Bf6 {-1.01} 29. Nc5 {-1.07}  Nxc5 {-1.12} 30. bxc5 {-3.48}  Qb2 {+0.38} 
31. Ng1 {-0.45}  b6 {-1.62} 32. Nf3 {-1.36}  bxc5 {-1.42} 33. dxc5 {-1.95}  Be4 {-1.84} 
34. Rce1 {-1.11}  Re7 {-1.09} 35. Bxf6 {-0.81}  gxf6 {+2.68} 36. Nxh4 {-0.83}  Rce8 {-0.13} 
37. Qg3 {-0.19}  Rg7 {-0.44} 38. Ra1 {-0.07}  g5 {-0.25} 39. fxg5 {-0.86}  Rxg5 {+1.15} 
40. Qf2 {-0.09}  Qxc3 {-0.26} 41. Qxf6 {-1.65}  Qg3+ {+1.83} 42. Kg1 {+3.78}  Qxg2+ {+2.36} 
43. Nxg2 {-0.44}  Rxg2+ {+11.77} 44. Kh1 {+8.47}  Rf2+ {+8.16} 45. Kg1 {+8.09}  1/2-1/2

[Event "4th Sinquefield Cup 2016"]
[Site "Saint Louis USA"]
[Date "2016.08.05"]
[Round "1.3"]
[White "So, Wesley"]
[Black "Nakamura, Hikaru"]
[Result "1-0"]
[WhiteTitle "GM"]
[BlackTitle "GM"]
[WhiteElo "2771"]
[BlackElo "2791"]
[ECO "E06"]
[Opening "Catalan"]
[Variation "closed, 5.Nf3"]
[WhiteFideId "5202213"]
[BlackFideId "2016192"]
[EventDate "2016.08.05"]
[Annotator "Stockfish 7 64 POPCNT"]

1. d4 {+0.08}  Nf6 {+0.70} 2. c4 {+0.27}  e6 {+0.48} 3. Nf3 {+0.02}  d5 {+0.44} 
4. g3 {-0.21}  Be7 {-0.19} 5. Bg2 {-0.20}  O-O {-0.10} 6. O-O {-0.71}  dxc4 {-0.07} 
7. Ne5 {-0.67}  Nc6 {-0.31} 8. Nxc6 {-0.68}  bxc6 {+2.47} 9. Na3 {-0.41}  Bxa3 {-0.38} 
10. bxa3 {-2.81}  Ba6 {-0.41} 11. Qd2 {-0.46}  Rb8 {-0.33} 12. Qa5 {-0.52}  Qc8 {-0.75} 
13. a4 {-0.55}  Rd8 {-0.62} 14. Ba3 {-0.80}  Rxd4 {-0.67} 15. Rfb1 {-1.17}  Rb6 {-1.01} 
16. Bc5 {-1.19}  Rd7 {-0.60} 17. Rd1 {-0.95}  h6 {-0.97} 18. Rxd7 {-0.90}  Nxd7 {+4.09} 
19. Bxb6 {-1.24}  cxb6 {+3.54} 20. Qd2 {-1.51}  c5 {-0.47} 21. Rd1 {-0.26}  Nf6 {+0.17} 
22. Kf1 {+0.10}  Kh7 {-0.02} 23. Qc2+ {+0.30}  Kg8 {-0.09} 24. Qd2 {+0.03}  Kh7 {-0.02} 
25. Qd8 {+0.30}  Qxd8 {-0.09} 26. Rxd8 {-10.43}  c3 {-0.40} 27. Ke1 {-1.19}  Bc4 {-1.08} 
28. Kd1 {-1.23}  Bxa2 {-0.35} 29. Kc2 {-0.46}  Bc4 {+0.44} 30. e3 {-0.15}  b5 {+0.27} 
31. Kxc3 {+0.28}  a6 {+0.40} 32. Ra8 {+0.61}  Nd5+ {+0.60} 33. Bxd5 {+0.60}  exd5 {+3.66} 
34. a5 {+0.74}  b4+ {+0.58} 35. Kd2 {+0.49}  Bf1 {-0.57} 36. Rc8 {-0.24}  c4 {+0.17} 
37. Rb8 {-0.22}  b3 {+0.57} 38. Kc3 {+0.76}  1-0

[Event "4th Sinquefield Cup 2016"]
[Site "Saint Louis USA"]
[Date "2016.08.05"]
[Round "1.4"]
[White "Ding, Liren"]
[Black "Aronian, Levon"]
[Result "1/2-1/2"]
[WhiteTitle "GM"]
[BlackTitle "GM"]
[WhiteElo "2755"]
[BlackElo "2792"]
[ECO "D37"]
[Opening "QGD"]
[Variation "4.Nf3"]
[WhiteFideId "8603677"]
[BlackFideId "13300474"]
[EventDate "2016.08.05"]
[Annotator "Stockfish 7 64 POPCNT"]

1. d4 {+0.08}  Nf6 {+0.70} 2. c4 {+0.27}  e6 {+0.48} 3. Nf3 {+0.02}  d5 {+0.44} 
4. Nc3 {-0.21}  Nbd7 {+0.09} 5. Bg5 {-0.07}  h6 {+0.20} 6. Bh4 {-0.23}  Be7 {-0.41} 
7. e3 {-0.45}  O-O {+0.17} 8. Rc1 {-0.38}  c5 {-0.52} 9. dxc5 {-0.60}  dxc4 {-0.40} 
10. Bxc4 {-0.61}  Nxc5 {+0.24} 11. O-O {-0.52}  a6 {+0.20} 12. Nd4 {+0.14}  Nce4 {-0.03} 
13. Nxe4 {+0.15}  Nxe4 {+3.50} 14. Bxe7 {+0.02}  Qxe7 {+4.79} 15. Qc2 {+0.57}  Nf6 {+0.57} 
16. Bb3 {+0.70}  Rb8 {+0.95} 17. e4 {+1.12}  Rd8 {+0.99} 18. Rfd1 {+0.54}  e5 {+0.84} 
19. Nf5 {+0.34}  Bxf5 {+1.88} 20. exf5 {-2.32}  Rxd1+ {+0.29} 21. Rxd1 {-4.90}  e4 {+0.34} 
22. Qc3 {+0.50}  Rd8 {+0.47} 23. Rxd8+ {+0.22}  Qxd8 {+5.59} 24. h3 {+0.24}  h5 {+0.04} 
25. Qe5 {+0.25}  b5 {+0.10} 26. g3 {+0.16}  Qd7 {-0.09} 27. g4 {+0.15}  hxg4 {+0.19} 
28. hxg4 {-1.13}  Nxg4 {+0.03} 29. Qxe4 {-0.91}  Nf6 {+0.04} 30. Qa8+ {-0.17}  Kh7 {+0.02} 
31. Qh1+ {+0.12}  1/2-1/2

[Event "4th Sinquefield Cup 2016"]
[Site "Saint Louis USA"]
[Date "2016.08.05"]
[Round "1.5"]
[White "Topalov, Veselin"]
[Black "Svidler, Peter"]
[Result "1-0"]
[WhiteTitle "GM"]
[BlackTitle "GM"]
[WhiteElo "2761"]
[BlackElo "2751"]
[ECO "C88"]
[Opening "Ruy Lopez"]
[Variation "closed, anti-Marshall 8.a4"]
[WhiteFideId "2900084"]
[BlackFideId "4102142"]
[EventDate "2016.08.05"]
[Annotator "Stockfish 7 64 POPCNT"]

1. e4 {+0.08}  e5 {+0.74} 2. Nf3 {+0.08}  Nc6 {+0.59} 3. Bb5 {+0.07}  a6 {+0.16} 
4. Ba4 {-0.36}  Nf6 {-0.36} 5. O-O {-0.87}  Be7 {-0.26} 6. Re1 {-0.20}  b5 {-0.17} 
7. Bb3 {-0.78}  O-O {+0.07} 8. a4 {-0.57}  b4 {-0.65} 9. d3 {-0.52}  d6 {+0.09} 
10. a5 {-0.26}  Be6 {-0.34} 11. Bxe6 {-0.47}  fxe6 {+2.69} 12. Nbd2 {-0.48}  d5 {-0.20} 
13. c3 {-0.22}  Bd6 {-0.31} 14. d4 {-0.12}  bxc3 {+0.05} 15. bxc3 {-1.21}  exd4 {-0.02} 
16. cxd4 {-1.23}  dxe4 {+0.21} 17. Nxe4 {-1.26}  Bb4 {+0.62} 18. Bd2 {+0.16}  Nxe4 {+0.60} 
19. Rxe4 {-3.10}  Qd5 {+0.44} 20. Bxb4 {+0.13}  Qxe4 {+3.81} 21. Bxf8 {-1.11}  Rxf8 {+3.20} 
22. Rc1 {+0.10}  h6 {+0.14} 23. Qd2 {+0.25}  Rb8 {+0.30} 24. Qe3 {+0.35}  Qd5 {+0.21} 
25. h3 {+0.20}  Rb4 {+0.09} 26. Qc3 {+0.16}  Nxd4 {-0.03} 27. Qxb4 {-0.52}  Ne2+ {+4.90} 
28. Kh1 {+4.84}  1-0
zenpawn
Posts: 349
Joined: Sat Aug 06, 2016 8:31 pm
Location: United States

Re: Stockfish eval output

Post by zenpawn »

Ferdy wrote:
zenpawn wrote:On the topic of static evals, is there a way/program to run through a PGN to get the evaluations of the positions along the way without the engine doing any search? I came close by setting Fritz 15 to perform its blunder check with depth 1 and margin (to consider a move a blunder) of 0.
Created one using python-chess lib.
Thanks for sharing this, Ferdinand!
Ferdy
Posts: 4833
Joined: Sun Aug 10, 2008 3:15 pm
Location: Philippines

Re: Stockfish eval output

Post by Ferdy »

zenpawn wrote:
Ferdy wrote:
zenpawn wrote:On the topic of static evals, is there a way/program to run through a PGN to get the evaluations of the positions along the way without the engine doing any search? I came close by setting Fritz 15 to perform its blunder check with depth 1 and margin (to consider a move a blunder) of 0.
Created one using python-chess lib.
Thanks for sharing this, Ferdinand!
Opps there was bug, the static eval extracted was the eval before the move is played. Now in version 2, the static eval is after the move is played.

The part that was changed:

Code: Select all

# Use FEN after a move to get the static eval
fen = nextNode.board().fen()
sf_staticeval_v2.py

Code: Select all

"""
A. Program name
Stockfish static eval

B. Program description
Read pgn and annotate the game with Stockfish static eval.

C. License notice

This program is free software, you can redistribute it and/or modify
it under the terms of the GPLv3 License as published by the
Free Software Foundation.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY. See the GNU General Public License
for more details.

You should have received a copy of the GNU General Public License (LICENSE)
along with this program, if not visit https://www.gnu.org/licenses/gpl.html

D. Program version development log
version 2
1. Output static eval after a move is played. In version 1 the static
   eval written in pgn is the score before the move is played.

version 1
1. Annotate a pgn file with Stockfish static eval.

E. Dependent modules and/or programs
1. python-chess
https://pypi.python.org/pypi/python-chess

F. Programming language
1. Python v2.7.11
https://www.python.org/

G. Program other info
1. filename: sf_staticeval_v2.py
2. version: 2
3. author: ferdy
4. created: Oct 3, 2016

H. Tests and Guide
1. This is tested under Windows 7 OS, python 2.7.11
   and python-chess 0.14.1.
2. You need to install python 2.7 version (or later but not tested)
   on your computer.
3. You need to install python-chess on your computer, see section E.
4. Rename your input pgn file to src.pgn.
5. Rename your engine to stockfish.exe.
6. The output filename is out_src.pgn, this is overwrite mode.

"""

import subprocess
import os
import sys
import chess
from chess import pgn
    
def DeleteFile(fn):
    """ Delete fn file """
    if os.path.isfile(fn):
        os.remove(fn)

def GetEngineIdName(engine):
    """ Returns the engine id name """
    engineIdName = engine[0:-4]

    # Run the engine
    p = subprocess.Popen(engine, stdin=subprocess.PIPE,
                         stdout=subprocess.PIPE,
                         stderr=subprocess.STDOUT)

    # Send command
    p.stdin.write("uci\n")
    for eline in iter(p.stdout.readline, ''):
        line = eline.strip()

        # Print engine output after uci command
        print(line)

        # Save id name
        if 'id name ' in line:
            idName = line.split()
            engineIdName = ' '.join(idName[2:])            
        if "uciok" in line:           
            break
    p.stdin.write('quit\n')
    p.communicate()
    return engineIdName    

def EvaluatePosition(engine, pos):
    """ Run stockfish, setup position pos and send
        eval command to get its static eval score
    """
    score = -32000.0

    # Run the engine
    p = subprocess.Popen(engine, stdin=subprocess.PIPE,
                         stdout=subprocess.PIPE,
                         stderr=subprocess.STDOUT)

    # Send commands to engine
    p.stdin.write("uci\n")

    # Parse engine replies
    for eline in iter(p.stdout.readline, ''):
        line = eline.strip()
        if "uciok" in line:
            break
    p.stdin.write("isready\n")
    for eline in iter(p.stdout.readline, ''):
        line = eline.strip()
        if "readyok" in line:
            break
    p.stdin.write("ucinewgame\n")
    p.stdin.write("position fen " + pos + "\n")
    p.stdin.write("eval\n")

    # Parse the output and extract the score
    for eline in iter(p.stdout.readline, ''):        
        line = eline.strip()
        if 'Total Evaluation: ' in line:
            first = line.split('(')[0]
            score = float(first.split()[2])
            break
    p.stdin.write('quit\n')
    p.communicate()
    assert score != -32000.0, 'Something is wrong in the eval'
    return score    

def main(argv):
    """ start """
    inputFile = 'src.pgn'
    outputFile = 'out_src.pgn'
    engineName = 'stockfish.exe'

    # Delete existing 'out-src.pgn'
    DeleteFile(outputFile)

    # Get engine id name for the Annotator tag
    engIdName = GetEngineIdName(engineName)

    # Open the input pgn file
    pgnHandle = open(inputFile, 'r')

    # Read the input pgn file
    game = chess.pgn.read_game(pgnHandle)
    game_cnt = 0

    # Loop thru the games
    while game:
        game_cnt += 1
        print('Annotating game %d...' %(game_cnt))       

        # Save the tag section of the game
        for key, value in game.headers.items():
            with open(outputFile, 'a+') as f:
                f.write('[%s "%s"]\n' %(key, value))

        # Write the annotator tag
        with open(outputFile, 'a+') as f:
            f.write('[Annotator "%s"]\n\n' %(engIdName))

        # Save result to be written later at end of game of every game
        res = game.headers['Result']

        # Loop thru the moves
        gameNode = game        
        while gameNode.variations:
            side = gameNode.board().turn
            fmvn = gameNode.board().fullmove_number             
            nextNode = gameNode.variation(0)                      
            sanMove = nextNode.san()

            # Use FEN after a move to get the static eval
            fen = nextNode.board().fen()

            # Get Stockfish static eval
            staticEval = EvaluatePosition(engineName, fen)

            # Write the move and score as comment
            with open(outputFile, 'a+') as f:
                if side:
                    f.write('%d. %s {%+0.2f} ' %(fmvn, sanMove, staticEval))
                else:
                    f.write('%s {%+0.2f} ' %(sanMove, staticEval))

                    # Don't write in one long line
                    if fmvn % 3 == 0:
                        f.write('\n')

            # Read the next position
            gameNode = nextNode

        # Write the result and a space between games
        with open(outputFile, 'a') as f:
            f.write(' %s\n\n' %(res))

        # Read the next game 
        game = chess.pgn.read_game(pgnHandle)

    # Close the file handle
    pgnHandle.close()  

    print('Done!!\n')    

if __name__ == "__main__":
    main(sys.argv[1:])
Example 1:

Code: Select all

1. d4 {+0.70}

Code: Select all

position startpos moves d2d4
eval
      Eval term |    White    |    Black    |    Total
                |   MG    EG  |   MG    EG  |   MG    EG
----------------+-------------+-------------+-------------
       Material |   ---   --- |   ---   --- |  0.11 -0.00
      Imbalance |   ---   --- |   ---   --- |  0.00  0.00
          Pawns |   ---   --- |   ---   --- | -0.02 -0.01
        Knights |  0.12  0.00 |  0.12  0.00 |  0.00  0.00
         Bishop | -0.12 -0.37 | -0.12 -0.37 |  0.00  0.00
          Rooks | -0.27  0.00 | -0.27  0.00 |  0.00  0.00
         Queens |  0.00  0.00 |  0.00  0.00 |  0.00  0.00
       Mobility | -0.22 -0.28 | -0.73 -0.84 |  0.51  0.56
    King safety |  0.89 -0.06 |  0.89 -0.06 |  0.00  0.00
        Threats |  0.00  0.00 |  0.00  0.00 |  0.00  0.00
   Passed pawns |  0.00  0.00 |  0.00  0.00 |  0.00  0.00
          Space |  0.45  0.00 |  0.27  0.00 |  0.18  0.00
----------------+-------------+-------------+-------------
          Total |   ---   --- |   ---   --- |  0.78  0.58

Total Evaluation: 0.70 (white side)
Example 2:

Code: Select all

1. e4 {+0.74} e5 {+0.08} 2. Nf3 {+0.59}

Code: Select all

position startpos moves e2e4 e7e5 g1f3
eval
      Eval term |    White    |    Black    |    Total
                |   MG    EG  |   MG    EG  |   MG    EG
----------------+-------------+-------------+-------------
       Material |   ---   --- |   ---   --- |  0.37  0.29
      Imbalance |   ---   --- |   ---   --- |  0.00  0.00
          Pawns |   ---   --- |   ---   --- |  0.00  0.00
        Knights |  0.06  0.00 |  0.12  0.00 | -0.06  0.00
         Bishop | -0.12 -0.37 | -0.12 -0.37 |  0.00  0.00
          Rooks | -0.19  0.00 | -0.27  0.00 |  0.09  0.00
         Queens |  0.00  0.00 |  0.00  0.00 |  0.00  0.00
       Mobility | -0.18 -0.12 | -0.26 -0.34 |  0.09  0.23
    King safety |  0.93 -0.06 |  0.93 -0.06 |  0.00  0.00
        Threats |  0.19  0.24 |  0.00  0.00 |  0.19  0.24
   Passed pawns |  0.00  0.00 |  0.00  0.00 |  0.00  0.00
          Space |  0.36  0.00 |  0.36  0.00 |  0.00  0.00
----------------+-------------+-------------+-------------
          Total |   ---   --- |   ---   --- |  0.67  0.78

Total Evaluation: 0.59 (white side)
zenpawn
Posts: 349
Joined: Sat Aug 06, 2016 8:31 pm
Location: United States

Re: Stockfish eval output

Post by zenpawn »

Ferdy wrote: Opps there was bug, the static eval extracted was the eval before the move is played. Now in version 2, the static eval is after the move is played.
Thanks for the correction. It's working beautifully.
Ferdy
Posts: 4833
Joined: Sun Aug 10, 2008 3:15 pm
Location: Philippines

Re: Stockfish eval output

Post by Ferdy »

zenpawn wrote:
Ferdy wrote: Opps there was bug, the static eval extracted was the eval before the move is played. Now in version 2, the static eval is after the move is played.
Thanks for the correction. It's working beautifully.
Created a repo in github based on this, and hope to expand it to include engine search score, variations, books and others.

https://github.com/fsmosca/chess-artist