Make it possible for the hash probes to reconcile multiple sources.
authorSteinar H. Gunderson <sgunderson@bigfoot.com>
Tue, 22 Mar 2016 09:49:36 +0000 (10:49 +0100)
committerSteinar H. Gunderson <sgunderson@bigfoot.com>
Tue, 22 Mar 2016 09:49:36 +0000 (10:49 +0100)
server/hash-lookup.js
server/serve-analysis.js

index 13f9758..b6ed75e 100644 (file)
@@ -4,29 +4,52 @@ var Chess = require('../www/js/chess.min.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 init = function(servers) {
+       for (var i = 0; i < servers.length; ++i) {
+               clients.push(new hashprobe_proto.HashProbe(servers[i], grpc.credentials.createInsecure()));
+       }
+}
+exports.init = init;
+
 var handle_request = function(fen, response) {
        if (!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']);
@@ -49,6 +72,59 @@ 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 uci_move = line['move']['from_sq'] + line['move']['to_sq'] + line['move']['promotion'];
+
+                       if (!moves[uci_move]) {
+                               moves[uci_move] = line;
+                       } else {
+                               moves[uci_move] = reconcile_moves(line, moves[uci_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);
index 0490e96..ce1f89d 100644 (file)
@@ -40,6 +40,13 @@ if (process.argv.length >= 6) {
        port = parseInt(process.argv[5]);
 }
 
+// gRPC backends.
+var grpc_backends = ["localhost:50051", "localhost:50052"];
+if (process.argv.length >= 7) {
+       grpc_backends = process.argv[6].split(",");
+}
+hash_lookup.init(grpc_backends);
+
 // If set to 1, we are already processing a JSON update and should not
 // start a new one. If set to 2, we are _also_ having one in the queue.
 var json_lock = 0;