UNPKG

tsgammon-core

Version:

A Backgammon library for Typescript, formerly developed as a part of tsgammon-ui

85 lines (84 loc) 2.96 kB
"use strict"; 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)); }