+var onDrop = function(source, target) {
+ if (source === target) {
+ if (recommended_move === null) {
+ return 'snapback';
+ } else {
+ // Accept the move. It will be changed in onSnapEnd.
+ return;
+ }
+ } else {
+ // Suggestion not asked for.
+ recommended_move = null;
+ }
+
+ // see if the move is legal
+ var pseudogame = new Chess(display_fen);
+ var move = pseudogame.move({
+ from: source,
+ to: target,
+ promotion: 'q' // NOTE: always promote to a queen for example simplicity
+ });
+
+ // illegal move
+ if (move === null) return 'snapback';
+}
+
+var onSnapEnd = function(source, target) {
+ if (source === target && recommended_move !== null) {
+ source = recommended_move.from;
+ target = recommended_move.to;
+ }
+ recommended_move = null;
+ var pseudogame = new Chess(display_fen);
+ var move = pseudogame.move({
+ from: source,
+ to: target,
+ promotion: 'q' // NOTE: always promote to a queen for example simplicity
+ });
+
+ if (current_display_line &&
+ current_display_move < current_display_line.pretty_pv.length - 1 &&
+ current_display_line.pretty_pv[current_display_move + 1] === move.san) {
+ next_move();
+ return;
+ }
+
+ // Walk down the displayed lines until we find one that starts with
+ // this move, then select that. Note that this gives us a good priority
+ // order (history first, then PV, then multi-PV lines).
+ for (var i = 0; i < display_lines.length; ++i) {
+ var line = display_lines[i];
+ if (line.pretty_pv[line.start_display_move_num] === move.san) {
+ show_line(i, 0);
+ return;
+ }
+ }
+
+ // Shouldn't really be here if we have hash probes, but there's really
+ // nothing we can do.
+}
+// End of dragging-related code.
+
+var pad = function(val, num_digits) {
+ var s = val.toString();
+ while (s.length < num_digits) {
+ s = " " + s;
+ }
+ return s;
+}
+
+var fmt_cp = function(v) {
+ if (v === 0) {
+ return "0.00";
+ } else if (v > 0) {
+ return "+" + (v / 100).toFixed(2);
+ } else {
+ v = -v;
+ return "-" + (v / 100).toFixed(2);
+ }
+}
+
+var format_short_score = function(score) {
+ if (!score) {
+ return "???";
+ }
+ if (score[0] === 'm') {
+ if (score[2]) { // Is a bound.
+ return score[2] + "\u00a0M" + pad(score[1], 3);
+ } else {
+ return "M" + pad(score[1], 3);
+ }
+ } else if (score[0] === 'd') {
+ return "TB draw";
+ } else if (score[0] === 'cp') {
+ if (score[2]) { // Is a bound.
+ return score[2] + "\u00a0" + fmt_cp(score[1]);
+ } else {
+ return pad(fmt_cp(score[1]), 5);
+ }
+ }
+ return null;
+}
+
+var format_long_score = function(score) {
+ if (score[0] === 'm') {
+ if (score[1] > 0) {
+ return "White mates in " + score[1];
+ } else {
+ return "Black mates in " + (-score[1]);
+ }
+ } else if (score[0] === 'd') {
+ return "Theoretical draw";
+ } else if (score[0] === 'cp') {
+ return "Score: " + format_short_score(score);
+ }
+ return null;
+}
+
+var compute_plot_score = function(score) {
+ if (score[0] === 'm') {
+ if (score[1] > 0) {
+ return 500;
+ } else {
+ return -500;
+ }
+ } else if (score[0] === 'd') {
+ return 0;
+ } else if (score[0] === 'cp') {
+ if (score[1] > 500) {
+ return 500;
+ } else if (score[1] < -500) {
+ return -500;
+ } else {
+ return score[1];
+ }
+ }
+ return null;
+}
+
+/**
+ * @param score The score digest tuple.
+ * @param {boolean} invert Whether black is to play.
+ * @return {number}
+ */
+var compute_score_sort_key = function(score, invert) {
+ var s;
+ if (!score) {
+ return -10000000;
+ }
+ if (score[0] === 'm') {
+ if (score[1] > 0) {
+ // White mates.
+ s = 99999 - score[1];
+ } else {
+ // Black mates (note the double negative for score[1]).
+ s = -99999 - score[1];
+ }
+ if (invert) s = -s;
+ return s;
+ } else if (score[0] === 'd') {
+ return 0;
+ } else if (score[0] === 'cp') {
+ return invert ? -score[1] : score[1];
+ }
+ return null;
+}
+
+/**
+ * @param {string} new_backend_url
+ */
+var switch_backend = function(new_backend_url, new_backend_hash_url) {
+ // Stop looking at historic data.
+ current_display_line = null;
+ current_display_move = null;
+ displayed_analysis_data = null;
+ if (current_historic_xhr) {
+ current_historic_xhr.abort();
+ }
+
+ // If we already have a backend response going, abort it.
+ if (current_analysis_xhr) {
+ current_analysis_xhr.abort();
+ }
+ if (current_hash_xhr) {
+ current_hash_xhr.abort();
+ }
+
+ // Otherwise, we should have a timer going to start a new one.
+ // Kill that, too.
+ if (current_analysis_request_timer) {
+ clearTimeout(current_analysis_request_timer);
+ current_analysis_request_timer = null;
+ }
+ if (current_hash_display_timer) {
+ clearTimeout(current_hash_display_timer);
+ current_hash_display_timer = null;
+ }
+
+ // Request an immediate fetch with the new backend.
+ backend_url = new_backend_url;
+ backend_hash_url = new_backend_hash_url;
+ current_analysis_data = null;
+ ims = 0;
+ request_update();
+}
+window['switch_backend'] = switch_backend;
+