最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to setup position with FEN string in stockfish.js? - Stack Overflow

programmeradmin0浏览0评论

I want to make a chess puzzle on my website for my student. I use stockfish.js to play with the engine. How to change the start position on the board? I try to change all FEN string but did not work. Where to look for the function or something? Anybody can help me, please?

I want to make a chess puzzle on my website for my student. I use stockfish.js to play with the engine. How to change the start position on the board? I try to change all FEN string but did not work. Where to look for the function or something? Anybody can help me, please?

Share Improve this question asked Jun 23, 2020 at 16:50 user3681383user3681383 831 silver badge7 bronze badges
Add a ment  | 

2 Answers 2

Reset to default 3

Interacting with the javascript port of Stockfish is (at time of writing) still like municating with a chess engine that uses/supports UCI (Universal Chess Interface).

The UCI position mand should suffice:

   var fenString = "rnbqkbnr/ppppp1pp/8/5p2/3P4/8/PPP1PPPP/RNBQKBNR w KQkq - 0 2"
   // start UCI
   stockfish.postMessage("uci");
   // start new game
   stockfish.postMessage("ucinewgame");
   // set new game position
   stockfish.postMessage("position fen " + fenString);
   // start search
   stockfish.postMessage("go depth 10");

Edited: Updated case for postMessage() function.

I was working on the same thing and figured it out -- it's by no means obvious and within the stockfish example there are lots of little trips and pitfalls. I found a couple questions online and thought I'd give them some answers.

So -- this answer assumes working with the example code found here: https://github./nmrugg/stockfish.js/tree/Stockfish11/example.

There are two major modifications that need to happen - first in the index.html file and second in enginegame.js.

First we'll define a helper function which will make it easy to work with the url "search" as it's called:

function searchToObject() {      
  var pairs = window.location.search.substring(1).split("&"),      
    obj = {},      
    pair,      
    i;      
            
  for ( i in pairs ) {      
    if ( pairs[i] === "" ) continue;      
          
    pair = pairs[i].split("=");      
    obj[ decodeURIComponent( pair[0] ) ] = decodeURIComponent( pair[1] );      
  }      
          
  return obj;      
}

For ease I just placed that function in both files, within index.html it's at the beginning of the script tag, in enginegame.js it's the very first line. Also btw, I certainly pilfered that from stackoverflow, but I can't seem to find that answer any more, rats.

In index.html the newGame function wants to look like this:

newGame = function newGame() {        
  var baseTime = parseFloat($('#timeBase').val()) * 60;        
  var inc = parseFloat($('#timeInc').val());        
  var skill = parseInt($('#skillLevel').val());        
 
  game.reset();        
 
  let search = searchToObject();        
 
  if (search.player) {        
    game.setPlayerColor(search.player)        
  } else {        
    game.setPlayerColor($('#color-white').hasClass('active') ? 'white' : 'black');        
  }        
 
  if (search.fen) {        
    game.game.load(search.fen);        
    game.board.position(game.game.fen());        
  }        
 
  game.setTime(baseTime, inc);        
  game.setSkillLevel(skill);        
  game.setDisplayScore($('#showScore').is(':checked'));        
 
  game.start();        
}

Note the game.game and game.board -- those need to be added in enginegame.js where it's returning an object. If I were writing this I would have done it differently, but I didn't have the patience to rename things.

Next up in enginegame.js we need to adjust prepareMove.

function prepareMove() {    
    stopClock();    
    $('#pgn').text(game.pgn());    
    board.position(game.fen());    
    updateClock();    
    var turn = game.turn() == 'w' ? 'white' : 'black';    
    if (!game.game_over()) {    
        if (turn != playerColor) {    
            let search = searchToObject();    
            if (search.fen) {    
                uciCmd('position fen ' + search.fen + ' moves ' + get_moves());    
            } else {    
                uciCmd('position startpos moves' + get_moves());    
                uciCmd('position startpos moves' + get_moves(), evaler);    
            }    
            evaluation_el.textContent = "";    
            uciCmd("eval", evaler);    
 
            if (time && time.wtime) {    
                uciCmd("go " + (time.depth ? "depth " + time.depth : "") + " wtime " + time.wtime + " winc " + time.winc + " btime " + time.btime + " binc " + time.binc);    
            } else {    
                uciCmd("go " + (time.depth ? "depth " + time.depth : ""));    
            }    
            isEngineRunning = true;    
        }    
        if (game.history().length >= 2 && !time.depth && !time.nodes) {    
            startClock();    
        }    
    }    
}

See, the trick is that if ever there was a fen string to start the game, every subsequent position call needs to be different. I think that's probably what's tripping most people up - that's definitely what got me.

What helped things click for me was reading through the UCI documentation. Before that my board was in some crazy infinite loop.

Also one weird but critical bit I stumbled onto was the game.game.load(<fen string>) function call in the index.html file. I can't find any documentation for that. I don't even remember how I found it. But there it is!

发布评论

评论列表(0)

  1. 暂无评论