tsgammon-core
Version:
A Backgammon library for Typescript, formerly developed as a part of tsgammon-ui
85 lines (84 loc) • 2.96 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.evalWithNN = exports.evaluate = exports.simpleNNEngine = void 0;
const GammonEngine_1 = require("./GammonEngine");
const Matrix_1 = require("./Matrix");
const td_default_1 = require("./td_default");
/**
* GammonEngineとして実装されたオブジェクト
*/
exports.simpleNNEngine = (0, GammonEngine_1.simpleEvalEngine)((board) => evaluate(board).e);
/**
* 評価関数
*
* @param board 盤面
*/
function evaluate(board) {
const e = evalWithNN(board.points, board.myBornOff, board.opponentBornOff);
const [oppWin, oppGammon, myWin, myGammon] = e;
const evalRet = myWin + myGammon - oppWin - oppGammon;
return { e: evalRet, myWin, myGammon, oppWin, oppGammon };
}
exports.evaluate = evaluate;
const hiddenL = layer(td_default_1.hidden_weight, td_default_1.hidden_bias);
const outputL = layer(td_default_1.output_weight, td_default_1.output_bias);
/**
* テストのためのインターフェース
*
* @param pieces 駒の配置
* @param myBornOff 自分がすでにあげた駒の数
* @param oppBornOff 相手がすでにあげた駒の数
*/
function evalWithNN(pieces, myBornOff, oppBornOff) {
const inputValues = (0, Matrix_1.matrix2d)([encode(pieces, myBornOff, oppBornOff)]);
const hiddenOut = hiddenL.calcOutput(inputValues);
const output = outputL.calcOutput(hiddenOut);
return output.arr[0];
}
exports.evalWithNN = evalWithNN;
function encode(pieces, myBornOff, oppBornOff) {
const input = Array(198);
pieces.forEach((p, i) => {
if (1 <= i && i <= 24) {
const pos = i - 1;
if (p > 0) {
input[pos * 8] = 1.0; // p > 0
input[pos * 8 + 1] = p > 1 ? 1.0 : 0.0;
input[pos * 8 + 2] = p > 2 ? 1.0 : 0.0;
input[pos * 8 + 3] = p > 3 ? (p - 3) / 2.0 : 0.0;
}
else if (p < 0) {
input[pos * 8 + 4] = 1.0;
input[pos * 8 + 5] = -p > 1 ? 1.0 : 0.0;
input[pos * 8 + 6] = -p > 2 ? 1.0 : 0.0;
input[pos * 8 + 7] = -p > 3 ? (-p - 3) / 2.0 : 0.0;
}
}
});
const idx = 24 * 8;
input[idx] = pieces[0] / 2.0;
input[idx + 1] = -pieces[25] / 2.0;
input[idx + 2] = myBornOff / 15;
input[idx + 3] = oppBornOff / 15;
input[idx + 4] = 1;
input[idx + 5] = 0;
return input;
}
function apply(matrix, f) {
return (0, Matrix_1.matrix2d)(matrix.arr.map((row) => {
return row.map(f);
}));
}
function layer(weight, bias) {
return {
weight: (0, Matrix_1.matrix2d)(weight),
bias: (0, Matrix_1.matrix2d)(bias),
calcOutput(inputValues) {
const prod = (0, Matrix_1.product)(inputValues, this.weight);
return apply((0, Matrix_1.add)(prod, this.bias), sigmoid);
},
};
}
function sigmoid(v) {
return 1 / (1 + Math.pow(Math.E, -v));
}