I'm using Stockfish in R via https://github.com/curso-r/stockfish.
I can execute anything that I could in the CLI using engine$run(command)
. For example,
engine <- fish$new()
engine$position("rnbqkbnr/pp2pp1p/2p3p1/3p4/4P3/2NB4/PPPP1PPP/R1BQK1NR w KQkq - 0 4")
engine$run("eval")
results in this output:
[1] ""
[2] " Contributing terms for the classical eval:"
[3] "+------------+-------------+-------------+-------------+"
[4] "| Term | White | Black | Total |"
[5] "| | MG EG | MG EG | MG EG |"
[6] "+------------+-------------+-------------+-------------+"
[7] "| Material | ---- ---- | ---- ---- | 0.68 0.42 |"
[8] "| Imbalance | ---- ---- | ---- ---- | 0.00 0.00 |"
[9] "| Pawns | 0.34 -0.07 | 0.74 0.00 | -0.40 -0.07 |"
[10] "| Knights | -0.07 -0.16 | -0.11 -0.20 | 0.04 0.04 |"
[11] "| Bishops | -0.30 -0.98 | -0.08 -0.42 | -0.22 -0.55 |"
[12] "| Rooks | -0.26 -0.06 | -0.26 -0.06 | 0.00 0.00 |"
[13] "| Queens | 0.00 0.00 | 0.00 0.00 | 0.00 0.00 |"
[14] "| Mobility | -0.22 -0.29 | -0.03 -0.14 | -0.19 -0.15 |"
[15] "|King safety | 0.84 -0.10 | 0.54 -0.10 | 0.30 0.00 |"
[16] "| Threats | 0.07 0.07 | 0.37 0.32 | -0.30 -0.25 |"
[17] "| Passed | 0.00 0.00 | 0.00 0.00 | 0.00 0.00 |"
[18] "| Space | 0.46 0.00 | 0.50 0.00 | -0.05 0.00 |"
[19] "| Winnable | ---- ---- | ---- ---- | 0.00 -0.19 |"
[20] "+------------+-------------+-------------+-------------+"
[21] "| Total | ---- ---- | ---- ---- | -0.13 -0.75 |"
[22] "+------------+-------------+-------------+-------------+"
[23] ""
[24] "Classical evaluation -0.08 (white side)"
[25] "Final evaluation -0.08 (white side)"
I want to return just the final evaluation value, -0.08. I could just write some code that takes the above string and returns the number after "Final evaluation", but I would rather have the computer do less work than that, or at least have a more elegant solution. In src/evaluation.cpp of the Stockfish source code, this is
v = Evaluation<TRACE>(pos).value();
v = pos.side_to_move() == WHITE ? v : -v;
Of course, I don't really want to fork Stockfish just to get that number. Is there a command with certain parameters that can calculate and return just the evaluation? Stockfish's documentation is surprisingly limited unless there are some docs I'm missing.
I would also like to get the engine including the NNUE evaluation and not just the classical. If I use the Stockfish 15.1 executable, this is done in the CLI with
$ position fen "rnbqkbnr/pp2pp1p/2p3p1/3p4/4P3/2NB4/PPPP1PPP/R1BQK1NR w KQkq - 0 4"
$ eval
Adjusting the analysis depth or thinking time would be ideal. (I haven't been able to find that in the documentation.)
How to analyze position score in Stockfish is a closely related question, but I need to solve this within R or plain Stockfish.
This is a solution for the part about including NNUE and controlling the depth.
It isn't a solution to the "only evaluation score and nothing else" problem; but as Cole commented, it might be the best we can do without a custom SF implementation.
library(tidyverse) # stringr (str_*), magrittr (%>%)
library(stockfish) # fish
library(parallel) # for detectCores()
# Get score of position.
# `side` determines which player to evaluate for
evaluate <- function(engine, fen, side = "w", depth = 30) {
engine$position(fen)
eval <- engine$run(paste("go depth", depth)) %>%
# correct instructions here might vary by engine
.[length(.) - 1] %>%
str_extract("(?<=score ).+(?= nodes)")
if ((side %in% c("b", "black") && str_detect(fen, " w ")) ||
(side %in% c("w", "white") && str_detect(fen, " b ")) ) {
eval <- str_replace(eval, "(\\d+)", "-\\1") %>%
str_replace("--", "") # remove double negative
}
return(eval)
}
# Load a UCI engine
engine <- fish$new("engines/stockfish_15.1_win64/stockfish-windows-2022-x86-64-avx2.exe")
engine$setoption(paste("threads", detectCores() - 1))
# Equal position
pos = "rnbqkbnr/pp2pp1p/2p3p1/3p4/4P3/2NB4/PPPP1PPP/R1BQK1NR w KQkq - 0 4"
evaluate(engine, pos, "w")
# Play a bad move
pos = "rnbqkbnr/pp2pp1p/2p3p1/3N4/4P3/3B4/PPPP1PPP/R1BQK1NR b KQkq - 0 4"
evaluate(engine, pos, "w")
stockfish - Description of the universal chess interface (UCI) is helpful. See especially, the Engine to GUI:
part about * info
(line 249, 12-26-2022).