analyze-sgf
Version:
Analyze SGF file by KataGo Parallel Analysis Engine to produce Reviewed SGF file
119 lines (100 loc) • 3.81 kB
JavaScript
/* eslint max-lines-per-function: ["error", 100] */
const fs = require('fs');
const assert = require('assert');
const yaml = require('js-yaml');
const sgfconv = require('../src/sgfconv');
const GameTree = require('../src/gametree');
const yamlpath = require.resolve('../src/analyze-sgf.yml');
const opts = yaml.load(fs.readFileSync(yamlpath));
opts.sgf.boardYSize = opts.analysis.boardYSize;
const sgfopts = opts.sgf;
// Removes line feeds and comments.
function strip(sgf) {
return sgf
.replace(/\r\n/g, '')
.replace(/\n/g, '')
.replace(/\\\]/g, '@$$yy$$@')
.replace(/\bC\[[^\]]*\]/g, '')
.replace(/@$$yy$$@/g, '\\]');
}
// Compares expected SGF except comments to the SGF generated by GameTree and
// Analysis JSON.
function compareButComments(json, expected) {
const data = fs.readFileSync(json).toString();
const index = data.indexOf('\n');
const sgf = sgfconv.correctSGFDialects(data.substring(0, index));
const responses = data.substring(index + 1);
const gametree = new GameTree(sgf, responses, sgfopts);
const rsgf = strip(gametree.getSGF());
const esgf = strip(fs.readFileSync(expected).toString());
assert.equal(esgf, rsgf);
}
// Compares expected SGF to the SGF generated by Analysis JSON.
function compare(json, expected) {
const data = fs.readFileSync(json).toString();
const index = data.indexOf('\n');
const sgf = sgfconv.correctSGFDialects(data.substring(0, index));
const responses = data.substring(index + 1);
const gametree = new GameTree(sgf, responses, sgfopts);
const rsgf = gametree.getSGF();
assert.equal(fs.readFileSync(expected).toString(), rsgf);
}
describe('GameTree', () => {
it('should remove the comment of root node, and add move comment.', () => {
const compareButLines = (x, y) =>
assert.equal(x.replace(/\n/g, ''), y.replace(/\n/g, ''));
const gametree = new GameTree('(PL[]C[12\n34];B[aa];W[bb])', '', opts);
compareButLines(
gametree.getSGF(),
'(;PL[]CA[UTF-8];B[aa]C[Move 1];W[bb]C[Move 2])',
);
});
it('should be expected values for "t-sabaki-1-default.sgf".', () => {
sgfopts.maxVariationsForEachMove = 10;
sgfopts.maxWinrateDropForGoodMove = 2;
sgfopts.minWinrateDropForBadMove = 5;
sgfopts.minWinrateDropForBadHotSpot = 20;
sgfopts.minWinrateDropForVariations = 5;
sgfopts.showVariationsAfterLastMove = false;
sgfopts.analyzeTurns = undefined;
compareButComments(
'test/examples/t-sabaki-1.json',
'test/examples/t-sabaki-1-default.sgf',
);
});
it('should add passing move for "t-sabaki-1-lastmove.sgf".', () => {
sgfopts.showVariationsAfterLastMove = true;
sgfopts.analyzeTurns = undefined;
compareButComments(
'test/examples/t-sabaki-1.json',
'test/examples/t-sabaki-1-lastmove.sgf',
);
});
it('should add passing move and all the variations.', () => {
sgfopts.showVariationsAfterLastMove = true;
sgfopts.analyzeTurns = [0, 1, 2, 3, 4, 5];
compareButComments(
'test/examples/t-sabaki-1.json',
'test/examples/t-sabaki-1-turns-lastmove.sgf',
);
});
it('should add all the variations.', () => {
sgfopts.showVariationsAfterLastMove = false;
compareButComments(
'test/examples/t-sabaki-1.json',
'test/examples/t-sabaki-1-turns.sgf',
);
});
it('should be same for each comment of "t-sabaki-2.sgf".', () => {
sgfopts.minWinrateDropForVariations = -100;
sgfopts.showBadVariations = true;
sgfopts.maxVariationsForEachMove = 20;
sgfopts.showVariationsAfterLastMove = true;
sgfopts.analyzeTurns = [0, 1, 2, 3, 4];
// Be careful. Easy to fail with the changes of comments formats.
compare(
'test/examples/t-sabaki-2.json',
'test/examples/t-sabaki-2-analyzed.sgf',
);
});
});