1 var grpc = require('@grpc/grpc-js');
2 var Chess = require('../www/js/chess.js').Chess;
4 var PROTO_PATH = __dirname + '/hashprobe.proto';
5 var protoLoader = require('@grpc/proto-loader');
6 var packageDefinition = protoLoader.loadSync(
14 var hashprobe_proto = grpc.loadPackageDefinition(packageDefinition).hashprobe;
16 var board = new Chess();
19 var current_servers = [];
21 var need_reinit = function(servers) {
22 if (servers.length != current_servers.length) {
25 for (var i = 0; i < servers.length; ++i) {
26 if (servers[i] != current_servers[i]) {
32 exports.need_reinit = need_reinit;
34 var init = function(servers) {
36 for (var i = 0; i < servers.length; ++i) {
37 clients.push(new hashprobe_proto.HashProbe(servers[i], grpc.credentials.createInsecure()));
39 current_servers = servers;
43 var handle_request = function(fen, response) {
44 if (fen === undefined || fen === null || fen === '' || !board.validate_fen(fen).valid) {
45 response.writeHead(400, {});
55 for (var i = 0; i < clients.length; ++i) {
56 clients[i].probe({fen: fen}, function(err, probe_response) {
58 rpc_status.failed = true;
60 rpc_status.responses.push(probe_response);
62 if (--rpc_status.left == 0) {
63 // All probes have come back.
64 if (rpc_status.failed) {
65 response.writeHead(500, {});
68 handle_response(fen, response, rpc_status.responses);
74 exports.handle_request = handle_request;
76 var handle_response = function(fen, response, probe_responses) {
77 var probe_response = reconcile_responses(probe_responses);
80 var root = translate_line(board, fen, probe_response['root']);
81 for (var i = 0; i < probe_response['line'].length; ++i) {
82 var line = probe_response['line'][i];
83 var pretty_move = line['move']['pretty'];
84 lines[pretty_move] = translate_line(board, fen, line);
87 var text = JSON.stringify({
92 'Content-Type': 'text/json; charset=utf-8'
93 //'Content-Length': text.length
95 response.writeHead(200, headers);
100 var reconcile_responses = function(probe_responses) {
101 var probe_response = {};
103 // Select the root that has searched the deepest, plain and simple.
104 probe_response['root'] = probe_responses[0]['root'];
105 for (var i = 1; i < probe_responses.length; ++i) {
106 var root = probe_responses[i]['root'];
107 if (root['depth'] > probe_response['root']['depth']) {
108 probe_response['root'] = root;
112 // Do the same ting for each move, combining on move.
114 for (var i = 0; i < probe_responses.length; ++i) {
115 for (var j = 0; j < probe_responses[i]['line'].length; ++j) {
116 var line = probe_responses[i]['line'][j];
117 var pretty_move = line['move']['pretty'];
119 if (!moves[pretty_move]) {
120 moves[pretty_move] = line;
122 moves[pretty_move] = reconcile_moves(line, moves[pretty_move]);
126 probe_response['line'] = [];
127 for (var move in moves) {
128 probe_response['line'].push(moves[move]);
130 return probe_response;
133 var reconcile_moves = function(a, b) {
134 // Prefer exact bounds, unless the depth is just so much higher.
135 if (a['bound'] === 'BOUND_EXACT' &&
136 b['bound'] !== 'BOUND_EXACT' &&
137 a['depth'] + 10 >= b['depth']) {
140 if (b['bound'] === 'BOUND_EXACT' &&
141 a['bound'] !== 'BOUND_EXACT' &&
142 b['depth'] + 10 >= a['depth']) {
146 if (a['depth'] > b['depth']) {
153 var translate_line = function(board, fen, line) {
156 if (line['move'] && line['move']['pretty']) {
157 r['move'] = line['move']['pretty']
161 if (!line['found']) {
165 r['depth'] = line['depth'];
172 for (var j = 0; j < line['pv'].length; ++j) {
173 var move = line['pv'][j];
174 pv.push(move['pretty']);
178 // Convert the score. Use the static eval if no search.
179 var value = line['value'] || line['eval'];
181 if (value['score_type'] === 'SCORE_CP') {
182 score = ['cp', value['score_cp']];
183 } else if (value['score_type'] === 'SCORE_MATE') {
184 score = ['m', value['score_mate']];
187 if (line['bound'] === 'BOUND_UPPER') {
189 } else if (line['bound'] === 'BOUND_LOWER') {