1 var grpc = require('grpc');
2 var Chess = require('../www/js/chess.min.js').Chess;
4 var PROTO_PATH = __dirname + '/hashprobe.proto';
5 var hashprobe_proto = grpc.load(PROTO_PATH).hashprobe;
7 var board = new Chess();
10 var current_servers = [];
12 var need_reinit = function(servers) {
13 if (servers.length != current_servers.length) {
16 for (var i = 0; i < servers.length; ++i) {
17 if (servers[i] != current_servers[i]) {
23 exports.need_reinit = need_reinit;
25 var init = function(servers) {
27 for (var i = 0; i < servers.length; ++i) {
28 clients.push(new hashprobe_proto.HashProbe(servers[i], grpc.credentials.createInsecure()));
30 current_servers = servers;
34 var handle_request = function(fen, response) {
35 if (fen === undefined || fen === null || fen === '' || !board.validate_fen(fen).valid) {
36 response.writeHead(400, {});
46 for (var i = 0; i < clients.length; ++i) {
47 clients[i].probe({fen: fen}, function(err, probe_response) {
49 rpc_status.failed = true;
51 rpc_status.responses.push(probe_response);
53 if (--rpc_status.left == 0) {
54 // All probes have come back.
55 if (rpc_status.failed) {
56 response.writeHead(500, {});
59 handle_response(fen, response, rpc_status.responses);
65 exports.handle_request = handle_request;
67 var handle_response = function(fen, response, probe_responses) {
68 var probe_response = reconcile_responses(probe_responses);
71 var root = translate_line(board, fen, probe_response['root']);
72 for (var i = 0; i < probe_response['line'].length; ++i) {
73 var line = probe_response['line'][i];
74 var uci_move = line['move']['from_sq'] + line['move']['to_sq'] + line['move']['promotion'];
75 lines[uci_move] = translate_line(board, fen, line);
78 var text = JSON.stringify({
83 'Content-Type': 'text/json; charset=utf-8'
84 //'Content-Length': text.length
86 response.writeHead(200, headers);
91 var reconcile_responses = function(probe_responses) {
92 var probe_response = {};
94 // Select the root that has searched the deepest, plain and simple.
95 probe_response['root'] = probe_responses[0]['root'];
96 for (var i = 1; i < probe_responses.length; ++i) {
97 var root = probe_responses[i]['root'];
98 if (root['depth'] > probe_response['root']['depth']) {
99 probe_response['root'] = root;
103 // Do the same ting for each move, combining on move.
105 for (var i = 0; i < probe_responses.length; ++i) {
106 for (var j = 0; j < probe_responses[i]['line'].length; ++j) {
107 var line = probe_responses[i]['line'][j];
108 var uci_move = line['move']['from_sq'] + line['move']['to_sq'] + line['move']['promotion'];
110 if (!moves[uci_move]) {
111 moves[uci_move] = line;
113 moves[uci_move] = reconcile_moves(line, moves[uci_move]);
117 probe_response['line'] = [];
118 for (var move in moves) {
119 probe_response['line'].push(moves[move]);
121 return probe_response;
124 var reconcile_moves = function(a, b) {
125 // Prefer exact bounds, unless the depth is just so much higher.
126 if (a['bound'] === 'BOUND_EXACT' &&
127 b['bound'] !== 'BOUND_EXACT' &&
128 a['depth'] + 10 >= b['depth']) {
131 if (b['bound'] === 'BOUND_EXACT' &&
132 a['bound'] !== 'BOUND_EXACT' &&
133 b['depth'] + 10 >= a['depth']) {
137 if (a['depth'] > b['depth']) {
144 var translate_line = function(board, fen, line) {
147 var toplay = board.turn();
149 if (line['move'] && line['move']['from_sq']) {
150 var promo = line['move']['promotion'];
152 r['move'] = board.move({ from: line['move']['from_sq'], to: line['move']['to_sq'], promotion: promo.toLowerCase() }).san;
154 r['move'] = board.move({ from: line['move']['from_sq'], to: line['move']['to_sq'] }).san;
159 if (!line['found']) {
163 r['depth'] = line['depth'];
170 for (var j = 0; j < line['pv'].length; ++j) {
171 var move = line['pv'][j];
172 var decoded = board.move({ from: move['from_sq'], to: move['to_sq'], promotion: move['promotion'] });
173 if (decoded === null) {
176 pv.push(decoded.san);
180 // Convert the score. Use the static eval if no search.
181 var value = line['value'] || line['eval'];
183 if (value['score_type'] === 'SCORE_CP') {
184 score = ['cp', value['score_cp']];
185 } else if (value['score_type'] === 'SCORE_MATE') {
186 score = ['m', value['score_mate']];
189 if (line['bound'] === 'BOUND_UPPER') {
191 } else if (line['bound'] === 'BOUND_LOWER') {