首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >设定鱼类技能水平(UCI / Javascript)

设定鱼类技能水平(UCI / Javascript)
EN

Stack Overflow用户
提问于 2021-03-01 16:32:43
回答 1查看 1.3K关注 0票数 1

在我的一生中,我似乎无法设置河豚去做任何事情,除了在20级发出毁灭性的打击。下面是为配置河豚的技能水平和深度而设置的代码,以及代码执行的UCI命令的顺序。

这段代码在javascript中,但使用UCI就像最初的开源实现一样。我遵循的例子是:https://github.com/nmrugg/stockfish.js/blob/2b87d5d16a613f3ce05b1dd0bbb58465501ed30a/example/enginegame.js#L38

Stockfish.js

代码语言:javascript
复制
import _ from 'lodash';

import ChessBoardState from './ChessBoardState';
import Move from './Move';

class Stockfish {
    constructor() {
        this.bestMove = null;
        this.skill = null;
        this.depth = null;
        this.isThinking = false;
        this.engineStatus = {};

        this.stockfish = new Worker('stockfish.js');
        this.stockfish.onmessage = (event) => {
            const line = event && typeof event === 'object' ? event.data : event;

            console.log('Stockfish: ', line);

            if (line === 'uciok') {
                this.engineStatus.engineLoaded = true;
            } else if (line === 'readyok') {
                this.engineStatus.engineReady = true;
            } else {
                const match = line.match('^bestmove ([a-h][1-8])([a-h][1-8])([qrbn])?');
                if (match) {
                    this.bestMove = new Move(match[1], match[2], match[3] ? match[3] : null);
                    this.isThinking = false;
                }
            }
        }

        this.stockfish.postMessage('uci');
        this.stockfish.postMessage('isready');
        this.stockfish.postMessage('ucinewgame');
    }

    isEngineLoaded() {
        return this.engineStatus.engineLoaded;
    }

    /**
     * Update engine state to fenCode.
     * @param {string} fenCode
     */
    setFEN(fenCode) {
        if (!this.engineStatus.engineLoaded) {
            throw new Error('Engine not loaded');
        }

        this.stockfish.postMessage(`position fen ${fenCode}`);
    }

    /**
     * Update engine depth
     * @param {number} depth
     */
    setDepth(depth) {
        console.log(depth);
        this.depth = _.clamp(depth, 1, 20);
    }

    /**
     * Update engine skill level
     * @param {number} skill
     */
    setSkillLevel(skillLevel) {
        if (!this.engineStatus.engineLoaded) {
            throw new Error('Engine not loaded');
        }

        skillLevel = _.clamp(skillLevel, 0, 20);
        console.log(skillLevel);
        this.stockfish.postMessage(`setoption name Skill Level value ${skillLevel}`);

        // Stockfish level 20 does not make errors (intentially), so these numbers have no effect on level 20.
        // Level 0 starts at 1
        const err_prob = Math.round((skillLevel * 6.35) + 1);
        // Level 0 starts at 10
        const max_err = Math.round((skillLevel * -0.5) + 10);

        this.stockfish.postMessage(`setoption name Skill Level Maximum Error value ${max_err}`);
        this.stockfish.postMessage(`setoption name Skill Level Probability value ${err_prob}`);

        this.skillLevel = skillLevel;
    }

    /**
     * Start churning for best move.
     * @param {ChessBoardState} chessBoardState
     * @param {number} depth
     */
    searchBestMove(chessBoardState) {
        this.bestMove = null;
        this.isThinking = true;

        this.setFEN(chessBoardState.toFEN());
        this.stockfish.postMessage(`go depth ${this.depth}`);
    }

    /**
     * Returns best move if one has been found.
     */
    getBestMove() {
        return this.isThinking ? null : this.bestMove;
    }
}

export default Stockfish

ChessGameUI.js (...用于表示无关代码)

代码语言:javascript
复制
...
const stockfish = new Stockfish()

this.state = {
    ...
    stockfish: stockfish,
    stockfishSkillLevel: 0,
    stockfishDepth: 1,
}
...
this.intID = setInterval(() => {
    this.state.stockfish.setSkillLevel(this.state.stockfishSkillLevel);
    this.state.stockfish.setDepth(this.state.stockfishDepth);
    
    ...
    
    const bestMove = this.state.stockfish.getBestMove();
    if (!bestMove && !this.state.stockfish.isThinking) {
        this.state.stockfish.searchBestMove(this.state.chessBoardState, this.state.stockfishDepth);
    } else if (bestMove) {
        this.state.chessBoardState.move(bestMove)
        this.state.stockfish.bestMove = null;

        this.setState(prev => ({
            ...prev,
            chessBoardState: ChessBoardState.fromFEN(this.state.chessBoardState.toFEN()),
        }));
    }
}, 500);

理论上,这段代码应该尝试每半秒积极地设置技能级别和深度,同时从Stockfish轮询一个新的bestMove。但这些设置似乎对发动机的难度没有任何影响。

调用(按顺序)的UCI命令:

代码语言:javascript
复制
uci
isready
ucinewgame
setoption name Skill Level value 0
setoption name Skill Level Maximum Error value 1
setoption name Skill Level Probability Value 10
position fen rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq - 0 1
go depth 1
EN

回答 1

Stack Overflow用户

发布于 2021-12-17 16:42:01

试着用这个,它对我有用:

代码语言:javascript
复制
const stockfish = new Worker('/stockfish.js');
stockfish.postMessage('uci');
stockfish.postMessage('ucinewgame');
stockfish.postMessage('setoption name Skill Level value 3');
stockfish.postMessage('setoption name Skill Level Maximum Error value 600');
stockfish.postMessage('setoption name Skill Level Probability value 128');
stockfish.postMessage('position fen ' + chess.fen());
stockfish.postMessage('go depth 10');
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/66425952

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档