7

I am looking for a way to return scores for all possible moves from a chess engine (preferably, Stockfish).

The UCI protocol does not seem to require it, but is seems like a useful feature to include.

Are there any chess engines/extensions of UCI that implement that?

  • 2
    Set multipv to a big number. – HelloWorld Oct 26 '16 at 13:10
  • wouldn't that just give me 100 different lines all starting with e4? – QuarterlyQuotaOfQuotes Oct 26 '16 at 16:18
  • 1
    Do you know what multi pv is? – HelloWorld Oct 26 '16 at 21:41
12

Of course there's a way: I'm going to show you one way of doing it on your own, using only free software. We'll write a small script in Python (I'm using v2.7) and only use the wonderful python-chess library (licensed under GPL3, note that I'm using the version 0.14.0).

In short, the script will first load up the engine, we will stick to free and open source software so we'll use the amazing Stockfish engine [*], then create a board instance of the position you want analyzed (using the FEN notation), generate all legal moves, and finally ask the engine to evaluate each move for a predefined amount of time (in this example it is set to 1 second ponder time). Here's a working sample:

import chess
import chess.uci

#Let's try our code with the starting position of chess:
fen = 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1'
board = chess.Board(fen)
handler = chess.uci.InfoHandler()

#Now make sure you give the correct location for your stockfish engine file
#...in the line that follows: e.g., /home/.../stockfish_6_x64
engine = chess.uci.popen_engine('stockfish_6_x64')

engine.info_handlers.append(handler)
engine.position(board)
if board.turn: print 'White to move'
else: print 'black to move'

for el in board.legal_moves:
    engine.go(searchmoves=[el],movetime=1000)
    print str(board.san(el)), 'eval = ', round(handler.info["score"][1].cp/100.0,2)

Note that this is not necessarily the best/most efficient way of doing it, I wrote this in 5 minutes just to showcase it at a basic level without using any advanced features of the engine, I'm sure you will do much better on your own. Anyhow here's the output once you run it (assuming you have python installed on whatever OS you're using, same goes for the python-chess library):

White to move
Na3 eval =  -0.39
Nc3 eval =  0.15
Nf3 eval =  0.15
Nh3 eval =  -0.37
a3 eval =  0.01
b3 eval =  -0.15
c3 eval =  -0.03
d3 eval =  -0.06
e3 eval =  0.12
f3 eval =  -0.49
g3 eval =  -0.33
h3 eval =  0.0
a4 eval =  -0.12
b4 eval =  -0.67
c4 eval =  0.07
d4 eval =  0.17
e4 eval =  0.17
f4 eval =  -0.15
g4 eval =  -0.74
h4 eval =  -0.15

There you go! The beauty of all this is of course the fact that you have now your own software to work with, modify and extend it as you wish...no limitations. All very easy to do, just acquaint yourself with the workings of the library we're using by following its documentation, and knock yourself out ;)

Don't hesitate to ask if you have any questions about the code, or adding potential functionalities.

[*]: which also happens to be one of the strongest current chess engines.


Edit to address the common request:

Here's the updated version of the same code using the latest version:

python-chess 0.30.0 and using the latest Stockfish

import chess
import chess.engine
import os

#here we assume the engine file is in same folder as our python script
path = os.getcwd()
#Let's try our code with the starting position of chess:
fen = 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1'
board = chess.Board(fen)
#Now make sure you give the correct location for your stockfish engine file
#...in the line that follows by correctly defining path
engine = chess.engine.SimpleEngine.popen_uci(path+'/'+'stockfish-10-64')

if board.turn: print('White to move')
else: print('black to move')

for el in board.legal_moves:
    info = engine.analyse(board, chess.engine.Limit(time=1), root_moves=[el])
    t = str(info["score"])
    if t.startswith('#'):
            print(str(board.san(el))," eval = mate in ", t)
    else: print(str(board.san(el))," eval = ", round(int(t)/100.,2))
engine.quit()

The output for ponder time set to 1 second per found move chess.engine.Limit(time=1):

White to move
Nh3  eval =  -0.43
Nf3  eval =  0.69
Nc3  eval =  0.29
Na3  eval =  -0.35
h3  eval =  0.41
g3  eval =  -0.2
f3  eval =  -0.62
e3  eval =  0.45
d3  eval =  0.03
c3  eval =  0.19
b3  eval =  0.1
a3  eval =  0.46
h4  eval =  -0.42
g4  eval =  -1.22
f4  eval =  -0.07
e4  eval =  0.82
d4  eval =  0.63
c4  eval =  0.57
b4  eval =  -0.26
a4  eval =  -0.02
  • 1
    can you update the code with last version of the lib please ? – shar Aug 6 '19 at 19:30
  • Seconding @shar's comment – Jordan Mackie Jan 6 at 22:56
  • 1
    @JordanMackie see the edit. – Phonon Jan 7 at 4:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.