为什么国际象棋会有不同的分数.引擎分析位置多次在同一脚本?



我是初学编程的,想做一个能检测错误的应用程序,想了解更多关于国际象棋的知识。引擎库。

我假设使用分析函数是一个离散的、自包含的过程,它不依赖于缓存或来自引擎的先前调用的内存或类似的东西。

如果是这种情况,为什么我在脚本中多次调用analyze时会得到多个不同的计算值:

import chess
import chess.engine
import os
# Loads board and engine
board = chess.Board("3r3k/pp5p/n1p2rp1/2P2p1n/1P2p3/PBNqP2P/5PP1/R2RB1K1 w - - 0 26")
engine = chess.engine.SimpleEngine.popen_uci(os.getcwd()+'/static/'+'stockfish')
#Sets engine depth constant
engine_depth = 10
# I'm assuming this is how to find the best move - arbitrary as I could have chosen any move in board.legal_moves
best_move = engine.play(board, chess.engine.Limit(depth=engine_depth)).move
# I'm assuming this is how to evaluate the score after a specific move from this position
info = engine.analyse(board, chess.engine.Limit(depth=engine_depth), root_moves=[best_move])
print(info["score"])
# Repeating the analysis call and printing the score 3 more times
info = engine.analyse(board, chess.engine.Limit(depth=engine_depth), root_moves=[best_move])
print(info["score"])
info = engine.analyse(board, chess.engine.Limit(depth=engine_depth), root_moves=[best_move])
print(info["score"])
info = engine.analyse(board, chess.engine.Limit(depth=engine_depth), root_moves=[best_move])
print(info["score"])
engine.quit()

输出:

PovScore(Cp(-21), WHITE)
PovScore(Cp(+2), WHITE)
PovScore(Cp(+19), WHITE)
PovScore(Cp(+63), WHITE)

在一定深度以上的各种发动机深度都会发生这种情况,但在深度较低时不会发生,例如高达3。
它以时间而不是深度为限制。
它出现在多个不同的起始位置。
它发生在多个不同的动作中。
即使每次调用之间有engine.quit()engine = chess.engine.SimpleEngine.popen_uci(os.getcwd()+'/static/'+'stockfish'),也会发生这种情况。

分析函数不能有随机元素,因为当我再次运行整个脚本时,我得到完全相同的分数。只是当它在同一脚本中多次调用同一位置时,每次都会给出不同的分数,好像它使用了某种缓存或者每次都在寻找更深的位置。

那么我在理解这是如何工作的时候哪里出错了呢?

编辑:

如果我删除root_moves参数(只是为了简化事情),然后替换:

print(info["score"])

:

for k, v in info.items():
print(k, v)

得到以下输出:

string NNUE evaluation using nn-82215d0fd0df.nnue enabled
depth 10
seldepth 13
multipv 1
score PovScore(Cp(+25), WHITE)
nodes 4396
nps 439600
tbhits 0
time 0.01
pv [Move.from_uci('d1d3'), Move.from_uci('e4d3'), Move.from_uci('a1d1'), Move.from_uci('a6c7'), Move.from_uci('c3a4'), Move.from_uci('f6f8'), Move.from_uci('a4b2'), Move.from_uci('h5f6'), Move.from_uci('b2d3'), Move.from_uci('d8d7')]
string NNUE evaluation using nn-82215d0fd0df.nnue enabled
depth 10
seldepth 15
multipv 1
score PovScore(Cp(+55), WHITE)
nodes 4072
nps 290857
tbhits 0
time 0.014
pv [Move.from_uci('d1d3'), Move.from_uci('e4d3'), Move.from_uci('a1d1'), Move.from_uci('a6c7'), Move.from_uci('c3a4'), Move.from_uci('c7b5'), Move.from_uci('a4b2'), Move.from_uci('b5a3'), Move.from_uci('b2d3'), Move.from_uci('a3b5')]
string NNUE evaluation using nn-82215d0fd0df.nnue enabled
depth 10
seldepth 16
multipv 1
score PovScore(Cp(+26), WHITE)
nodes 4514
nps 282125
tbhits 0
time 0.016
pv [Move.from_uci('d1d3'), Move.from_uci('e4d3'), Move.from_uci('a1d1'), Move.from_uci('a6c7'), Move.from_uci('c3a4'), Move.from_uci('c7b5'), Move.from_uci('a4b2'), Move.from_uci('h8g7'), Move.from_uci('b2d3'), Move.from_uci('f6f8')]
string NNUE evaluation using nn-82215d0fd0df.nnue enabled
depth 10
seldepth 12
multipv 1
score PovScore(Cp(+164), WHITE)
nodes 2018
nps 252250
tbhits 0
time 0.008
pv [Move.from_uci('d1d3'), Move.from_uci('d8d3'), Move.from_uci('b3c4'), Move.from_uci('d3d8'), Move.from_uci('c3e2'), Move.from_uci('h8g7'), Move.from_uci('e1c3')]

所以看起来我每次都得到不同的"seldepth"。seldepth到底是什么?我在文档中找不到足够的信息。

Stockfish是确定性的单线程分析与节点限制,状态和选项是相等的。

引擎状态主要是散列表(以及可能加载的Syzygy表基)。因此,您的第二次分析将利用第一次运行的散列表。第三次运行将重用第二次运行的哈希表结果,以此类推。

通常重用哈希表结果是可取的,并且可以提高强度,但是有一种方法可以重置引擎状态,清除哈希表。

在UCI协议中,这是通过发送提示来完成的:
ucinewgame

在python-chess中,这是通过使用game键自动管理的。

engine.analyse(..., game="key1")
engine.analyse(..., game="key1")
engine.analyse(..., game="key2")  # will clear previous state
engine.play(..., game="key2")
engine.analyse(..., game="key1")  # will clear previous state

键可以是任何对象,特别是object()不等于任何其他对象,因此总是会清除哈希表。


import chess
import chess.engine
board = chess.Board("3r3k/pp5p/n1p2rp1/2P2p1n/1P2p3/PBNqP2P/5PP1/R2RB1K1 w - - 0 26")
engine = chess.engine.SimpleEngine.popen_uci("stockfish")
engine_depth = 10
best_move = engine.play(board, chess.engine.Limit(depth=engine_depth), game=object()).move
info = engine.analyse(board, chess.engine.Limit(depth=engine_depth), game=object(), root_moves=[best_move])
print(info["score"])
info = engine.analyse(board, chess.engine.Limit(depth=engine_depth), game=object(), root_moves=[best_move])
print(info["score"])
info = engine.analyse(board, chess.engine.Limit(depth=engine_depth), game=object(), root_moves=[best_move])
print(info["score"])
info = engine.analyse(board, chess.engine.Limit(depth=engine_depth), game=object(), root_moves=[best_move])
print(info["score"])
engine.quit()
PovScore(Cp(+35), WHITE)
PovScore(Cp(+35), WHITE)
PovScore(Cp(+35), WHITE)
PovScore(Cp(+35), WHITE)

最新更新