Skip to content

Commit

Permalink
Merge pull request lichess-org#2551 from isaacl/sfCtrlImprovements
Browse files Browse the repository at this point in the history
Stockfish Protocol improvements.
  • Loading branch information
ornicar authored Jan 22, 2017
2 parents 59c7fea + 0dc9be4 commit 2c16760
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 43 deletions.
3 changes: 1 addition & 2 deletions ui/ceval/src/ctrl.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,7 @@ module.exports = function(opts) {
onCrash: opts.onCrash
}, {
minDepth: minDepth,
maxDepth: maxDepth,
variant: opts.variant,
multiPv: multiPv,
threads: pnaclSupported && threads,
hashSize: pnaclSupported && hashSize
});
Expand Down Expand Up @@ -97,6 +95,7 @@ module.exports = function(opts) {
path: path,
ply: step.ply,
maxDepth: maxD,
multiPv: parseInt(multiPv()),
threatMode: threatMode,
emit: function(res) {
if (enabled()) onEmit(res);
Expand Down
96 changes: 55 additions & 41 deletions ui/ceval/src/stockfishProtocol.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,24 @@
var m = require('mithril');

module.exports = function(worker, opts) {
var EVAL_REGEX = new RegExp(''
+ /^info depth (\d+) seldepth \d+ multipv (\d+) /.source
+ /score (cp|mate) ([-\d]+) /.source
+ /(?:(upper|lower)bound )?nodes (\d+) nps (\d+) /.source
+ /(?:hashfull \d+ )?tbhits \d+ time (\d+) /.source
+ /pv (.+)/.source);

module.exports = function(worker, opts) {
var emitTimer = null;
var work = null;
var state = null;
var minLegalMoves = 0;
var startedAt = null;

var stopped = m.deferred();
stopped.resolve(true);

var emit = function() {
emitTimer = clearTimeout(emitTimer);
if (!work || !state) return;
minLegalMoves = Math.max(minLegalMoves, state.eval.pvs.length);
if (state.eval.pvs.length < minLegalMoves) return;
work.emit(state);
state = null;
};

if (opts.variant.key === 'fromPosition' || opts.variant.key === 'chess960')
Expand All @@ -29,55 +32,67 @@ module.exports = function(worker, opts) {

var processOutput = function(text) {
if (text.indexOf('bestmove ') === 0) {
emit();
if (!stopped) stopped = m.deferred();
stopped.resolve(true);
return;
}
if (!work) return;

if (text.indexOf('currmovenumber') !== -1) return;
var matches = text.match(/depth (\d+) .*multipv (\d+) .*score (cp|mate) ([-\d]+) .*nps (\d+) .*pv (.+)/);
if (!matches) {
emit();
return;
}
var matches = text.match(EVAL_REGEX);
if (!matches) return;

var depth = parseInt(matches[1]),
multiPv = parseInt(matches[2]),
isMate = matches[3] === 'mate',
eval = parseFloat(matches[4]),
evalType = matches[5],
nodes = parseInt(matches[6]),
nps = parseInt(matches[7]),
elapsedMs = parseInt(matches[8]),
pv = matches[9];

var depth = parseInt(matches[1]);
if (depth < opts.minDepth) return;
var multiPv = parseInt(matches[2]);
var cp, mate;
if (matches[3] === 'cp') cp = parseFloat(matches[4]);
else mate = parseFloat(matches[4]);
if (work.ply % 2 === 1) {
if (matches[3] === 'cp') cp = -cp;
else mate = -mate;
}
if (work.ply % 2 === 1) eval = -eval;

// For now, ignore most upperbound/lowerbound messages.
// The exception is for multiPV, sometimes non-primary PVs
// only have an upperbound. See: ddugovic/Stockfish#228
if (evalType && (multiPv === 1 || evalType !== 'upper' || !state)) return;

var pvData = {
best: pv.split(' ', 2)[0],
pv: pv,
cp: isMate ? undefined : eval,
mate: isMate ? eval : undefined,
depth: depth,
};

if (multiPv === 1) {
emit();
state = {
work: work,
eval: {
depth: depth,
nps: parseInt(matches[5]),
best: matches[6].split(' ')[0],
cp: cp,
mate: mate,
pvs: [],
millis: new Date() - startedAt
}
nps: nps,
best: pvData.best,
cp: pvData.cp,
mate: pvData.mate,
pvs: [pvData],
millis: elapsedMs,
},
};
} else if (!state || depth < state.eval.depth) return; // multipv progress

state.eval.pvs[multiPv - 1] = {
cp: cp,
mate: mate,
pv: matches[6],
best: matches[6].split(' ')[0]
};
} else if (state) {
state.eval.pvs.push(pvData);
state.eval.depth = Math.min(state.eval.depth, depth);
}

if (multiPv === opts.multiPv) emit();
if (multiPv === work.multiPv) {
emit();
state = null;
} else {
// emit timeout in case there aren't a full set of PVs.
clearTimeout(emitTimer);
emitTimer = setTimeout(emit, 50);
}
};

return {
Expand All @@ -88,10 +103,9 @@ module.exports = function(worker, opts) {
minLegalMoves = 0;
if (opts.threads) worker.send('setoption name Threads value ' + opts.threads());
if (opts.hashSize) worker.send('setoption name Hash value ' + opts.hashSize());
worker.send('setoption name MultiPV value ' + opts.multiPv());
worker.send('setoption name MultiPV value ' + work.multiPv);
worker.send(['position', 'fen', work.initialFen, 'moves'].concat(work.moves).join(' '));
worker.send('go depth ' + work.maxDepth);
startedAt = new Date();
},
stop: function() {
if (!stopped) {
Expand Down

0 comments on commit 2c16760

Please sign in to comment.