]> git.sesse.net Git - remoteglot/blobdiff - www/index.html
If the PV is hidden by exploration stuff, it should not be possible to inadvertedly...
[remoteglot] / www / index.html
index cda85c7c7e6176a2cf1aac8f428c4dca69c23e5d..94547e4eb7464a2a3ea3d2318c8f0c5a5fb711cb 100644 (file)
@@ -2,32 +2,61 @@
 <html>
 <head>
   <meta charset="utf-8" />
-  <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
+  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
   <title>analysis.sesse.net</title>
 
   <link rel="stylesheet" href="css/chessboard-0.3.0.min.css" />
   <link rel="stylesheet" href="css/remoteglot.css" />
+  <meta name="viewport" content="width=device-width, initial-scale=1" />
 </head>
 <body>
+<audio id="ding" preload="none">
+  <source src="ding.opus" type="audio/ogg; codecs=opus" />
+  <source src="ding.mp3" type="audio/mp3" />
+</audio>
+<div id="games">
+</div>
 <h1 id="headline">Analysis</h1>
-<table>
-<tr>
-<td>
-<div id="board" style="width: 400px"></div>
-</td>
-<td>
-  <p id="score">Score:</p>
-  <p><strong>PV:</strong> <span id="pv"></span></p>
+<div id="boardcontainer">
+  <div id="board"></div>
+  <div id="bottompanel">
+    <p id="whiteinfo"><span id="whiteclock"></span><span id="whiteimbalance"></span></p>
+    <p id="blackinfo"><span id="blackimbalance"></span><span id="blackclock"></span></p>
+    <p id="numviewers"></p>
+  </div>
+</div>
+<div id="analysis">
+  <div id="scorecontainer">
+    <span id="score">Score:</span>
+    <div id="scoresparkcontainer">
+      <span id="scorespark"></span>
+    </div>
+  </div>
+  <p id="pvcontainer"><strong id="pvtitle">PV:</strong> <span id="pv"></span></p>
   <p id="searchstats"></p>
-  <h3 style="margin-top: 1em; margin-bottom: 0;">Shallow search of all legal moves (multi-PV)</h3>
-  <table id="refutationlines">
-  </table>
-</td>
-</tr>
-</table>
-<h2>Symbol explanation</h2>
+  <h3>History and potential moves (multi-PV)</h3>
+  <p id="sortbyscoreholder">
+    Sound:
+    <span id="soundon"><a href="javascript:set_sound(true)">On</a></span>
+    <span id="soundoff"><a href="javascript:set_sound(false)">Off</a></span>
+    |
+    Sort by:
+    <span id="sortbyscore0"><a href="javascript:resort_refutation_lines(0)">Move</a></span>
+    <span id="sortbyscore1"><a href="javascript:resort_refutation_lines(1)">Score</a></span>
+    |
+    <span id="history">No history</span>
+    |
+    <span id="linemsg">Make moves by clicking on them, or on an involved square.</span>
+    <span id="linenav">
+      <span id="prevmove"><a href="javascript:prev_move();">Previous</a></span>,
+      <span id="nextmove"><a href="javascript:next_move();">Next</a></span>,
+      <a href="javascript:show_line(-1, -1);">Exit to main position</a>
+    </span></p>
+  <table id="refutationlines"></table>
+</div>
+<h2 style="clear: both;">Symbol explanation</h2>
 <ul>
-  <li><strong>Score:</strong> 1.00 is the value of one pawn (in the opening). Positive values are better for white.</li>
+  <li><strong>Score:</strong> 1.00 is the value of one pawn (in a balanced endgame). Positive values are better for white.</li>
   <li><strong>PV:</strong> Principal Variation, the series of moves the engine thinks is the best.</li>
   <li><strong>Thick red line:</strong> Marks the best move (in the view of the engine). Multiple chained arrows
     means that the PV starts with multiple successive moves with the same piece, ie., the engine thinks
     is forced or nearly so.</li>
 </ul>
 <p id="credits"><a href="http://git.sesse.net/?p=remoteglot;a=summary">remoteglot</a>
-  &copy; 2007-2013 <a href="http://www.sesse.net/">Steinar H. Gunderson</a>.
-  Chess analysis by <a href="http://stockfishchess.org/">Stockfish</a> (main analysis: 12x2.3GHz Sandy Bridge,
-  multi-PV search: 8x2.27GHz Nehalem).
-  Moves provided by <a href="http://www.freechess.org/">FICS</a>.
-  Hosting and main analysis hardware by <a href="http://www.samfundet.no/">Studentersamfundet i Trondhjem</a>.
-  JavaScript chessboard powered by <a href="http://chessboardjs.com/">chessboard.js</a>.
-  Arrows by <a href="http://jsplumbtoolkit.com">jsPlumb</a>&mdash;who would think you could
-  draw such beautiful arrows in just 161 kB of JavaScript on top of the
-  323 kB needed for jQuery and jQuery UI? How far technology has come. If you want something
-  more retro, the <a href="/text.pl">text interface</a> is still available.</p>
-
-<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script>
-<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.9.2/jquery-ui.min.js"></script>
-<script type="text/javascript" src="js/jquery.jsPlumb-1.5.3-min.js"></script>
+  &copy; 2007&ndash;2016 <a href="http://www.sesse.net/">Steinar H. Gunderson</a>.
+  Chess analysis by <a href="http://stockfishchess.org/" id="engineid">Stockfish</a><span id="enginedetails"></span>.
+  <span id="movesource"></span>
+  Hosting and additional analysis hardware by <a href="http://www.samfundet.no/">Studentersamfundet i Trondhjem</a>.
+  JavaScript chessboard powered by <a href="http://chessboardjs.com/">chessboard.js</a>
+  and <a href="https://github.com/jhlywa/chess.js">chess.js</a>.
+  Ding sound by <a href="https://www.freesound.org/people/Aiwha/sounds/196106/">Aiwha</a> (CC-BY-3.0).
+  <span id="lomonosov">7-man Lomonosov tablebase lookup by <a href="http://tb7.chessok.com/">ChessOK</a>.</span></p>
+
+<!-- For faster development -->
+<!--
+<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
 <script type="text/javascript" src="js/chessboard-0.3.0.min.js"></script>
-<script>
-var arrows = [];
-var arrow_targets = [];
-var occupied_by_arrows = [];
-
-var request_update = function(board, first) {
-       $.ajax({
-               //url: "http://analysis.sesse.net/analysis.pl?first=" + first
-               url: "http://analysis.sesse.net:5000/analysis.pl?first=" + first
-       }).done(function(data) {
-               update_board(board, data);
-       });
-}
-
-var clear_arrows = function() {
-       for (var i = 0; i < arrows.length; ++i) {
-               jsPlumb.detach(arrows[i]);
-       }
-       arrows = [];
-
-       for (var i = 0; i < arrow_targets.length; ++i) {
-               document.body.removeChild(arrow_targets[i]);
-       }
-       arrow_targets = [];
-       
-       occupied_by_arrows = [];        
-       for (var y = 0; y < 8; ++y) {
-               occupied_by_arrows.push([false, false, false, false, false, false, false, false]);
-       }
-}
-
-var sign = function(x) {
-       if (x > 0) {
-               return 1;
-       } else if (x < 0) {
-               return -1;
-       } else {
-               return 0;
-       }
-}
-
-// See if drawing this arrow on the board would cause unduly amount of confusion.
-var interfering_arrow = function(from, to) {
-       var from_col = from.charCodeAt(0) - "a1".charCodeAt(0);
-       var from_row = from.charCodeAt(1) - "a1".charCodeAt(1);
-       var to_col   = to.charCodeAt(0) - "a1".charCodeAt(0);
-       var to_row   = to.charCodeAt(1) - "a1".charCodeAt(1);
-
-       occupied_by_arrows[from_row][from_col] = true;
-
-       // Knight move: Just check that we haven't been at the destination before.
-       if ((Math.abs(to_col - from_col) == 2 && Math.abs(to_row - from_row) == 1) ||
-           (Math.abs(to_col - from_col) == 1 && Math.abs(to_row - from_row) == 2)) {
-               return occupied_by_arrows[to_row][to_col];
-       }
-
-       // Sliding piece: Check if anything except the from-square is seen before.
-       var dx = sign(to_col - from_col);
-       var dy = sign(to_row - from_row);
-       var x = from_col;
-       var y = from_row;
-       do {
-               x += dx;
-               y += dy;
-               if (occupied_by_arrows[y][x]) {
-                       return true;
-               }
-               occupied_by_arrows[y][x] = true;
-       } while (x != to_col || y != to_row);
-
-       return false;
-}
-
-var add_target = function() {
-       var elem = document.createElement("div");
-       $(elem).addClass("window");
-       elem.id = "target" + arrow_targets.length;
-       document.body.appendChild(elem);        
-       arrow_targets.push(elem);
-       return elem.id;
-}
-
-var create_arrow = function(from_square, to_square, fg_color, line_width, arrow_size) {
-       var from_col = from_square.charCodeAt(0) - "a1".charCodeAt(0);
-       var from_row = from_square.charCodeAt(1) - "a1".charCodeAt(1);
-       var to_col   = to_square.charCodeAt(0) - "a1".charCodeAt(0);
-       var to_row   = to_square.charCodeAt(1) - "a1".charCodeAt(1);
-
-       var from_y = (7 - from_row)*49 + 25;
-       var to_y = (7 - to_row)*49 + 25;
-       var from_x = from_col*49 + 25;
-       var to_x = to_col*49 + 25;
-
-       var dx = to_x - from_x;
-       var dy = to_y - from_y;
-       var len = Math.sqrt(dx * dx + dy * dy);
-       dx /= len;
-       dy /= len;
-
-       // Create arrow.
-       var s1 = add_target();
-       var d1 = add_target();
-       var s1v = add_target();
-       var d1v = add_target();
-       var pos = $("#board").position();
-       $("#" + s1).css({ top: pos.top + from_y + (0.5 * arrow_size) * dy, left: pos.left + from_x + (0.5 * arrow_size) * dx });
-       $("#" + d1).css({ top: pos.top + to_y - (0.5 * arrow_size) * dy, left: pos.left + to_x - (0.5 * arrow_size) * dx });
-       $("#" + s1v).css({ top: pos.top + from_y - 0 * dy, left: pos.left + from_x - 0 * dx });
-       $("#" + d1v).css({ top: pos.top + to_y + 0 * dy, left: pos.left + to_x + 0 * dx });
-       var connection1 = jsPlumb.connect({
-               source: s1,
-               target: d1,
-               connector:["Straight"],
-               cssClass:"c1",
-               endpoint:"Blank",
-               endpointClass:"c1Endpoint",                                                                                                        
-               anchor:"Continuous",
-               paintStyle:{ 
-                       lineWidth:line_width,
-                       strokeStyle:fg_color,
-                       outlineWidth:1,
-                       outlineColor:"#666",
-                       opacity:"60%"
-               }
-       });            
-       var connection2 = jsPlumb.connect({
-               source: s1v,
-               target: d1v,
-               connector:["Straight"],
-               cssClass:"vir",
-               endpoint:"Blank",
-               endpointClass:"c1Endpoint",                                                                                                        
-               anchor:"Continuous",
-               paintStyle:{ 
-                       lineWidth:0,
-                       strokeStyle:fg_color,
-                       outlineWidth:0,
-                       outlineColor:"#666",
-               },
-               overlays : [
-                       ["Arrow", {
-                               cssClass:"l1arrow",
-                               location:1.0,
-                               width: arrow_size, length: arrow_size,
-                               paintStyle:{ 
-                                       lineWidth:line_width,
-                                       strokeStyle:"#000",
-                               },
-                       }]
-               ]
-       });
-       arrows.push(connection1);
-       arrows.push(connection2);
-}
-
-// Fake multi-PV using the refutation lines. Find all “relevant” moves,
-// sorted by quality, descending.
-var find_nonstupid_moves = function(data, margin) {
-       // First of all, if there are any moves that are more than 0.5 ahead of
-       // the primary move, the refutation lines are probably bunk, so just
-       // kill them all. 
-       var best_score = undefined;
-       var pv_score = undefined;
-       for (var move in data.refutation_lines) {
-               var score = data.refutation_lines[move].score_sort_key;
-               if (move == data.pv_uci[0]) {
-                       pv_score = score;
-               }
-               if (best_score === undefined || score > best_score) {
-                       best_score = score;
-               }
-               if (!(data.refutation_lines[move].depth >= 8)) {
-                       return [];
-               }
-       }
-
-       if (best_score - pv_score > 50) {
-               return [];
-       }
-
-       // Now find all moves that are within “margin” of the best score.
-       // The PV move will always be first.
-       var moves = [];
-       for (var move in data.refutation_lines) {
-               var score = data.refutation_lines[move].score_sort_key;
-               if (move != data.pv_uci[0] && best_score - score <= margin) {
-                       moves.push(move);
-               }
-       }
-       moves = moves.sort(function(a, b) { return data.refutation_lines[b].score_sort_key - data.refutation_lines[a].score_sort_key; });
-       moves.unshift(data.pv_uci[0]);
-
-       return moves;
-}
-
-var thousands = function(x) {
-       return String(x).split('').reverse().join('').replace(/(\d{3}\B)/g, '$1,').split('').reverse().join('');
-}
-
-var print_pv = function(pretty_pv, move_num, toplay, limit) {
-       var pv = '';
-       var i = 0;
-       if (toplay == 'B') {
-               pv = move_num + '. … ' + pretty_pv[0];
-               toplay = 'W';
-               ++i;    
-       }
-       ++move_num;
-       for ( ; i < pretty_pv.length; ++i) {
-               if (toplay == 'W') {
-                       if (i > limit) {
-                               return pv + ' (…)';
-                       }
-                       if (pv != '') {
-                               pv += ' ';
-                       }
-                       pv += move_num + '. ' + pretty_pv[i];
-                       ++move_num;
-                       toplay = 'B';
-               } else {
-                       pv += ' ' + pretty_pv[i];
-                       toplay = 'W';
-               }
-       }
-       return pv;
-}
-
-var compare_by_sort_key = function(data, a, b) {
-       var ska = data.refutation_lines[a].sort_key;
-       var skb = data.refutation_lines[b].sort_key;
-       if (ska < skb) return -1;
-       if (ska > skb) return 1;
-       return 0;
-};
-
-var update_board = function(board, data) {
-       // The headline.
-       var headline = 'Analysis';
-       if (data.position.last_move !== 'none') {
-               headline += ' after ' + data.position.move_num + '. ';
-               if (data.position.toplay == 'W') {
-                       headline += '… ';
-               }
-               headline += data.position.last_move;
-               if (data.id.name) {
-                       headline += ', ';
-               }
-       }
-
-       if (data.id.name) {
-               headline += ' by ' + data.id.name;  // + ':';
-       } else {
-               //headline += ':';
-       }
-       $("#headline").text(headline);
-
-       // The score.
-       if (data.score !== null) {
-               $("#score").text(data.score);
-       }
-
-       // The search stats.
-       if (data.nodes && data.nps && data.depth) {
-               var stats = thousands(data.nodes) + ' nodes, ' + thousands(data.nps) + ' nodes/sec, depth ' + data.depth + ' ply';
-               if (data.seldepth) {
-                       stats += ' (' + data.seldepth + ' selective)';
-               }
-               if (data.tbhits && data.tbhits > 0) {
-                       if (data.tbhits == 1) {
-                               stats += ', one Nalimov hit';
-                       } else {
-                               stats += ', ' + data.tbhits + ' Nalimov hits';
-                       }
-               }
-               
-
-               $("#searchstats").text(stats);
-       }
-
-       // Update the board itself.
-       board.position(data.position.fen);
-
-       $("#board").find('.square-55d63').removeClass('nonuglyhighlight');
-       if (data.position.last_move_uci) {
-               var from = data.position.last_move_uci.substr(0, 2);
-               var to = data.position.last_move_uci.substr(2, 4);
-               $("#board").find('.square-' + from).addClass('nonuglyhighlight');
-               $("#board").find('.square-' + to).addClass('nonuglyhighlight');
-       }
-
-       // Print the PV.
-       var pv = print_pv(data.pv_pretty, data.position.move_num, data.position.toplay);
-       $("#pv").text(pv);
-
-       // Update the PV arrow.
-       clear_arrows();
-       if (data.pv_uci.length >= 1) {
-               // draw a continuation arrow as long as it's the same piece
-               for (var i = 0; i < data.pv_uci.length; i += 2) {
-                       var from = data.pv_uci[i].substr(0, 2);
-                       var to = data.pv_uci[i].substr(2,4);
-                       if ((i >= 2 && from != data.pv_uci[i - 2].substr(2, 4)) ||
-                            interfering_arrow(from, to)) {
-                               break;
-                       }
-                       create_arrow(from, to, '#f66', 6, 20);
-               }
-
-               var alt_moves = find_nonstupid_moves(data, 30);
-               for (var i = 1; i < alt_moves.length && i < 3; ++i) {
-                       create_arrow(alt_moves[i].substr(0, 2),
-                                    alt_moves[i].substr(2, 4), '#f66', 1, 10);
-               }
-       }
-
-       // See if all semi-reasonable moves have only one possible response.
-       if (data.pv_uci.length >= 2) {
-               var nonstupid_moves = find_nonstupid_moves(data, 300);
-               var response = data.pv_uci[1];
-               for (var i = 0; i < nonstupid_moves.length; ++i) {
-                       if (nonstupid_moves[i] == data.pv_uci[0]) {
-                               // ignore the PV move for refutation lines.
-                               continue;
-                       }
-                       if (!data.refutation_lines ||
-                           !data.refutation_lines[nonstupid_moves[i]] ||
-                           !data.refutation_lines[nonstupid_moves[i]].pv_uci ||
-                           data.refutation_lines[nonstupid_moves[i]].pv_uci.length < 1) {
-                               // Incomplete PV, abort.
-                               response = undefined;
-                               break;
-                       }
-                       var this_response = data.refutation_lines[nonstupid_moves[i]].pv_uci[1];
-                       if (response !== this_response) {
-                               // Different response depending on lines, abort.
-                               response = undefined;
-                               break;
-                       }
-               }
-
-               if (nonstupid_moves.length > 0 && response !== undefined) {
-                       create_arrow(response.substr(0, 2),
-                                    response.substr(2, 4), '#66f', 6, 20);
-               }
-       }
-
-       // Show the refutation lines.
-       var tbl = $("#refutationlines");
-       tbl.empty();
-
-       moves = [];
-       for (var move in data.refutation_lines) {
-               moves.push(move);
-       }
-       moves = moves.sort(function(a, b) { return compare_by_sort_key(data, a, b) });
-       for (var i = 0; i < moves.length; ++i) {
-               var line = data.refutation_lines[moves[i]];
-
-               var tr = document.createElement("tr");
-
-               var move_td = document.createElement("td");
-               tr.appendChild(move_td);
-               $(move_td).addClass("move");
-               $(move_td).text(line.pretty_move);
-
-               var score_td = document.createElement("td");
-               tr.appendChild(score_td);
-               $(score_td).addClass("score");
-               $(score_td).text(line.pretty_score);
-
-               var depth_td = document.createElement("td");
-               tr.appendChild(depth_td);
-               $(depth_td).addClass("depth");
-               $(depth_td).text("d" + line.depth);
-
-               var pv_td = document.createElement("td");
-               tr.appendChild(pv_td);
-               $(pv_td).addClass("pv");
-               $(pv_td).text(print_pv(line.pv_pretty, data.position.move_num, data.position.toplay, 10));
-
-               tbl.append(tr);
-       }
-
-       // Next update.
-       setTimeout(function() { request_update(board, 0); }, 100);
-}
-
-var init = function() {
-       // Create board.
-       var board = new ChessBoard('board', 'start');
-
-       request_update(board, 1);
-
-};
-$(document).ready(init);
-</script>
+<script type="text/javascript" src="js/chess.min.js"></script>
+<script type="text/javascript" src="js/json_delta.js"></script>
+<script type="text/javascript" src="js/jquery.sparkline.js"></script>
+<script type="text/javascript" src="js/remoteglot.js"></script>
+-->
+
+<!-- Minified version of the previous six, compiled together -->
+<script type="text/javascript" src="js/remoteglot.min.js"></script>
+<!--
+-->
 </body>
 </html>