X-Git-Url: https://git.sesse.net/?p=remoteglot;a=blobdiff_plain;f=server%2Fhash-lookup.js;h=7d7daeb9099c6c36f2781cb4889f4fd573f86618;hp=13f97582e51dd18f3bb562582218ecea7bdeb79c;hb=93c084f827a5783b20a3b3349463187c6d342810;hpb=83aa0538ddb9037d37295f7e6e68348773661d7a diff --git a/server/hash-lookup.js b/server/hash-lookup.js index 13f9758..7d7daeb 100644 --- a/server/hash-lookup.js +++ b/server/hash-lookup.js @@ -1,39 +1,78 @@ var grpc = require('grpc'); -var Chess = require('../www/js/chess.min.js').Chess; +var Chess = require('../www/js/chess.js').Chess; var PROTO_PATH = __dirname + '/hashprobe.proto'; var hashprobe_proto = grpc.load(PROTO_PATH).hashprobe; -// TODO: Make destination configurable. -var client = new hashprobe_proto.HashProbe('localhost:50051', grpc.credentials.createInsecure()); - var board = new Chess(); +var clients = []; +var current_servers = []; + +var need_reinit = function(servers) { + if (servers.length != current_servers.length) { + return true; + } + for (var i = 0; i < servers.length; ++i) { + if (servers[i] != current_servers[i]) { + return true; + } + } + return false; +} +exports.need_reinit = need_reinit; + +var init = function(servers) { + clients = []; + for (var i = 0; i < servers.length; ++i) { + clients.push(new hashprobe_proto.HashProbe(servers[i], grpc.credentials.createInsecure())); + } + current_servers = servers; +} +exports.init = init; + var handle_request = function(fen, response) { - if (!board.validate_fen(fen).valid) { + if (fen === undefined || fen === null || fen === '' || !board.validate_fen(fen).valid) { response.writeHead(400, {}); response.end(); return; } - client.probe({fen: fen}, function(err, probe_response) { - if (err) { - response.writeHead(500, {}); - response.end(); - } else { - handle_response(fen, response, probe_response); - } - }); + + var rpc_status = { + failed: false, + left: clients.length, + responses: [], + } + for (var i = 0; i < clients.length; ++i) { + clients[i].probe({fen: fen}, function(err, probe_response) { + if (err) { + rpc_status.failed = true; + } else { + rpc_status.responses.push(probe_response); + } + if (--rpc_status.left == 0) { + // All probes have come back. + if (rpc_status.failed) { + response.writeHead(500, {}); + response.end(); + } else { + handle_response(fen, response, rpc_status.responses); + } + } + }); + } } exports.handle_request = handle_request; -var handle_response = function(fen, response, probe_response) { +var handle_response = function(fen, response, probe_responses) { + var probe_response = reconcile_responses(probe_responses); var lines = {}; var root = translate_line(board, fen, probe_response['root']); for (var i = 0; i < probe_response['line'].length; ++i) { var line = probe_response['line'][i]; - var uci_move = line['move']['from_sq'] + line['move']['to_sq'] + line['move']['promotion']; - lines[uci_move] = translate_line(board, fen, line); + var pretty_move = line['move']['pretty']; + lines[pretty_move] = translate_line(board, fen, line); } var text = JSON.stringify({ @@ -49,42 +88,83 @@ var handle_response = function(fen, response, probe_response) { response.end(); } +var reconcile_responses = function(probe_responses) { + var probe_response = {}; + + // Select the root that has searched the deepest, plain and simple. + probe_response['root'] = probe_responses[0]['root']; + for (var i = 1; i < probe_responses.length; ++i) { + var root = probe_responses[i]['root']; + if (root['depth'] > probe_response['root']['depth']) { + probe_response['root'] = root; + } + } + + // Do the same ting for each move, combining on move. + var moves = {}; + for (var i = 0; i < probe_responses.length; ++i) { + for (var j = 0; j < probe_responses[i]['line'].length; ++j) { + var line = probe_responses[i]['line'][j]; + var pretty_move = line['move']['pretty']; + + if (!moves[pretty_move]) { + moves[pretty_move] = line; + } else { + moves[pretty_move] = reconcile_moves(line, moves[pretty_move]); + } + } + } + probe_response['line'] = []; + for (var move in moves) { + probe_response['line'].push(moves[move]); + } + return probe_response; +} + +var reconcile_moves = function(a, b) { + // Prefer exact bounds, unless the depth is just so much higher. + if (a['bound'] === 'BOUND_EXACT' && + b['bound'] !== 'BOUND_EXACT' && + a['depth'] + 10 >= b['depth']) { + return a; + } + if (b['bound'] === 'BOUND_EXACT' && + a['bound'] !== 'BOUND_EXACT' && + b['depth'] + 10 >= a['depth']) { + return b; + } + + if (a['depth'] > b['depth']) { + return a; + } else { + return b; + } +} + var translate_line = function(board, fen, line) { var r = {}; - board.load(fen); - var toplay = board.turn(); - - if (line['move'] && line['move']['from_sq']) { - var promo = line['move']['promotion']; - if (promo) { - r['pretty_move'] = board.move({ from: line['move']['from_sq'], to: line['move']['to_sq'], promotion: promo.toLowerCase() }).san; - } else { - r['pretty_move'] = board.move({ from: line['move']['from_sq'], to: line['move']['to_sq'] }).san; - } + + if (line['move'] && line['move']['pretty']) { + r['move'] = line['move']['pretty'] } else { - r['pretty_move'] = ''; + r['move'] = ''; } - r['sort_key'] = r['pretty_move']; if (!line['found']) { - r['pv_pretty'] = []; + r['pv'] = []; return r; } r['depth'] = line['depth']; // Convert the PV. var pv = []; - if (r['pretty_move']) { - pv.push(r['pretty_move']); + if (r['move']) { + pv.push(r['move']); } for (var j = 0; j < line['pv'].length; ++j) { var move = line['pv'][j]; - var decoded = board.move({ from: move['from_sq'], to: move['to_sq'], promotion: move['promotion'] }); - if (decoded === null) { - break; - } - pv.push(decoded.san); + pv.push(move['pretty']); } - r['pv_pretty'] = pv; + r['pv'] = pv; // Convert the score. Use the static eval if no search. var value = line['value'] || line['eval'];