Search code examples
c++rstockfish

How to retrieve Stockfish evaluation score with NNUE by itself using the Stockfish CLI


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.


Solution

  • 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).